aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/boot/memory.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-06-10 19:14:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-10 19:14:41 -0400
commitbec706838ec2f9c8c2b99e88a1270d7cba159b06 (patch)
tree96ec3ccbab3596dee79ef874483238853351a4f8 /arch/x86/boot/memory.c
parentbb7762961d3ce745688e9050e914c1d3f980268d (diff)
parentee0736627d3347be0be2769fa7b26431f9726c9d (diff)
Merge branch 'x86-setup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-setup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: x86, setup: fix comment in the "glove box" code x86, setup: "glove box" BIOS interrupts in the video code x86, setup: "glove box" BIOS interrupts in the MCA code x86, setup: "glove box" BIOS interrupts in the EDD code x86, setup: "glove box" BIOS interrupts in the APM code x86, setup: "glove box" BIOS interrupts in the core boot code x86, setup: "glove box" BIOS calls -- infrastructure
Diffstat (limited to 'arch/x86/boot/memory.c')
-rw-r--r--arch/x86/boot/memory.c79
1 files changed, 39 insertions, 40 deletions
diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c
index 74b3d2ba84e9..cae3feb1035e 100644
--- a/arch/x86/boot/memory.c
+++ b/arch/x86/boot/memory.c
@@ -20,12 +20,16 @@
20static int detect_memory_e820(void) 20static int detect_memory_e820(void)
21{ 21{
22 int count = 0; 22 int count = 0;
23 u32 next = 0; 23 struct biosregs ireg, oreg;
24 u32 size, id, edi;
25 u8 err;
26 struct e820entry *desc = boot_params.e820_map; 24 struct e820entry *desc = boot_params.e820_map;
27 static struct e820entry buf; /* static so it is zeroed */ 25 static struct e820entry buf; /* static so it is zeroed */
28 26
27 initregs(&ireg);
28 ireg.ax = 0xe820;
29 ireg.cx = sizeof buf;
30 ireg.edx = SMAP;
31 ireg.di = (size_t)&buf;
32
29 /* 33 /*
30 * Note: at least one BIOS is known which assumes that the 34 * Note: at least one BIOS is known which assumes that the
31 * buffer pointed to by one e820 call is the same one as 35 * buffer pointed to by one e820 call is the same one as
@@ -41,22 +45,13 @@ static int detect_memory_e820(void)
41 */ 45 */
42 46
43 do { 47 do {
44 size = sizeof buf; 48 intcall(0x15, &ireg, &oreg);
45 49 ireg.ebx = oreg.ebx; /* for next iteration... */
46 /* Important: %edx and %esi are clobbered by some BIOSes,
47 so they must be either used for the error output
48 or explicitly marked clobbered. Given that, assume there
49 is something out there clobbering %ebp and %edi, too. */
50 asm("pushl %%ebp; int $0x15; popl %%ebp; setc %0"
51 : "=d" (err), "+b" (next), "=a" (id), "+c" (size),
52 "=D" (edi), "+m" (buf)
53 : "D" (&buf), "d" (SMAP), "a" (0xe820)
54 : "esi");
55 50
56 /* BIOSes which terminate the chain with CF = 1 as opposed 51 /* BIOSes which terminate the chain with CF = 1 as opposed
57 to %ebx = 0 don't always report the SMAP signature on 52 to %ebx = 0 don't always report the SMAP signature on
58 the final, failing, probe. */ 53 the final, failing, probe. */
59 if (err) 54 if (oreg.eflags & X86_EFLAGS_CF)
60 break; 55 break;
61 56
62 /* Some BIOSes stop returning SMAP in the middle of 57 /* Some BIOSes stop returning SMAP in the middle of
@@ -64,60 +59,64 @@ static int detect_memory_e820(void)
64 screwed up the map at that point, we might have a 59 screwed up the map at that point, we might have a
65 partial map, the full map, or complete garbage, so 60 partial map, the full map, or complete garbage, so
66 just return failure. */ 61 just return failure. */
67 if (id != SMAP) { 62 if (oreg.eax != SMAP) {
68 count = 0; 63 count = 0;
69 break; 64 break;
70 } 65 }
71 66
72 *desc++ = buf; 67 *desc++ = buf;
73 count++; 68 count++;
74 } while (next && count < ARRAY_SIZE(boot_params.e820_map)); 69 } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_map));
75 70
76 return boot_params.e820_entries = count; 71 return boot_params.e820_entries = count;
77} 72}
78 73
79static int detect_memory_e801(void) 74static int detect_memory_e801(void)
80{ 75{
81 u16 ax, bx, cx, dx; 76 struct biosregs ireg, oreg;
82 u8 err;
83 77
84 bx = cx = dx = 0; 78 initregs(&ireg);
85 ax = 0xe801; 79 ireg.ax = 0xe801;
86 asm("stc; int $0x15; setc %0" 80 intcall(0x15, &ireg, &oreg);
87 : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));
88 81
89 if (err) 82 if (oreg.eflags & X86_EFLAGS_CF)
90 return -1; 83 return -1;
91 84
92 /* Do we really need to do this? */ 85 /* Do we really need to do this? */
93 if (cx || dx) { 86 if (oreg.cx || oreg.dx) {
94 ax = cx; 87 oreg.ax = oreg.cx;
95 bx = dx; 88 oreg.bx = oreg.dx;
96 } 89 }
97 90
98 if (ax > 15*1024) 91 if (oreg.ax > 15*1024) {
99 return -1; /* Bogus! */ 92 return -1; /* Bogus! */
100 93 } else if (oreg.ax == 15*1024) {
101 /* This ignores memory above 16MB if we have a memory hole 94 boot_params.alt_mem_k = (oreg.dx << 6) + oreg.ax;
102 there. If someone actually finds a machine with a memory 95 } else {
103 hole at 16MB and no support for 0E820h they should probably 96 /*
104 generate a fake e820 map. */ 97 * This ignores memory above 16MB if we have a memory
105 boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax; 98 * hole there. If someone actually finds a machine
99 * with a memory hole at 16MB and no support for
100 * 0E820h they should probably generate a fake e820
101 * map.
102 */
103 boot_params.alt_mem_k = oreg.ax;
104 }
106 105
107 return 0; 106 return 0;
108} 107}
109 108
110static int detect_memory_88(void) 109static int detect_memory_88(void)
111{ 110{
112 u16 ax; 111 struct biosregs ireg, oreg;
113 u8 err;
114 112
115 ax = 0x8800; 113 initregs(&ireg);
116 asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax)); 114 ireg.ah = 0x88;
115 intcall(0x15, &ireg, &oreg);
117 116
118 boot_params.screen_info.ext_mem_k = ax; 117 boot_params.screen_info.ext_mem_k = oreg.ax;
119 118
120 return -err; 119 return -(oreg.eflags & X86_EFLAGS_CF); /* 0 or -1 */
121} 120}
122 121
123int detect_memory(void) 122int detect_memory(void)