|
@@ -25,12 +25,16 @@ struct e820_ext_entry {
|
|
static int detect_memory_e820(void)
|
|
static int detect_memory_e820(void)
|
|
{
|
|
{
|
|
int count = 0;
|
|
int count = 0;
|
|
- u32 next = 0;
|
|
|
|
- u32 size, id, edi;
|
|
|
|
- u8 err;
|
|
|
|
|
|
+ struct biosregs ireg, oreg;
|
|
struct e820entry *desc = boot_params.e820_map;
|
|
struct e820entry *desc = boot_params.e820_map;
|
|
static struct e820_ext_entry buf; /* static so it is zeroed */
|
|
static struct e820_ext_entry buf; /* static so it is zeroed */
|
|
|
|
|
|
|
|
+ initregs(&ireg);
|
|
|
|
+ ireg.ax = 0xe820;
|
|
|
|
+ ireg.cx = sizeof buf;
|
|
|
|
+ ireg.edx = SMAP;
|
|
|
|
+ ireg.di = (size_t)&buf;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Set this here so that if the BIOS doesn't change this field
|
|
* Set this here so that if the BIOS doesn't change this field
|
|
* but still doesn't change %ecx, we're still okay...
|
|
* but still doesn't change %ecx, we're still okay...
|
|
@@ -38,22 +42,13 @@ static int detect_memory_e820(void)
|
|
buf.ext_flags = 1;
|
|
buf.ext_flags = 1;
|
|
|
|
|
|
do {
|
|
do {
|
|
- size = sizeof buf;
|
|
|
|
-
|
|
|
|
- /* Important: %edx and %esi are clobbered by some BIOSes,
|
|
|
|
- so they must be either used for the error output
|
|
|
|
- or explicitly marked clobbered. Given that, assume there
|
|
|
|
- is something out there clobbering %ebp and %edi, too. */
|
|
|
|
- asm("pushl %%ebp; int $0x15; popl %%ebp; setc %0"
|
|
|
|
- : "=d" (err), "+b" (next), "=a" (id), "+c" (size),
|
|
|
|
- "=D" (edi), "+m" (buf)
|
|
|
|
- : "D" (&buf), "d" (SMAP), "a" (0xe820)
|
|
|
|
- : "esi");
|
|
|
|
|
|
+ intcall(0x15, &ireg, &oreg);
|
|
|
|
+ ireg.ebx = oreg.ebx; /* for next iteration... */
|
|
|
|
|
|
/* BIOSes which terminate the chain with CF = 1 as opposed
|
|
/* BIOSes which terminate the chain with CF = 1 as opposed
|
|
to %ebx = 0 don't always report the SMAP signature on
|
|
to %ebx = 0 don't always report the SMAP signature on
|
|
the final, failing, probe. */
|
|
the final, failing, probe. */
|
|
- if (err)
|
|
|
|
|
|
+ if (oreg.eflags & X86_EFLAGS_CF)
|
|
break;
|
|
break;
|
|
|
|
|
|
/* Some BIOSes stop returning SMAP in the middle of
|
|
/* Some BIOSes stop returning SMAP in the middle of
|
|
@@ -61,7 +56,7 @@ static int detect_memory_e820(void)
|
|
screwed up the map at that point, we might have a
|
|
screwed up the map at that point, we might have a
|
|
partial map, the full map, or complete garbage, so
|
|
partial map, the full map, or complete garbage, so
|
|
just return failure. */
|
|
just return failure. */
|
|
- if (id != SMAP) {
|
|
|
|
|
|
+ if (oreg.eax != SMAP) {
|
|
count = 0;
|
|
count = 0;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -69,58 +64,62 @@ static int detect_memory_e820(void)
|
|
/* ACPI 3.0 added the extended flags support. If bit 0
|
|
/* ACPI 3.0 added the extended flags support. If bit 0
|
|
in the extended flags is zero, we're supposed to simply
|
|
in the extended flags is zero, we're supposed to simply
|
|
ignore the entry -- a backwards incompatible change! */
|
|
ignore the entry -- a backwards incompatible change! */
|
|
- if (size > 20 && !(buf.ext_flags & 1))
|
|
|
|
|
|
+ if (oreg.cx > 20 && !(buf.ext_flags & 1))
|
|
continue;
|
|
continue;
|
|
|
|
|
|
*desc++ = buf.std;
|
|
*desc++ = buf.std;
|
|
count++;
|
|
count++;
|
|
- } while (next && count < ARRAY_SIZE(boot_params.e820_map));
|
|
|
|
|
|
+ } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map));
|
|
|
|
|
|
return boot_params.e820_entries = count;
|
|
return boot_params.e820_entries = count;
|
|
}
|
|
}
|
|
|
|
|
|
static int detect_memory_e801(void)
|
|
static int detect_memory_e801(void)
|
|
{
|
|
{
|
|
- u16 ax, bx, cx, dx;
|
|
|
|
- u8 err;
|
|
|
|
|
|
+ struct biosregs ireg, oreg;
|
|
|
|
|
|
- bx = cx = dx = 0;
|
|
|
|
- ax = 0xe801;
|
|
|
|
- asm("stc; int $0x15; setc %0"
|
|
|
|
- : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));
|
|
|
|
|
|
+ initregs(&ireg);
|
|
|
|
+ ireg.ax = 0xe801;
|
|
|
|
+ intcall(0x15, &ireg, &oreg);
|
|
|
|
|
|
- if (err)
|
|
|
|
|
|
+ if (oreg.eflags & X86_EFLAGS_CF)
|
|
return -1;
|
|
return -1;
|
|
|
|
|
|
/* Do we really need to do this? */
|
|
/* Do we really need to do this? */
|
|
- if (cx || dx) {
|
|
|
|
- ax = cx;
|
|
|
|
- bx = dx;
|
|
|
|
|
|
+ if (oreg.cx || oreg.dx) {
|
|
|
|
+ oreg.ax = oreg.cx;
|
|
|
|
+ oreg.bx = oreg.dx;
|
|
}
|
|
}
|
|
|
|
|
|
- if (ax > 15*1024)
|
|
|
|
|
|
+ if (oreg.ax > 15*1024) {
|
|
return -1; /* Bogus! */
|
|
return -1; /* Bogus! */
|
|
-
|
|
|
|
- /* This ignores memory above 16MB if we have a memory hole
|
|
|
|
- there. If someone actually finds a machine with a memory
|
|
|
|
- hole at 16MB and no support for 0E820h they should probably
|
|
|
|
- generate a fake e820 map. */
|
|
|
|
- boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax;
|
|
|
|
|
|
+ } else if (oreg.ax == 15*1024) {
|
|
|
|
+ boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax;
|
|
|
|
+ } else {
|
|
|
|
+ /*
|
|
|
|
+ * This ignores memory above 16MB if we have a memory
|
|
|
|
+ * hole there. If someone actually finds a machine
|
|
|
|
+ * with a memory hole at 16MB and no support for
|
|
|
|
+ * 0E820h they should probably generate a fake e820
|
|
|
|
+ * map.
|
|
|
|
+ */
|
|
|
|
+ boot_params.alt_mem_k = oreg.ax;
|
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int detect_memory_88(void)
|
|
static int detect_memory_88(void)
|
|
{
|
|
{
|
|
- u16 ax;
|
|
|
|
- u8 err;
|
|
|
|
|
|
+ struct biosregs ireg, oreg;
|
|
|
|
|
|
- ax = 0x8800;
|
|
|
|
- asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax));
|
|
|
|
|
|
+ initregs(&ireg);
|
|
|
|
+ ireg.ah = 0x88;
|
|
|
|
+ intcall(0x15, &ireg, &oreg);
|
|
|
|
|
|
- boot_params.screen_info.ext_mem_k = ax;
|
|
|
|
|
|
+ boot_params.screen_info.ext_mem_k = oreg.ax;
|
|
|
|
|
|
- return -err;
|
|
|
|
|
|
+ return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */
|
|
}
|
|
}
|
|
|
|
|
|
int detect_memory(void)
|
|
int detect_memory(void)
|