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