Commit dedd04be authored by Alexander van Heukelum's avatar Alexander van Heukelum Committed by Ingo Molnar

x86: reserve end-of-conventional-memory to 1MB on 32-bit

This patch adds explicit detection of the EBDA and reservation
of the rom and adapter address space 0xa0000-0x100000 to the
i386 kernels. Before this patch, the EBDA size was hardcoded
as 4Kb. Also, the reservation of the adapter range was done by
modifying the e820 map which is now not necessary any longer,
and that code is removed from copy_e820_map.

The amount of conventional memory and the start of the EBDA are
detected by reading the BIOS data area directly. Paravirtual
environments do not provide this area, so we bail out early
in that case. They will just have to set up a correct memory
map to start with.
Signed-off-by: default avatarAlexander van Heukelum <heukelum@fastmail.fm>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 823c248e
...@@ -450,38 +450,25 @@ int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) ...@@ -450,38 +450,25 @@ int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
* thinkpad 560x, for example, does not cooperate with the memory * thinkpad 560x, for example, does not cooperate with the memory
* detection code.) * detection code.)
*/ */
int __init copy_e820_map(struct e820entry * biosmap, int nr_map) int __init copy_e820_map(struct e820entry *biosmap, int nr_map)
{ {
/* Only one memory region (or negative)? Ignore it */ /* Only one memory region (or negative)? Ignore it */
if (nr_map < 2) if (nr_map < 2)
return -1; return -1;
do { do {
unsigned long long start = biosmap->addr; u64 start = biosmap->addr;
unsigned long long size = biosmap->size; u64 size = biosmap->size;
unsigned long long end = start + size; u64 end = start + size;
unsigned long type = biosmap->type; u32 type = biosmap->type;
/* Overflow in 64 bits? Ignore the memory map. */ /* Overflow in 64 bits? Ignore the memory map. */
if (start > end) if (start > end)
return -1; return -1;
/*
* Some BIOSes claim RAM in the 640k - 1M region.
* Not right. Fix it up.
*/
if (type == E820_RAM) {
if (start < 0x100000ULL && end > 0xA0000ULL) {
if (start < 0xA0000ULL)
add_memory_region(start, 0xA0000ULL-start, type);
if (end <= 0x100000ULL)
continue;
start = 0x100000ULL;
size = end - start;
}
}
add_memory_region(start, size, type); add_memory_region(start, size, type);
} while (biosmap++,--nr_map); } while (biosmap++, --nr_map);
return 0; return 0;
} }
......
...@@ -385,15 +385,60 @@ unsigned long __init find_max_low_pfn(void) ...@@ -385,15 +385,60 @@ unsigned long __init find_max_low_pfn(void)
return max_low_pfn; return max_low_pfn;
} }
#define BIOS_EBDA_SEGMENT 0x40E
#define BIOS_LOWMEM_KILOBYTES 0x413
/* /*
* workaround for Dell systems that neglect to reserve EBDA * The BIOS places the EBDA/XBDA at the top of conventional
* memory, and usually decreases the reported amount of
* conventional memory (int 0x12) too. This also contains a
* workaround for Dell systems that neglect to reserve EBDA.
* The same workaround also avoids a problem with the AMD768MPX
* chipset: reserve a page before VGA to prevent PCI prefetch
* into it (errata #56). Usually the page is reserved anyways,
* unless you have no PS/2 mouse plugged in.
*/ */
static void __init reserve_ebda_region(void) static void __init reserve_ebda_region(void)
{ {
unsigned int addr; unsigned int lowmem, ebda_addr;
addr = get_bios_ebda();
if (addr) /* To determine the position of the EBDA and the */
reserve_bootmem(addr, PAGE_SIZE, BOOTMEM_DEFAULT); /* end of conventional memory, we need to look at */
/* the BIOS data area. In a paravirtual environment */
/* that area is absent. We'll just have to assume */
/* that the paravirt case can handle memory setup */
/* correctly, without our help. */
#ifdef CONFIG_PARAVIRT
if ((boot_params.hdr.version >= 0x207) &&
(boot_params.hdr.hardware_subarch != 0)) {
return;
}
#endif
/* end of low (conventional) memory */
lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES);
lowmem <<= 10;
/* start of EBDA area */
ebda_addr = *(unsigned short *)__va(BIOS_EBDA_SEGMENT);
ebda_addr <<= 4;
/* Fixup: bios puts an EBDA in the top 64K segment */
/* of conventional memory, but does not adjust lowmem. */
if ((lowmem - ebda_addr) <= 0x10000)
lowmem = ebda_addr;
/* Fixup: bios does not report an EBDA at all. */
/* Some old Dells seem to need 4k anyhow (bugzilla 2990) */
if ((ebda_addr == 0) && (lowmem >= 0x9f000))
lowmem = 0x9f000;
/* Paranoia: should never happen, but... */
if ((lowmem == 0) || (lowmem >= 0x100000))
lowmem = 0x9f000;
/* reserve all memory between lowmem and the 1MB mark */
reserve_bootmem(lowmem, 0x100000 - lowmem, BOOTMEM_DEFAULT);
} }
#ifndef CONFIG_NEED_MULTIPLE_NODES #ifndef CONFIG_NEED_MULTIPLE_NODES
...@@ -617,16 +662,9 @@ void __init setup_bootmem_allocator(void) ...@@ -617,16 +662,9 @@ void __init setup_bootmem_allocator(void)
*/ */
reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT); reserve_bootmem(0, PAGE_SIZE, BOOTMEM_DEFAULT);
/* reserve EBDA region, it's a 4K region */ /* reserve EBDA region */
reserve_ebda_region(); reserve_ebda_region();
/* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent
PCI prefetch into it (errata #56). Usually the page is reserved anyways,
unless you have no PS/2 mouse plugged in. */
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
boot_cpu_data.x86 == 6)
reserve_bootmem(0xa0000 - 4096, 4096, BOOTMEM_DEFAULT);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* /*
* But first pinch a few for the stack/trampoline stuff * But first pinch a few for the stack/trampoline stuff
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment