Skip to content

Commit 7a734e7

Browse files
H. Peter AnvinH. Peter Anvin
authored andcommitted
x86, setup: "glove box" BIOS calls -- infrastructure
Impact: new interfaces (not yet used) For all the platforms out there, there is an infinite number of buggy BIOSes. This adds infrastructure to treat BIOS interrupts more like toxic waste and "glove box" them -- we switch out the register set, perform the BIOS interrupt, and then restore the previous state. LKML-Reference: <[email protected]> Signed-off-by: H. Peter Anvin <[email protected]> Cc: Pavel Machek <[email protected]> Cc: Rafael J. Wysocki <[email protected]>
1 parent 62b8e68 commit 7a734e7

File tree

9 files changed

+172
-4
lines changed

9 files changed

+172
-4
lines changed

arch/x86/boot/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ targets := vmlinux.bin setup.bin setup.elf bzImage
2626
targets += fdimage fdimage144 fdimage288 image.iso mtools.conf
2727
subdir- := compressed
2828

29-
setup-y += a20.o cmdline.o copy.o cpu.o cpucheck.o edd.o
29+
setup-y += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.o edd.o
3030
setup-y += header.o main.o mca.o memory.o pm.o pmjump.o
31-
setup-y += printf.o string.o tty.o video.o video-mode.o version.o
31+
setup-y += printf.o regs.o string.o tty.o video.o video-mode.o
32+
setup-y += version.o
3233
setup-$(CONFIG_X86_APM_BOOT) += apm.o
3334

3435
# The link order of the video-*.o modules can matter. In particular,

arch/x86/boot/bioscall.S

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* -----------------------------------------------------------------------
2+
*
3+
* Copyright 2009 Intel Corporation; author H. Peter Anvin
4+
*
5+
* This file is part of the Linux kernel, and is made available under
6+
* the terms of the GNU General Public License version 2 or (at your
7+
* option) any later version; incorporated herein by reference.
8+
*
9+
* ----------------------------------------------------------------------- */
10+
11+
/*
12+
* "Glove box" for BIOS calls. Avoids the constant problems with BIOSes
13+
* touching memory they shouldn't be.
14+
*/
15+
16+
.code16
17+
.text
18+
.globl intcall
19+
.type intcall, @function
20+
intcall:
21+
/* Self-modify the INT instruction. Ugly, but works. */
22+
cmpb %al, 3f
23+
je 1f
24+
movb %al, 3f
25+
jmp 1f /* Synchronize pipeline */
26+
1:
27+
/* Save state */
28+
pushfl
29+
pushw %fs
30+
pushw %gs
31+
pushal
32+
33+
/* Copy input state to stack frame */
34+
subw $44, %sp
35+
movw %dx, %si
36+
movw %sp, %di
37+
movw $11, %cx
38+
rep; movsd
39+
40+
/* Pop full state from the stack */
41+
popal
42+
popw %gs
43+
popw %fs
44+
popw %es
45+
popw %ds
46+
popfl
47+
48+
/* Actual INT */
49+
.byte 0xcd /* INT opcode */
50+
3: .byte 0
51+
52+
/* Push full state to the stack */
53+
pushfl
54+
pushw %ds
55+
pushw %es
56+
pushw %fs
57+
pushw %gs
58+
pushal
59+
60+
/* Re-establish C environment invariants */
61+
cld
62+
movzwl %sp, %esp
63+
movw %cs, %ax
64+
movw %ax, %ds
65+
movw %ax, %es
66+
67+
/* Copy output state from stack frame */
68+
movw 68(%esp), %di /* Original %cx == 3rd argument */
69+
andw %di, %di
70+
jz 4f
71+
movw %sp, %si
72+
movw $11, %cx
73+
rep; movsd
74+
4: addw $44, %sp
75+
76+
/* Restore state and return */
77+
popal
78+
popw %gs
79+
popw %fs
80+
popfl
81+
retl
82+
.size intcall, .-intcall

arch/x86/boot/boot.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
*
33
* Copyright (C) 1991, 1992 Linus Torvalds
44
* Copyright 2007 rPath, Inc. - All Rights Reserved
5+
* Copyright 2009 Intel Corporation; author H. Peter Anvin
56
*
67
* This file is part of the Linux kernel, and is made available under
78
* the terms of the GNU General Public License version 2.
@@ -26,6 +27,7 @@
2627
#include <asm/setup.h>
2728
#include "bitops.h"
2829
#include <asm/cpufeature.h>
30+
#include <asm/processor-flags.h>
2931

3032
/* Useful macros */
3133
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
@@ -241,6 +243,49 @@ int enable_a20(void);
241243
/* apm.c */
242244
int query_apm_bios(void);
243245

246+
/* bioscall.c */
247+
struct biosregs {
248+
union {
249+
struct {
250+
u32 edi;
251+
u32 esi;
252+
u32 ebp;
253+
u32 _esp;
254+
u32 ebx;
255+
u32 edx;
256+
u32 ecx;
257+
u32 eax;
258+
u32 _fsgs;
259+
u32 _dses;
260+
u32 eflags;
261+
};
262+
struct {
263+
u16 di, hdi;
264+
u16 si, hsi;
265+
u16 bp, hbp;
266+
u16 _sp, _hsp;
267+
u16 bx, hbx;
268+
u16 dx, hdx;
269+
u16 cx, hcx;
270+
u16 ax, hax;
271+
u16 gs, fs;
272+
u16 es, ds;
273+
u16 flags, hflags;
274+
};
275+
struct {
276+
u8 dil, dih, edi2, edi3;
277+
u8 sil, sih, esi2, esi3;
278+
u8 bpl, bph, ebp2, ebp3;
279+
u8 _spl, _sph, _esp2, _esp3;
280+
u8 bl, bh, ebx2, ebx3;
281+
u8 dl, dh, edx2, edx3;
282+
u8 cl, ch, ecx2, ecx3;
283+
u8 al, ah, eax2, eax3;
284+
};
285+
};
286+
};
287+
void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg);
288+
244289
/* cmdline.c */
245290
int cmdline_find_option(const char *option, char *buffer, int bufsize);
246291
int cmdline_find_option_bool(const char *option);
@@ -279,6 +324,9 @@ int sprintf(char *buf, const char *fmt, ...);
279324
int vsprintf(char *buf, const char *fmt, va_list args);
280325
int printf(const char *fmt, ...);
281326

327+
/* regs.c */
328+
void initregs(struct biosregs *regs);
329+
282330
/* string.c */
283331
int strcmp(const char *str1, const char *str2);
284332
size_t strnlen(const char *s, size_t maxlen);

arch/x86/boot/header.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ setup_data: .quad 0 # 64-bit physical pointer to
221221

222222
# End of setup header #####################################################
223223

224-
.section ".inittext", "ax"
224+
.section ".entrytext", "ax"
225225
start_of_setup:
226226
#ifdef SAFE_RESET_DISK_CONTROLLER
227227
# Reset the disk controller.

arch/x86/boot/regs.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* -----------------------------------------------------------------------
2+
*
3+
* Copyright 2009 Intel Corporation; author H. Peter Anvin
4+
*
5+
* This file is part of the Linux kernel, and is made available under
6+
* the terms of the GNU General Public License version 2 or (at your
7+
* option) any later version; incorporated herein by reference.
8+
*
9+
* ----------------------------------------------------------------------- */
10+
11+
/*
12+
* Simple helper function for initializing a register set.
13+
*
14+
* Note that this sets EFLAGS_CF in the input register set; this
15+
* makes it easier to catch functions which do nothing but don't
16+
* explicitly set CF.
17+
*/
18+
19+
#include "boot.h"
20+
21+
void initregs(struct biosregs *reg)
22+
{
23+
memset(reg, 0, sizeof *reg);
24+
reg->eflags |= X86_EFLAGS_CF;
25+
reg->ds = ds();
26+
reg->es = ds();
27+
reg->fs = fs();
28+
reg->gs = gs();
29+
}

arch/x86/boot/setup.ld

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ SECTIONS
1515

1616
. = 497;
1717
.header : { *(.header) }
18+
.entrytext : { *(.entrytext) }
1819
.inittext : { *(.inittext) }
1920
.initdata : { *(.initdata) }
21+
__end_init = .;
22+
2023
.text : { *(.text) }
2124
.text32 : { *(.text32) }
2225

@@ -52,4 +55,7 @@ SECTIONS
5255

5356
. = ASSERT(_end <= 0x8000, "Setup too big!");
5457
. = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
58+
/* Necessary for the very-old-loader check to work... */
59+
. = ASSERT(__end_init <= 5*512, "init sections too big!");
60+
5561
}

arch/x86/kernel/acpi/realmode/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
always := wakeup.bin
1010
targets := wakeup.elf wakeup.lds
1111

12-
wakeup-y += wakeup.o wakemain.o video-mode.o copy.o
12+
wakeup-y += wakeup.o wakemain.o video-mode.o copy.o bioscall.o regs.o
1313

1414
# The link order of the video-*.o modules can matter. In particular,
1515
# video-vga.o *must* be listed first, followed by video-vesa.o.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#include "../../../boot/bioscall.S"

arch/x86/kernel/acpi/realmode/regs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#include "../../../boot/regs.c"

0 commit comments

Comments
 (0)