aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/boot/memory.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2009-04-01 21:13:46 -0400
committerH. Peter Anvin <hpa@zytor.com>2009-04-09 19:08:11 -0400
commitdf7699c56421c0476704f24a43409ac8c505f3d2 (patch)
treec8d5935a5bd7dd59b0ce70db1a53999090be938b /arch/x86/boot/memory.c
parent7a734e7dd93b9aea08ed51036a9a0e2c9dfd8dac (diff)
x86, setup: "glove box" BIOS interrupts in the core boot code
Impact: BIOS proofing "Glove box" off BIOS interrupts in the core boot code. LKML-Reference: <49DE7F79.4030106@zytor.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/boot/memory.c')
-rw-r--r--arch/x86/boot/memory.c81
1 files changed, 40 insertions, 41 deletions
diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c
index 5054c2ddd1a..d989de810ca 100644
--- a/arch/x86/boot/memory.c
+++ b/arch/x86/boot/memory.c
@@ -25,12 +25,16 @@ struct e820_ext_entry {
25static int detect_memory_e820(void) 25static int detect_memory_e820(void)
26{ 26{
27 int count = 0; 27 int count = 0;
28 u32 next = 0; 28 struct biosregs ireg, oreg;
29 u32 size, id, edi;
30 u8 err;
31 struct e820entry *desc = boot_params.e820_map; 29 struct e820entry *desc = boot_params.e820_map;
32 static struct e820_ext_entry buf; /* static so it is zeroed */ 30 static struct e820_ext_entry buf; /* static so it is zeroed */
33 31
32 initregs(&ireg);
33 ireg.ax = 0xe820;
34 ireg.cx = sizeof buf;
35 ireg.edx = SMAP;
36 ireg.di = (size_t)&buf;
37
34 /* 38 /*
35 * Set this here so that if the BIOS doesn't change this field 39 * Set this here so that if the BIOS doesn't change this field
36 * but still doesn't change %ecx, we're still okay... 40 * but still doesn't change %ecx, we're still okay...
@@ -38,22 +42,13 @@ static int detect_memory_e820(void)
38 buf.ext_flags = 1; 42 buf.ext_flags = 1;
39 43
40 do { 44 do {
41 size = sizeof buf; 45 intcall(0x15, &ireg, &oreg);
42 46 ireg.ebx = oreg.ebx; /* for next iteration... */
43 /* Important: %edx and %esi are clobbered by some BIOSes,
44 so they must be either used for the error output
45 or explicitly marked clobbered. Given that, assume there
46 is something out there clobbering %ebp and %edi, too. */
47 asm("pushl %%ebp; int $0x15; popl %%ebp; setc %0"
48 : "=d" (err), "+b" (next), "=a" (id), "+c" (size),
49 "=D" (edi), "+m" (buf)
50 : "D" (&buf), "d" (SMAP), "a" (0xe820)
51 : "esi");
52 47
53 /* BIOSes which terminate the chain with CF = 1 as opposed 48 /* BIOSes which terminate the chain with CF = 1 as opposed
54 to %ebx = 0 don't always report the SMAP signature on 49 to %ebx = 0 don't always report the SMAP signature on
55 the final, failing, probe. */ 50 the final, failing, probe. */
56 if (err) 51 if (oreg.eflags & X86_EFLAGS_CF)
57 break; 52 break;
58 53
59 /* Some BIOSes stop returning SMAP in the middle of 54 /* Some BIOSes stop returning SMAP in the middle of
@@ -61,7 +56,7 @@ static int detect_memory_e820(void)
61 screwed up the map at that point, we might have a 56 screwed up the map at that point, we might have a
62 partial map, the full map, or complete garbage, so 57 partial map, the full map, or complete garbage, so
63 just return failure. */ 58 just return failure. */
64 if (id != SMAP) { 59 if (oreg.eax != SMAP) {
65 count = 0; 60 count = 0;
66 break; 61 break;
67 } 62 }
@@ -69,58 +64,62 @@ static int detect_memory_e820(void)
69 /* ACPI 3.0 added the extended flags support. If bit 0 64 /* ACPI 3.0 added the extended flags support. If bit 0
70 in the extended flags is zero, we're supposed to simply 65 in the extended flags is zero, we're supposed to simply
71 ignore the entry -- a backwards incompatible change! */ 66 ignore the entry -- a backwards incompatible change! */
72 if (size > 20 && !(buf.ext_flags & 1)) 67 if (oreg.cx > 20 && !(buf.ext_flags & 1))
73 continue; 68 continue;
74 69
75 *desc++ = buf.std; 70 *desc++ = buf.std;
76 count++; 71 count++;
77 } while (next && count < ARRAY_SIZE(boot_params.e820_map)); 72 } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map));
78 73
79 return boot_params.e820_entries = count; 74 return boot_params.e820_entries = count;
80} 75}
81 76
82static int detect_memory_e801(void) 77static int detect_memory_e801(void)
83{ 78{
84 u16 ax, bx, cx, dx; 79 struct biosregs ireg, oreg;
85 u8 err;
86 80
87 bx = cx = dx = 0; 81 initregs(&ireg);
88 ax = 0xe801; 82 ireg.ax = 0xe801;
89 asm("stc; int $0x15; setc %0" 83 intcall(0x15, &ireg, &oreg);
90 : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));
91 84
92 if (err) 85 if (oreg.eflags & X86_EFLAGS_CF)
93 return -1; 86 return -1;
94 87
95 /* Do we really need to do this? */ 88 /* Do we really need to do this? */
96 if (cx || dx) { 89 if (oreg.cx || oreg.dx) {
97 ax = cx; 90 oreg.ax = oreg.cx;
98 bx = dx; 91 oreg.bx = oreg.dx;
99 } 92 }
100 93
101 if (ax > 15*1024) 94 if (oreg.ax > 15*1024) {
102 return -1; /* Bogus! */ 95 return -1; /* Bogus! */
103 96 } else if (oreg.ax == 15*1024) {
104 /* This ignores memory above 16MB if we have a memory hole 97 boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax;
105 there. If someone actually finds a machine with a memory 98 } else {
106 hole at 16MB and no support for 0E820h they should probably 99 /*
107 generate a fake e820 map. */ 100 * This ignores memory above 16MB if we have a memory
108 boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax; 101 * hole there. If someone actually finds a machine
102 * with a memory hole at 16MB and no support for
103 * 0E820h they should probably generate a fake e820
104 * map.
105 */
106 boot_params.alt_mem_k = oreg.ax;
107 }
109 108
110 return 0; 109 return 0;
111} 110}
112 111
113static int detect_memory_88(void) 112static int detect_memory_88(void)
114{ 113{
115 u16 ax; 114 struct biosregs ireg, oreg;
116 u8 err;
117 115
118 ax = 0x8800; 116 initregs(&ireg);
119 asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax)); 117 ireg.ah = 0x88;
118 intcall(0x15, &ireg, &oreg);
120 119
121 boot_params.screen_info.ext_mem_k = ax; 120 boot_params.screen_info.ext_mem_k = oreg.ax;
122 121
123 return -err; 122 return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */
124} 123}
125 124
126int detect_memory(void) 125int detect_memory(void)