From c80420c025506ab24825769ca28a545e89f52f74 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Mon, 8 Oct 2012 12:46:38 +0000 Subject: 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. --- sys/arch/amd64/stand/libsa/gidt.S | 57 ++++++++++++++++++++++++++++++--------- sys/arch/i386/stand/libsa/gidt.S | 57 ++++++++++++++++++++++++++++++--------- 2 files changed, 88 insertions(+), 26 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 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 -- cgit v1.2.3