xref: /openbmc/linux/arch/x86/kernel/ebda.c (revision f2d85299b7f11f73cc0a294e396cdae114e75787)
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