summaryrefslogtreecommitdiff
path: root/sys/arch/amd64/stand/libsa/gidt.S
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2012-10-08 12:46:38 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2012-10-08 12:46:38 +0000
commitc80420c025506ab24825769ca28a545e89f52f74 (patch)
treec347adf9db5e144da2f1d6e0184d66fed2d5fb06 /sys/arch/amd64/stand/libsa/gidt.S
parent67c0fab681d2964d05a3f58d939718713a369357 (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/amd64/stand/libsa/gidt.S')
-rw-r--r--sys/arch/amd64/stand/libsa/gidt.S57
1 files changed, 44 insertions, 13 deletions
diff --git a/sys/arch/amd64/stand/libsa/gidt.S b/sys/arch/amd64/stand/libsa/gidt.S
index 04aab9828b9..325433b45dc 100644
--- a/sys/arch/amd64/stand/libsa/gidt.S
+++ b/sys/arch/amd64/stand/libsa/gidt.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: gidt.S,v 1.6 2006/12/29 11:44:01 tom Exp $ */
+/* $OpenBSD: gidt.S,v 1.7 2012/10/08 12:46:37 jsing Exp $ */
/*
* Copyright (c) 1997 Michael Shalayeff
@@ -312,6 +312,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)
*
@@ -320,7 +324,7 @@ IEMUENT(44); IEMUENT(45); IEMUENT(46); IEMUENT(47)
.align 8, 0x90
EMUh:
/* save %eax */
- mov %eax, 3f
+ mov %eax, 5f
pop %eax
pusha
@@ -332,18 +336,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
@@ -352,20 +367,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)
@@ -411,6 +442,6 @@ ENTRY(bootbuf)
sti
/* Jump to buffer */
- ljmp $0x0, $0x7c00
+ ljmp $0x0, $0x7c00
.end