aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/boot
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
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')
-rw-r--r--arch/x86/boot/a20.c9
-rw-r--r--arch/x86/boot/main.c39
-rw-r--r--arch/x86/boot/memory.c81
-rw-r--r--arch/x86/boot/tty.c52
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
91static void enable_a20_bios(void) 91static 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
97static void enable_a20_kbc(void) 100static 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 */
62static void keyboard_set_repeat(void) 63static 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 */
74static void query_ist(void) 74static 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)
93static void set_bios_mode(void) 97static 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 {
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)
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
23void __attribute__((section(".inittext"))) putchar(int ch) 24void __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
36void __attribute__((section(".inittext"))) puts(const char *str) 39void __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
50static u8 gettime(void) 50static 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 */
65int getchar(void) 64int 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
73static int kbd_pending(void) 75static 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
82void kbd_flush(void) 86void kbd_flush(void)