1*f2d85299SLuis R. Rodriguez #include <linux/kernel.h> 2*f2d85299SLuis R. Rodriguez #include <linux/init.h> 3*f2d85299SLuis R. Rodriguez #include <linux/memblock.h> 4*f2d85299SLuis R. Rodriguez 5*f2d85299SLuis R. Rodriguez #include <asm/setup.h> 6*f2d85299SLuis R. Rodriguez #include <asm/bios_ebda.h> 7*f2d85299SLuis R. Rodriguez 8*f2d85299SLuis R. Rodriguez /* 9*f2d85299SLuis R. Rodriguez * The BIOS places the EBDA/XBDA at the top of conventional 10*f2d85299SLuis R. Rodriguez * memory, and usually decreases the reported amount of 11*f2d85299SLuis R. Rodriguez * conventional memory (int 0x12) too. This also contains a 12*f2d85299SLuis R. Rodriguez * workaround for Dell systems that neglect to reserve EBDA. 13*f2d85299SLuis R. Rodriguez * The same workaround also avoids a problem with the AMD768MPX 14*f2d85299SLuis R. Rodriguez * chipset: reserve a page before VGA to prevent PCI prefetch 15*f2d85299SLuis R. Rodriguez * into it (errata #56). Usually the page is reserved anyways, 16*f2d85299SLuis R. Rodriguez * unless you have no PS/2 mouse plugged in. 17*f2d85299SLuis R. Rodriguez * 18*f2d85299SLuis R. Rodriguez * This functions is deliberately very conservative. Losing 19*f2d85299SLuis R. Rodriguez * memory in the bottom megabyte is rarely a problem, as long 20*f2d85299SLuis R. Rodriguez * as we have enough memory to install the trampoline. Using 21*f2d85299SLuis R. Rodriguez * memory that is in use by the BIOS or by some DMA device 22*f2d85299SLuis R. Rodriguez * the BIOS didn't shut down *is* a big problem. 23*f2d85299SLuis R. Rodriguez */ 24*f2d85299SLuis R. Rodriguez 25*f2d85299SLuis R. Rodriguez #define BIOS_LOWMEM_KILOBYTES 0x413 26*f2d85299SLuis R. Rodriguez #define LOWMEM_CAP 0x9f000U /* Absolute maximum */ 27*f2d85299SLuis R. Rodriguez #define INSANE_CUTOFF 0x20000U /* Less than this = insane */ 28*f2d85299SLuis R. Rodriguez 29*f2d85299SLuis R. Rodriguez void __init reserve_ebda_region(void) 30*f2d85299SLuis R. Rodriguez { 31*f2d85299SLuis R. Rodriguez unsigned int lowmem, ebda_addr; 32*f2d85299SLuis R. Rodriguez 33*f2d85299SLuis R. Rodriguez /* 34*f2d85299SLuis R. Rodriguez * To determine the position of the EBDA and the 35*f2d85299SLuis R. Rodriguez * end of conventional memory, we need to look at 36*f2d85299SLuis R. Rodriguez * the BIOS data area. In a paravirtual environment 37*f2d85299SLuis R. Rodriguez * that area is absent. We'll just have to assume 38*f2d85299SLuis R. Rodriguez * that the paravirt case can handle memory setup 39*f2d85299SLuis R. Rodriguez * correctly, without our help. 40*f2d85299SLuis R. Rodriguez */ 41*f2d85299SLuis R. Rodriguez if (!x86_platform.legacy.ebda_search) 42*f2d85299SLuis R. Rodriguez return; 43*f2d85299SLuis R. Rodriguez 44*f2d85299SLuis R. Rodriguez /* end of low (conventional) memory */ 45*f2d85299SLuis R. Rodriguez lowmem = *(unsigned short *)__va(BIOS_LOWMEM_KILOBYTES); 46*f2d85299SLuis R. Rodriguez lowmem <<= 10; 47*f2d85299SLuis R. Rodriguez 48*f2d85299SLuis R. Rodriguez /* start of EBDA area */ 49*f2d85299SLuis R. Rodriguez ebda_addr = get_bios_ebda(); 50*f2d85299SLuis R. Rodriguez 51*f2d85299SLuis R. Rodriguez /* 52*f2d85299SLuis R. Rodriguez * Note: some old Dells seem to need 4k EBDA without 53*f2d85299SLuis R. Rodriguez * reporting so, so just consider the memory above 0x9f000 54*f2d85299SLuis R. Rodriguez * to be off limits (bugzilla 2990). 55*f2d85299SLuis R. Rodriguez */ 56*f2d85299SLuis R. Rodriguez 57*f2d85299SLuis R. Rodriguez /* If the EBDA address is below 128K, assume it is bogus */ 58*f2d85299SLuis R. Rodriguez if (ebda_addr < INSANE_CUTOFF) 59*f2d85299SLuis R. Rodriguez ebda_addr = LOWMEM_CAP; 60*f2d85299SLuis R. Rodriguez 61*f2d85299SLuis R. Rodriguez /* If lowmem is less than 128K, assume it is bogus */ 62*f2d85299SLuis R. Rodriguez if (lowmem < INSANE_CUTOFF) 63*f2d85299SLuis R. Rodriguez lowmem = LOWMEM_CAP; 64*f2d85299SLuis R. Rodriguez 65*f2d85299SLuis R. Rodriguez /* Use the lower of the lowmem and EBDA markers as the cutoff */ 66*f2d85299SLuis R. Rodriguez lowmem = min(lowmem, ebda_addr); 67*f2d85299SLuis R. Rodriguez lowmem = min(lowmem, LOWMEM_CAP); /* Absolute cap */ 68*f2d85299SLuis R. Rodriguez 69*f2d85299SLuis R. Rodriguez /* reserve all memory between lowmem and the 1MB mark */ 70*f2d85299SLuis R. Rodriguez memblock_reserve(lowmem, 0x100000 - lowmem); 71*f2d85299SLuis R. Rodriguez } 72