diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2012-10-08 12:46:38 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2012-10-08 12:46:38 +0000 |
commit | c80420c025506ab24825769ca28a545e89f52f74 (patch) | |
tree | c347adf9db5e144da2f1d6e0184d66fed2d5fb06 /sys/arch/i386/stand | |
parent | 67c0fab681d2964d05a3f58d939718713a369357 (diff) |
Avoid accessing .data or .bss from real mode, since they may not be within
the current segment. Load and store the necessary BIOS registers from
protected mode, preserving the register values across the real mode and
protected mode switches by directly patching instructions. This allows for
boot(8) to be larger than 64KB.
Diffstat (limited to 'sys/arch/i386/stand')
-rw-r--r-- | sys/arch/i386/stand/libsa/gidt.S | 57 |
1 files changed, 44 insertions, 13 deletions
diff --git a/sys/arch/i386/stand/libsa/gidt.S b/sys/arch/i386/stand/libsa/gidt.S index 9fe2d7ac0cb..6ea7e8323d4 100644 --- a/sys/arch/i386/stand/libsa/gidt.S +++ b/sys/arch/i386/stand/libsa/gidt.S @@ -1,4 +1,4 @@ -/* $OpenBSD: gidt.S,v 1.32 2006/12/26 19:30:44 tom Exp $ */ +/* $OpenBSD: gidt.S,v 1.33 2012/10/08 12:46:37 jsing Exp $ */ /* * Copyright (c) 1997 Michael Shalayeff @@ -314,6 +314,10 @@ IEMUENT(44); IEMUENT(45); IEMUENT(46); IEMUENT(47) * entry point for BIOS real-mode interface * all the magic for real-prot mode switching is here * + * Note: Once in real mode access to .data or .bss should be avoided since it + * may not be reachable within the current segment. The following code also + * assumes that .text is writeable. + * * Call: %eax, %ecx, %edx, %ebx, %ebp, %esi, %edi, %es, %ds * Return: %eax, %edx, %ecx, %eflags (as returned from BIOS) * @@ -322,7 +326,7 @@ IEMUENT(44); IEMUENT(45); IEMUENT(46); IEMUENT(47) .align 8, 0x90 EMUh: /* save %eax */ - mov %eax, 3f + mov %eax, 5f pop %eax pusha @@ -334,18 +338,29 @@ EMUh: /* save BIOS int vector */ mov %al, intno + /* Load BIOS registers prior to switching to real mode. */ + movl _C_LABEL(BIOS_regs)+BIOSR_ES, %eax + mov %eax, 7f + movl _C_LABEL(BIOS_regs)+BIOSR_DS, %eax + mov %eax, 6f + prot2real push %ds - addr32 movw (_C_LABEL(BIOS_regs)+(BIOSR_ES) - LINKADDR), %ax - movw %ax, %es - addr32 movw (_C_LABEL(BIOS_regs)+(BIOSR_DS) - LINKADDR), %ax - movw %ax, %ds + # data32 movl $Leax, %eax + .byte 0x66, 0xb8 +7: .long 0x90909090 + mov %ax, %es + + # data32 movl $Leax, %eax + .byte 0x66, 0xb8 +6: .long 0x90909090 + mov %ax, %ds # data32 movl $Leax, %eax .byte 0x66, 0xb8 -3: .long 0x90909090 +5: .long 0x90909090 ;sti int $0 @@ -354,20 +369,36 @@ intno = . - 1 pop %ds - addr32 movl %ebx, (_C_LABEL(BIOS_regs)+(BIOSR_BX) - LINKADDR) - movw %es, %bx - addr32 movw %bx, (_C_LABEL(BIOS_regs)+(BIOSR_ES) - LINKADDR) + /* Preserve BX and ES for protected mode. */ + addr32 movl %eax, (2f - LINKADDR) + movl %ebx, %eax + addr32 movl %eax, (4f - LINKADDR) + movl %es, %eax + addr32 movl %eax, (3f - LINKADDR) + addr32 movl (2f - LINKADDR), %eax + movb %ah, %bh lahf xchgb %ah, %bh + /* Preserve AX for protected mode. */ addr32 movl %eax, (2f - LINKADDR) real2prot # movl $Leax, %eax - .byte 0xb8 -2: .long 0x90909090 + .byte 0xb8 +4: .long 0x90909090 + movl %eax, _C_LABEL(BIOS_regs)+BIOSR_BX + + # movl $Leax, %eax + .byte 0xb8 +3: .long 0x90909090 + movl %eax, _C_LABEL(BIOS_regs)+BIOSR_ES + + # movl $Leax, %eax + .byte 0xb8 +2: .long 0x90909090 /* pass BIOS return values back to caller */ movl %eax, 0xb*4(%esp) @@ -413,6 +444,6 @@ ENTRY(bootbuf) sti /* Jump to buffer */ - ljmp $0x0, $0x7c00 + ljmp $0x0, $0x7c00 .end |