Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86: Make sure we can boot in the case the BDA contains pure garbage

On non-BIOS platforms it is possible that the BIOS data area contains
garbage instead of being zeroed or something equivalent (firmware
people: we are talking of 1.5K here, so please do the sane thing.)

We need on the order of 20-30K of low memory in order to boot, which
may grow up to < 64K in the future. We probably want to avoid the
lowest of the low memory. At the same time, it seems extremely
unlikely that a legitimate EBDA would ever reach down to the 128K
(which would require it to be over half a megabyte in size.) Thus,
pick 128K as the cutoff for "this is insane, ignore." We may still
end up reserving a bunch of extra memory on the low megabyte, but that
is not really a major issue these days. In the worst case we lose
512K of RAM.

This code really should be merged with trim_bios_range() in
arch/x86/kernel/setup.c, but that is a bigger patch for a later merge
window.

Reported-by: Darren Hart <dvhart@linux.intel.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: Matt Fleming <matt.fleming@intel.com>
Cc: <stable@vger.kernel.org>
Link: http://lkml.kernel.org/n/tip-oebml055yyfm8yxmria09rja@git.kernel.org

+34 -19
+34 -19
arch/x86/kernel/head.c
··· 5 5 #include <asm/setup.h> 6 6 #include <asm/bios_ebda.h> 7 7 8 - #define BIOS_LOWMEM_KILOBYTES 0x413 9 - 10 8 /* 11 9 * The BIOS places the EBDA/XBDA at the top of conventional 12 10 * memory, and usually decreases the reported amount of ··· 14 16 * chipset: reserve a page before VGA to prevent PCI prefetch 15 17 * into it (errata #56). Usually the page is reserved anyways, 16 18 * unless you have no PS/2 mouse plugged in. 19 + * 20 + * This functions is deliberately very conservative. Losing 21 + * memory in the bottom megabyte is rarely a problem, as long 22 + * as we have enough memory to install the trampoline. Using 23 + * memory that is in use by the BIOS or by some DMA device 24 + * the BIOS didn't shut down *is* a big problem. 17 25 */ 26 + 27 + #define BIOS_LOWMEM_KILOBYTES 0x413 28 + #define LOWMEM_CAP 0x9f000U /* Absolute maximum */ 29 + #define INSANE_CUTOFF 0x20000U /* Less than this = insane */ 30 + 18 31 void __init reserve_ebda_region(void) 19 32 { 20 33 unsigned int lowmem, ebda_addr; 21 34 22 - /* To determine the position of the EBDA and the */ 23 - /* end of conventional memory, we need to look at */ 24 - /* the BIOS data area. In a paravirtual environment */ 25 - /* that area is absent. We'll just have to assume */ 26 - /* that the paravirt case can handle memory setup */ 27 - /* correctly, without our help. */ 35 + /* 36 + * To determine the position of the EBDA and the 37 + * end of conventional memory, we need to look at 38 + * the BIOS data area. In a paravirtual environment 39 + * that area is absent. We'll just have to assume 40 + * that the paravirt case can handle memory setup 41 + * correctly, without our help. 42 + */ 28 43 if (paravirt_enabled()) 29 44 return; 30 45 ··· 48 37 /* start of EBDA area */ 49 38 ebda_addr = get_bios_ebda(); 50 39 51 - /* Fixup: bios puts an EBDA in the top 64K segment */ 52 - /* of conventional memory, but does not adjust lowmem. */ 53 - if ((lowmem - ebda_addr) <= 0x10000) 54 - lowmem = ebda_addr; 40 + /* 41 + * Note: some old Dells seem to need 4k EBDA without 42 + * reporting so, so just consider the memory above 0x9f000 43 + * to be off limits (bugzilla 2990). 44 + */ 55 45 56 - /* Fixup: bios does not report an EBDA at all. */ 57 - /* Some old Dells seem to need 4k anyhow (bugzilla 2990) */ 58 - if ((ebda_addr == 0) && (lowmem >= 0x9f000)) 59 - lowmem = 0x9f000; 46 + /* If the EBDA address is below 128K, assume it is bogus */ 47 + if (ebda_addr < INSANE_CUTOFF) 48 + ebda_addr = LOWMEM_CAP; 60 49 61 - /* Paranoia: should never happen, but... */ 62 - if ((lowmem == 0) || (lowmem >= 0x100000)) 63 - lowmem = 0x9f000; 50 + /* If lowmem is less than 128K, assume it is bogus */ 51 + if (lowmem < INSANE_CUTOFF) 52 + lowmem = LOWMEM_CAP; 53 + 54 + /* Use the lower of the lowmem and EBDA markers as the cutoff */ 55 + lowmem = min(lowmem, ebda_addr); 56 + lowmem = min(lowmem, LOWMEM_CAP); /* Absolute cap */ 64 57 65 58 /* reserve all memory between lowmem and the 1MB mark */ 66 59 memblock_reserve(lowmem, 0x100000 - lowmem);