diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2009-04-01 21:13:46 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-04-09 19:08:11 -0400 |
commit | df7699c56421c0476704f24a43409ac8c505f3d2 (patch) | |
tree | c8d5935a5bd7dd59b0ce70db1a53999090be938b /arch/x86/boot | |
parent | 7a734e7dd93b9aea08ed51036a9a0e2c9dfd8dac (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')
-rw-r--r-- | arch/x86/boot/a20.c | 9 | ||||
-rw-r--r-- | arch/x86/boot/main.c | 39 | ||||
-rw-r--r-- | arch/x86/boot/memory.c | 81 | ||||
-rw-r--r-- | arch/x86/boot/tty.c | 52 |
4 files changed, 95 insertions, 86 deletions
diff --git a/arch/x86/boot/a20.c b/arch/x86/boot/a20.c index 7c19ce8c2442..64a31a6d751a 100644 --- a/arch/x86/boot/a20.c +++ b/arch/x86/boot/a20.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007-2008 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007-2008 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation | 5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin |
6 | * | 6 | * |
7 | * This file is part of the Linux kernel, and is made available under | 7 | * This file is part of the Linux kernel, and is made available under |
8 | * the terms of the GNU General Public License version 2. | 8 | * the terms of the GNU General Public License version 2. |
@@ -90,8 +90,11 @@ static int a20_test_long(void) | |||
90 | 90 | ||
91 | static void enable_a20_bios(void) | 91 | static void enable_a20_bios(void) |
92 | { | 92 | { |
93 | asm volatile("pushfl; int $0x15; popfl" | 93 | struct biosregs ireg; |
94 | : : "a" ((u16)0x2401)); | 94 | |
95 | initregs(&ireg); | ||
96 | ireg.ax = 0x2401; | ||
97 | intcall(0x15, &ireg, NULL); | ||
95 | } | 98 | } |
96 | 99 | ||
97 | static void enable_a20_kbc(void) | 100 | static void enable_a20_kbc(void) |
diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c index 58f0415d3ae0..140172b895bd 100644 --- a/arch/x86/boot/main.c +++ b/arch/x86/boot/main.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * This file is part of the Linux kernel, and is made available under |
7 | * the terms of the GNU General Public License version 2. | 8 | * the terms of the GNU General Public License version 2. |
@@ -61,11 +62,10 @@ static void copy_boot_params(void) | |||
61 | */ | 62 | */ |
62 | static void keyboard_set_repeat(void) | 63 | static void keyboard_set_repeat(void) |
63 | { | 64 | { |
64 | u16 ax = 0x0305; | 65 | struct biosregs ireg; |
65 | u16 bx = 0; | 66 | initregs(&ireg); |
66 | asm volatile("int $0x16" | 67 | ireg.ax = 0x0305; |
67 | : "+a" (ax), "+b" (bx) | 68 | intcall(0x16, &ireg, NULL); |
68 | : : "ecx", "edx", "esi", "edi"); | ||
69 | } | 69 | } |
70 | 70 | ||
71 | /* | 71 | /* |
@@ -73,18 +73,22 @@ static void keyboard_set_repeat(void) | |||
73 | */ | 73 | */ |
74 | static void query_ist(void) | 74 | static void query_ist(void) |
75 | { | 75 | { |
76 | struct biosregs ireg, oreg; | ||
77 | |||
76 | /* Some older BIOSes apparently crash on this call, so filter | 78 | /* Some older BIOSes apparently crash on this call, so filter |
77 | it from machines too old to have SpeedStep at all. */ | 79 | it from machines too old to have SpeedStep at all. */ |
78 | if (cpu.level < 6) | 80 | if (cpu.level < 6) |
79 | return; | 81 | return; |
80 | 82 | ||
81 | asm("int $0x15" | 83 | initregs(&ireg); |
82 | : "=a" (boot_params.ist_info.signature), | 84 | ireg.ax = 0xe980; /* IST Support */ |
83 | "=b" (boot_params.ist_info.command), | 85 | ireg.edx = 0x47534943; /* Request value */ |
84 | "=c" (boot_params.ist_info.event), | 86 | intcall(0x15, &ireg, &oreg); |
85 | "=d" (boot_params.ist_info.perf_level) | 87 | |
86 | : "a" (0x0000e980), /* IST Support */ | 88 | boot_params.ist_info.signature = oreg.eax; |
87 | "d" (0x47534943)); /* Request value */ | 89 | boot_params.ist_info.command = oreg.ebx; |
90 | boot_params.ist_info.event = oreg.ecx; | ||
91 | boot_params.ist_info.perf_level = oreg.edx; | ||
88 | } | 92 | } |
89 | 93 | ||
90 | /* | 94 | /* |
@@ -93,13 +97,12 @@ static void query_ist(void) | |||
93 | static void set_bios_mode(void) | 97 | static void set_bios_mode(void) |
94 | { | 98 | { |
95 | #ifdef CONFIG_X86_64 | 99 | #ifdef CONFIG_X86_64 |
96 | u32 eax, ebx; | 100 | struct biosregs ireg; |
97 | 101 | ||
98 | eax = 0xec00; | 102 | initregs(&ireg); |
99 | ebx = 2; | 103 | ireg.ax = 0xec00; |
100 | asm volatile("int $0x15" | 104 | ireg.bx = 2; |
101 | : "+a" (eax), "+b" (ebx) | 105 | intcall(0x15, &ireg, NULL); |
102 | : : "ecx", "edx", "esi", "edi"); | ||
103 | #endif | 106 | #endif |
104 | } | 107 | } |
105 | 108 | ||
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) |
diff --git a/arch/x86/boot/tty.c b/arch/x86/boot/tty.c index 7e8e8b25f5f6..01ec69c901c7 100644 --- a/arch/x86/boot/tty.c +++ b/arch/x86/boot/tty.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * | 2 | * |
3 | * Copyright (C) 1991, 1992 Linus Torvalds | 3 | * Copyright (C) 1991, 1992 Linus Torvalds |
4 | * Copyright 2007 rPath, Inc. - All Rights Reserved | 4 | * Copyright 2007 rPath, Inc. - All Rights Reserved |
5 | * Copyright 2009 Intel Corporation; author H. Peter Anvin | ||
5 | * | 6 | * |
6 | * This file is part of the Linux kernel, and is made available under | 7 | * This file is part of the Linux kernel, and is made available under |
7 | * the terms of the GNU General Public License version 2. | 8 | * the terms of the GNU General Public License version 2. |
@@ -22,24 +23,23 @@ | |||
22 | 23 | ||
23 | void __attribute__((section(".inittext"))) putchar(int ch) | 24 | void __attribute__((section(".inittext"))) putchar(int ch) |
24 | { | 25 | { |
25 | unsigned char c = ch; | 26 | struct biosregs ireg; |
26 | 27 | ||
27 | if (c == '\n') | 28 | if (ch == '\n') |
28 | putchar('\r'); /* \n -> \r\n */ | 29 | putchar('\r'); /* \n -> \r\n */ |
29 | 30 | ||
30 | /* int $0x10 is known to have bugs involving touching registers | 31 | initregs(&ireg); |
31 | it shouldn't. Be extra conservative... */ | 32 | ireg.bx = 0x0007; |
32 | asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal" | 33 | ireg.cx = 0x0001; |
33 | : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch)); | 34 | ireg.ah = 0x0e; |
35 | ireg.al = ch; | ||
36 | intcall(0x10, &ireg, NULL); | ||
34 | } | 37 | } |
35 | 38 | ||
36 | void __attribute__((section(".inittext"))) puts(const char *str) | 39 | void __attribute__((section(".inittext"))) puts(const char *str) |
37 | { | 40 | { |
38 | int n = 0; | 41 | while (*str) |
39 | while (*str) { | ||
40 | putchar(*str++); | 42 | putchar(*str++); |
41 | n++; | ||
42 | } | ||
43 | } | 43 | } |
44 | 44 | ||
45 | /* | 45 | /* |
@@ -49,14 +49,13 @@ void __attribute__((section(".inittext"))) puts(const char *str) | |||
49 | 49 | ||
50 | static u8 gettime(void) | 50 | static u8 gettime(void) |
51 | { | 51 | { |
52 | u16 ax = 0x0200; | 52 | struct biosregs ireg, oreg; |
53 | u16 cx, dx; | ||
54 | 53 | ||
55 | asm volatile("int $0x1a" | 54 | initregs(&ireg); |
56 | : "+a" (ax), "=c" (cx), "=d" (dx) | 55 | ireg.ah = 0x02; |
57 | : : "ebx", "esi", "edi"); | 56 | intcall(0x1a, &ireg, &oreg); |
58 | 57 | ||
59 | return dx >> 8; | 58 | return oreg.dh; |
60 | } | 59 | } |
61 | 60 | ||
62 | /* | 61 | /* |
@@ -64,19 +63,24 @@ static u8 gettime(void) | |||
64 | */ | 63 | */ |
65 | int getchar(void) | 64 | int getchar(void) |
66 | { | 65 | { |
67 | u16 ax = 0; | 66 | struct biosregs ireg, oreg; |
68 | asm volatile("int $0x16" : "+a" (ax)); | 67 | |
68 | initregs(&ireg); | ||
69 | /* ireg.ah = 0x00; */ | ||
70 | intcall(0x16, &ireg, &oreg); | ||
69 | 71 | ||
70 | return ax & 0xff; | 72 | return oreg.al; |
71 | } | 73 | } |
72 | 74 | ||
73 | static int kbd_pending(void) | 75 | static int kbd_pending(void) |
74 | { | 76 | { |
75 | u8 pending; | 77 | struct biosregs ireg, oreg; |
76 | asm volatile("int $0x16; setnz %0" | 78 | |
77 | : "=qm" (pending) | 79 | initregs(&ireg); |
78 | : "a" (0x0100)); | 80 | ireg.ah = 0x01; |
79 | return pending; | 81 | intcall(0x16, &ireg, &oreg); |
82 | |||
83 | return !(oreg.eflags & X86_EFLAGS_ZF); | ||
80 | } | 84 | } |
81 | 85 | ||
82 | void kbd_flush(void) | 86 | void kbd_flush(void) |