diff options
Diffstat (limited to 'arch/x86/boot/memory.c')
-rw-r--r-- | arch/x86/boot/memory.c | 81 |
1 files changed, 40 insertions, 41 deletions
diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c index 5054c2ddd1a0..d989de810cac 100644 --- a/arch/x86/boot/memory.c +++ b/arch/x86/boot/memory.c | |||
@@ -25,12 +25,16 @@ struct e820_ext_entry { | |||
25 | static int detect_memory_e820(void) | 25 | static 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 | ||
82 | static int detect_memory_e801(void) | 77 | static 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 | ||
113 | static int detect_memory_88(void) | 112 | static 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 | ||
126 | int detect_memory(void) | 125 | int detect_memory(void) |