Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hpa/linux...
[sfrench/cifs-2.6.git] / arch / i386 / boot / memory.c
index 1a2e62db8bed48df0e613066c9efb69f2509d0e0..378353956b5dfc86469b66419b9680e1770a7410 100644 (file)
@@ -20,6 +20,7 @@
 
 static int detect_memory_e820(void)
 {
+       int count = 0;
        u32 next = 0;
        u32 size, id;
        u8 err;
@@ -27,20 +28,33 @@ static int detect_memory_e820(void)
 
        do {
                size = sizeof(struct e820entry);
-               id = SMAP;
+
+               /* Important: %edx is clobbered by some BIOSes,
+                  so it must be either used for the error output
+                  or explicitly marked clobbered. */
                asm("int $0x15; setc %0"
-                   : "=am" (err), "+b" (next), "+d" (id), "+c" (size),
+                   : "=d" (err), "+b" (next), "=a" (id), "+c" (size),
                      "=m" (*desc)
-                   : "D" (desc), "a" (0xe820));
+                   : "D" (desc), "d" (SMAP), "a" (0xe820));
+
+               /* Some BIOSes stop returning SMAP in the middle of
+                  the search loop.  We don't know exactly how the BIOS
+                  screwed up the map at that point, we might have a
+                  partial map, the full map, or complete garbage, so
+                  just return failure. */
+               if (id != SMAP) {
+                       count = 0;
+                       break;
+               }
 
-               if (err || id != SMAP)
+               if (err)
                        break;
 
-               boot_params.e820_entries++;
+               count++;
                desc++;
-       } while (next && boot_params.e820_entries < E820MAX);
+       } while (next && count < E820MAX);
 
-       return boot_params.e820_entries;
+       return boot_params.e820_entries = count;
 }
 
 static int detect_memory_e801(void)
@@ -89,11 +103,16 @@ static int detect_memory_88(void)
 
 int detect_memory(void)
 {
+       int err = -1;
+
        if (detect_memory_e820() > 0)
-               return 0;
+               err = 0;
 
        if (!detect_memory_e801())
-               return 0;
+               err = 0;
+
+       if (!detect_memory_88())
+               err = 0;
 
-       return detect_memory_88();
+       return err;
 }