c3965bd151
This patch is motivated by a subsequent patch which will allow for more memory map entries on EFI supported systems than can be passed via the x86 legacy BIOS E820 interface. The legacy interface is limited to E820MAX == 128 memory entries, and that "E820MAX" manifest constant was used as the size for several arrays and loops over those arrays. The primary change in this patch is to change code loop sizes over those arrays from using the constant E820MAX, to using the ARRAY_SIZE() macro evaluated for the array being looped. That way, a subsequent patch can change the size of some of these arrays, without breaking this code. This patch also adds a parameter to the sanitize_e820_map() routine, which had an implicit size for the array passed it of E820MAX entries. This new parameter explicitly passes the size of said array. Once again, this will allow a subsequent patch to change that array size for some calls to sanitize_e820_map() without breaking the code. As part of enhancing the sanitize_e820_map() interface this way, I further combined the unnecessarily distinct x86_32 and x86_64 declarations for this routine into a single, commonly used, declaration. This patch in itself should make no difference to the resulting kernel binary. [ mingo@elte.hu: merged to -tip ] Signed-off-by: Paul Jackson <pj@sgi.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
120 lines
2.6 KiB
C
120 lines
2.6 KiB
C
/* -*- linux-c -*- ------------------------------------------------------- *
|
|
*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
* Copyright 2007 rPath, Inc. - All Rights Reserved
|
|
*
|
|
* This file is part of the Linux kernel, and is made available under
|
|
* the terms of the GNU General Public License version 2.
|
|
*
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* Memory detection code
|
|
*/
|
|
|
|
#include "boot.h"
|
|
#include <linux/kernel.h>
|
|
|
|
#define SMAP 0x534d4150 /* ASCII "SMAP" */
|
|
|
|
static int detect_memory_e820(void)
|
|
{
|
|
int count = 0;
|
|
u32 next = 0;
|
|
u32 size, id;
|
|
u8 err;
|
|
struct e820entry *desc = boot_params.e820_map;
|
|
|
|
do {
|
|
size = sizeof(struct e820entry);
|
|
|
|
/* 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"
|
|
: "=d" (err), "+b" (next), "=a" (id), "+c" (size),
|
|
"=m" (*desc)
|
|
: "D" (desc), "d" (SMAP), "a" (0xe820));
|
|
|
|
/* BIOSes which terminate the chain with CF = 1 as opposed
|
|
to %ebx = 0 don't always report the SMAP signature on
|
|
the final, failing, probe. */
|
|
if (err)
|
|
break;
|
|
|
|
/* 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;
|
|
}
|
|
|
|
count++;
|
|
desc++;
|
|
} while (next && count < ARRAY_SIZE(boot_params.e820_map));
|
|
|
|
return boot_params.e820_entries = count;
|
|
}
|
|
|
|
static int detect_memory_e801(void)
|
|
{
|
|
u16 ax, bx, cx, dx;
|
|
u8 err;
|
|
|
|
bx = cx = dx = 0;
|
|
ax = 0xe801;
|
|
asm("stc; int $0x15; setc %0"
|
|
: "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));
|
|
|
|
if (err)
|
|
return -1;
|
|
|
|
/* Do we really need to do this? */
|
|
if (cx || dx) {
|
|
ax = cx;
|
|
bx = dx;
|
|
}
|
|
|
|
if (ax > 15*1024)
|
|
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;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int detect_memory_88(void)
|
|
{
|
|
u16 ax;
|
|
u8 err;
|
|
|
|
ax = 0x8800;
|
|
asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax));
|
|
|
|
boot_params.screen_info.ext_mem_k = ax;
|
|
|
|
return -err;
|
|
}
|
|
|
|
int detect_memory(void)
|
|
{
|
|
int err = -1;
|
|
|
|
if (detect_memory_e820() > 0)
|
|
err = 0;
|
|
|
|
if (!detect_memory_e801())
|
|
err = 0;
|
|
|
|
if (!detect_memory_88())
|
|
err = 0;
|
|
|
|
return err;
|
|
}
|