Save segment registers on stack in case the thunk code assembly calls CF9 soft reset and the x64 registers get cleared.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8124 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
qhuang8 2009-04-17 07:47:08 +00:00
parent 0fe43214e3
commit 1e4371671b
2 changed files with 73 additions and 52 deletions

View File

@ -1,6 +1,6 @@
#------------------------------------------------------------------------------
#
# Copyright (c) 2006 - 2008, Intel Corporation
# Copyright (c) 2006 - 2009, Intel Corporation
# All rights reserved. This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
@ -18,6 +18,7 @@
# Real mode thunk
#
#------------------------------------------------------------------------------
#include <EdkIIGlueBase.h>
.globl ASM_PFX(m16Start)
@ -51,7 +52,7 @@
ASM_PFX(m16Size): .word ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start)
ASM_PFX(mThunk16Attr): .word _ThunkAttr - ASM_PFX(m16Start)
ASM_PFX(m16Gdt): .word _NullSeg - ASM_PFX(m16Start)
ASM_PFX(m16Gdt): .word ASM_PFX(NullSeg) - ASM_PFX(m16Start)
ASM_PFX(m16GdtrBase): .word _16GdtrBase - ASM_PFX(m16Start)
ASM_PFX(mTransition): .word _EntryPoint - ASM_PFX(m16Start)
@ -78,8 +79,8 @@ ASM_PFX(BackFromUserCode):
.byte 0x16 # push ss
.byte 0xe # push cs
.byte 0x66
call @Base # push eip
@Base:
call L_Base # push eip
L_Base:
.byte 0x66
pushq $0 # reserved high order 32 bits of EFlags
.byte 0x66, 0x9c # pushfd actually
@ -92,17 +93,17 @@ ASM_PFX(BackFromUserCode):
.byte 0x66,0xba # mov edx, imm32
_ThunkAttr: .space 4
testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15, %dl
jz @1
jz L_1
movl $0x15cd2401,%eax # mov ax, 2401h & int 15h
cli # disable interrupts
jnc @2
@1:
jnc L_2
L_1:
testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL, %dl
jz @2
jz L_2
inb $0x92,%al
orb $2,%al
outb %al, $0x92 # deactivate A20M#
@2:
L_2:
movl %ss,%eax
lea IA32_REGS_SIZE(%esp), %bp
#
@ -115,9 +116,9 @@ _ThunkAttr: .space 4
addw %ax,%bp # add ebp, eax
movw %cs,%ax
shlw $4,%ax
lea (@64BitCode - @Base)(%ebx, %eax), %ax
.byte 0x66,0x2e,0x89,0x87 # mov cs:[bx + (@64Eip - @Base)], eax
.word @64Eip - @Base
lea (L_64BitCode - L_Base)(%ebx, %eax), %ax
.byte 0x66,0x2e,0x89,0x87 # mov cs:[bx + (L_64Eip - L_Base)], eax
.word L_64Eip - L_Base
.byte 0x66,0xb8 # mov eax, imm32
SavedCr4: .space 4
movq %rax, %cr4
@ -125,7 +126,7 @@ SavedCr4: .space 4
# rdi in the instruction below is indeed bx in 16-bit code
#
.byte 0x66,0x2e # 2eh is "cs:" segment override
lgdt (SavedGdt - @Base)(%rdi)
lgdt (SavedGdt - L_Base)(%rdi)
.byte 0x66
movl $0xc0000080,%ecx
rdmsr
@ -134,17 +135,20 @@ SavedCr4: .space 4
.byte 0x66,0xb8 # mov eax, imm32
SavedCr0: .space 4
movq %rax, %cr0
.byte 0x66,0xea # jmp far cs:@64Bit
@64Eip: .space 4
.byte 0x66,0xea # jmp far cs:L_64Bit
L_64Eip: .space 4
SavedCs: .space 2
@64BitCode:
movq %r8, %rsp
L_64BitCode:
.byte 0x90
.byte 0x67,0xbc # mov esp, imm32
SavedSp: .space 4 # restore stack
nop
ret
_EntryPoint: .long ASM_PFX(ToUserCode) - ASM_PFX(m16Start)
.word CODE16
_16Gdtr: .word GDT_SIZE - 1
_16GdtrBase: .quad _NullSeg
_16GdtrBase: .quad ASM_PFX(NullSeg)
_16Idtr: .word 0x3ff
.long 0
@ -169,16 +173,16 @@ ASM_PFX(ToUserCode):
movl %esi,%ss # set up 16-bit stack segment
movw %bx,%sp # set up 16-bit stack pointer
.byte 0x66 # make the following call 32-bit
call @Base1 # push eip
@Base1:
popw %bp # ebp <- address of @Base1
call L_Base1 # push eip
L_Base1:
popw %bp # ebp <- address of L_Base1
pushq (IA32_REGS_SIZE + 2)(%esp)
lea 0x0c(%rsi), %eax
pushq %rax
lret # execution begins at next instruction
@RealMode:
L_RealMode:
.byte 0x66,0x2e # CS and operand size override
lidt (_16Idtr - @Base1)(%rsi)
lidt (_16Idtr - L_Base1)(%rsi)
.byte 0x66,0x61 # popad
.byte 0x1f # pop ds
.byte 0x7 # pop es
@ -189,26 +193,26 @@ ASM_PFX(ToUserCode):
.byte 0x66 # make the following retf 32-bit
lret # transfer control to user code
.equ CODE16, ASM_PFX(16Code) - .
.equ DATA16, ASM_PFX(16Data) - .
.equ DATA32, ASM_PFX(32Data) - .
.equ CODE16, ASM_PFX(_16Code) - .
.equ DATA16, ASM_PFX(_16Data) - .
.equ DATA32, ASM_PFX(_32Data) - .
_NullSeg: .quad 0
ASM_PFX(16Code):
ASM_PFX(NullSeg): .quad 0
ASM_PFX(_16Code):
.word -1
.word 0
.byte 0
.byte 0x9b
.byte 0x8f # 16-bit segment, 4GB limit
.byte 0
ASM_PFX(16Data):
ASM_PFX(_16Data):
.word -1
.word 0
.byte 0
.byte 0x93
.byte 0x8f # 16-bit segment, 4GB limit
.byte 0
ASM_PFX(32Data):
ASM_PFX(_32Data):
.word -1
.word 0
.byte 0
@ -226,7 +230,6 @@ ASM_PFX(32Data):
# IN OUT VOID *Transition
# );
#------------------------------------------------------------------------------
# MISMATCH: "InternalAsmThunk16 PROC USES rbp rbx rsi rdi"
.globl ASM_PFX(InternalAsmThunk16)
ASM_PFX(InternalAsmThunk16):
@ -235,9 +238,13 @@ ASM_PFX(InternalAsmThunk16):
pushq %rsi
pushq %rdi
movl %ds, %r10d # r9 ~ r11 are not accessible in 16-bit
movl %es, %r11d # so use them for saving seg registers
movl %ss, %r9d
movq %ds, %rbx
pushq %rbx # Save ds segment register on the stack
movq %es, %rbx
pushq %rbx # Save es segment register on the stack
movq %ss, %rbx
pushq %rbx # Save ss segment register on the stack
.byte 0x0f, 0xa0 #push fs
.byte 0x0f, 0xa8 #push gs
movq %rcx, %rsi
@ -258,7 +265,7 @@ ASM_PFX(InternalAsmThunk16):
lea (_BackFromUserCode - ASM_PFX(m16Start))(%rdx), %ax
stosl # [edi] <- return address of user code
sgdt (SavedGdt - SavedCr4)(%rcx)
sidt 0x38(%rsp)
sidt 0x50(%rsp)
movq %cr0, %rax
movl %eax, (SavedCr0 - SavedCr4)(%rcx)
andl $0x7ffffffe,%eax # clear PE, PG bits
@ -272,22 +279,26 @@ ASM_PFX(InternalAsmThunk16):
movl %edx,%ss
pushfq
lea -8(%rdx), %edx
lea @RetFromRealMode, %r8
lea L_RetFromRealMode, %r8
pushq %r8
movl %cs, %r8d
movw %r8w, (SavedCs - SavedCr4)(%rcx)
movq %rsp, %r8
movl %esp, (SavedSp - SavedCr4)(%rcx)
.byte 0xff, 0x69 # jmp (_EntryPoint - SavedCr4)(%rcx)
.byte _EntryPoint - SavedCr4
@RetFromRealMode:
L_RetFromRealMode:
popfq
lidt 0x38(%rsp)
lidt 0x50(%rsp)
lea -IA32_REGS_SIZE(%rbp), %eax
.byte 0x0f, 0xa9 # pop gs
.byte 0x0f, 0xa1 # pop fs
movl %r9d, %ss
movl %r11d, %es
movl %r10d, %ds
popq %rbx
movq %rbx, %ss
popq %rbx
movq %rbx, %es
popq %rbx
movq %rbx, %ds
popq %rdi
popq %rsi

View File

@ -138,7 +138,10 @@ SavedCr0 DD ?
@64Eip DD ?
SavedCs DW ?
@64BitCode:
mov rsp, r8 ; restore stack
db 090h
db 067h, 0bch ; mov esp, imm32
SavedSp DD ? ; restore stack
nop
ret
_BackFromUserCode ENDP
@ -228,9 +231,13 @@ GDT_SIZE = $ - _NullSeg
; );
;------------------------------------------------------------------------------
InternalAsmThunk16 PROC USES rbp rbx rsi rdi
mov r10d, ds ; r9 ~ r11 are not accessible in 16-bit
mov r11d, es ; so use them for saving seg registers
mov r9d, ss
mov rbx, ds
push rbx ; Save ds segment register on the stack
mov rbx, es
push rbx ; Save es segment register on the stack
mov rbx, ss
push rbx ; Save ss segment register on the stack
push fs
push gs
mov rsi, rcx
@ -250,7 +257,7 @@ InternalAsmThunk16 PROC USES rbp rbx rsi rdi
lea ax, [rdx + (_BackFromUserCode - m16Start)] ; offset address
stosd ; [edi] <- return address of user code
sgdt fword ptr [rcx + (SavedGdt - SavedCr4)]
sidt fword ptr [rsp + 38h] ; save IDT stack in argument space
sidt fword ptr [rsp + 50h] ; save IDT stack in argument space
mov rax, cr0
mov [rcx + (SavedCr0 - SavedCr4)], eax
and eax, 7ffffffeh ; clear PE, PG bits
@ -268,17 +275,20 @@ InternalAsmThunk16 PROC USES rbp rbx rsi rdi
push r8
mov r8d, cs
mov [rcx + (SavedCs - SavedCr4)], r8w
mov r8, rsp
mov [rcx + (SavedSp - SavedCr4)], esp
jmp fword ptr [rcx + (_EntryPoint - SavedCr4)]
@RetFromRealMode:
popfq
lidt fword ptr [rsp + 38h] ; restore protected mode IDTR
lidt fword ptr [rsp + 50h] ; restore protected mode IDTR
lea eax, [rbp - sizeof (IA32_REGS)]
pop gs
pop fs
mov ss, r9d
mov es, r11d
mov ds, r10d
pop rbx
mov ss, rbx
pop rbx
mov es, rbx
pop rbx
mov ds, rbx
ret
InternalAsmThunk16 ENDP