MdePkg BaseLib NASM Thunk16: Use bits 16 for 16-bit code

By using 'bits 16', we can write code for 16-bit use the actual
assembly syntax rather than 'DB' and sometimes writing code with
seemingly incorrect operands because we know it will run correctly
when the processor is running in 16-bit mode.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16023 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Jordan Justen 2014-09-01 17:23:51 +00:00 committed by jljusten
parent a8458d6cb3
commit f6888eea46
2 changed files with 87 additions and 115 deletions

View File

@ -82,23 +82,24 @@ _BackFromUserCode:
; in IA32_REGS structure. This facilitates wrapper function to extract them ; in IA32_REGS structure. This facilitates wrapper function to extract them
; into that structure. ; into that structure.
; ;
BITS 16
push ss push ss
push cs push cs
DB 66h o32 call dword .Base ; push eip
call .Base ; push eip
.Base: .Base:
pushfw ; pushfd actually pushfd
cli ; disable interrupts cli ; disable interrupts
push gs push gs
push fs push fs
push es push es
push ds push ds
pushaw ; pushad actually pushad
DB 66h, 0bah ; mov edx, imm32 DB 66h, 0bah ; mov edx, imm32
.ThunkAttr: dd 0 .ThunkAttr: dd 0
test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
jz .1 jz .1
mov eax, 15cd2401h ; mov ax, 2401h & int 15h mov ax, 2401h
int 15h
cli ; disable interrupts cli ; disable interrupts
jnc .2 jnc .2
.1: .1:
@ -108,24 +109,17 @@ _BackFromUserCode:
or al, 2 or al, 2
out 92h, al ; deactivate A20M# out 92h, al ; deactivate A20M#
.2: .2:
xor ax, ax ; xor eax, eax xor eax, eax
mov eax, ss ; mov ax, ss mov ax, ss
DB 67h lea ebp, [esp + IA32_REGS.size]
lea bp, [esp + IA32_REGS.size] mov [bp - IA32_REGS.size + IA32_REGS._ESP], ebp
; mov bx, [bp - IA32_REGS.size + IA32_REGS._EIP]
; esi's in the following 2 instructions are indeed bp in 16-bit code. Fact shl eax, 4 ; shl eax, 4
; is "esi" in 32-bit addressing mode has the same encoding of "bp" in 16- add ebp, eax ; add ebp, eax
; bit addressing mode.
;
mov [esi - IA32_REGS.size + IA32_REGS._ESP], bp
mov ebx, [esi - IA32_REGS.size + IA32_REGS._EIP]
shl ax, 4 ; shl eax, 4
add bp, ax ; add ebp, eax
DB 66h, 0b8h ; mov eax, imm32 DB 66h, 0b8h ; mov eax, imm32
.SavedCr4: DD 0 .SavedCr4: DD 0
mov cr4, eax mov cr4, eax
DB 66h o32 lgdt [cs:bx + (SavedGdt - .Base)]
lgdt [cs:edi + (SavedGdt - .Base)]
DB 66h, 0b8h ; mov eax, imm32 DB 66h, 0b8h ; mov eax, imm32
.SavedCr0: DD 0 .SavedCr0: DD 0
mov cr0, eax mov cr0, eax
@ -134,8 +128,7 @@ _BackFromUserCode:
mov ss, eax mov ss, eax
DB 66h, 0bch ; mov esp, imm32 DB 66h, 0bch ; mov esp, imm32
.SavedEsp DD 0 .SavedEsp DD 0
DB 66h o32 retf ; return to protected mode
retf ; return to protected mode
_EntryPoint: _EntryPoint:
DD _ToUserCode - ASM_PFX(m16Start) DD _ToUserCode - ASM_PFX(m16Start)
@ -153,45 +146,34 @@ _16GdtrBase:
; It will be shadowed to somewhere in memory below 1MB. ; It will be shadowed to somewhere in memory below 1MB.
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
_ToUserCode: _ToUserCode:
mov edx, ss BITS 16
mov ss, ecx ; set new segment selectors mov dx, ss
mov ds, ecx mov ss, cx ; set new segment selectors
mov es, ecx mov ds, cx
mov fs, ecx mov es, cx
mov gs, ecx mov fs, cx
mov gs, cx
mov cr0, eax ; real mode starts at next instruction mov cr0, eax ; real mode starts at next instruction
; which (per SDM) *must* be a far JMP. ; which (per SDM) *must* be a far JMP.
DB 0eah DB 0eah
.RealAddr: DW 0, 0 .RealAddr: DW 0, 0
mov cr4, ebp mov cr4, ebp
mov ss, esi ; set up 16-bit stack segment mov ss, si ; set up 16-bit stack segment
xchg sp, bx ; set up 16-bit stack pointer xchg esp, ebx ; set up 16-bit stack pointer
mov bp, [esp + IA32_REGS.size]
mov [cs:bp + (_BackFromUserCode.SavedSs - _BackFromUserCode)], dx
mov [cs:bp + (_BackFromUserCode.SavedEsp - _BackFromUserCode)], ebx
lidt [cs:bp + (_16Idtr - _BackFromUserCode)]
; mov bp, [esp + sizeof(IA32_REGS) popad
DB 67h
mov ebp, [esp + IA32_REGS.size] ; BackFromUserCode address from stack
; mov cs:[bp + (_BackFromUserCode.SavedSs - _BackFromUserCode)], dx
mov [cs:esi + (_BackFromUserCode.SavedSs - _BackFromUserCode)], edx
; mov cs:[bp + (_BackFromUserCode.SavedEsp - _BackFromUserCode)], ebx
DB 2eh, 66h, 89h, 9eh
DW _BackFromUserCode.SavedEsp - _BackFromUserCode
; lidt cs:[bp + (_16Idtr - _BackFromUserCode)]
DB 2eh, 66h, 0fh, 01h, 9eh
DW _16Idtr - _BackFromUserCode
popaw ; popad actually
pop ds pop ds
pop es pop es
pop fs pop fs
pop gs pop gs
popfw ; popfd popfd
DB 66h ; Use 32-bit addressing for "retf" below o32 retf ; transfer control to user code
retf ; transfer control to user code
ALIGN 16 ALIGN 16
_NullSegDesc DQ 0 _NullSegDesc DQ 0
@ -221,6 +203,7 @@ GdtEnd:
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
global ASM_PFX(InternalAsmThunk16) global ASM_PFX(InternalAsmThunk16)
ASM_PFX(InternalAsmThunk16): ASM_PFX(InternalAsmThunk16):
BITS 32
push ebp push ebp
push ebx push ebx
push esi push esi

View File

@ -80,28 +80,25 @@ _BackFromUserCode:
; in IA32_REGS structure. This facilitates wrapper function to extract them ; in IA32_REGS structure. This facilitates wrapper function to extract them
; into that structure. ; into that structure.
; ;
; Some instructions for manipulation of segment registers have to be written BITS 16
; in opcode since 64-bit MASM prevents accesses to those registers. push ss
; push cs
DB 16h ; push ss o32 call dword .Base ; push eip
DB 0eh ; push cs
DB 66h
call .Base ; push eip
.Base: .Base:
DB 66h push dword 0 ; reserved high order 32 bits of EFlags
push 0 ; reserved high order 32 bits of EFlags pushfd
pushfw ; pushfd actually
cli ; disable interrupts cli ; disable interrupts
push gs push gs
push fs push fs
DB 6 ; push es push es
DB 1eh ; push ds push ds
DB 66h, 60h ; pushad pushad
DB 66h, 0bah ; mov edx, imm32 DB 66h, 0bah ; mov edx, imm32
.ThunkAttr: dd 0 .ThunkAttr: dd 0
test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
jz .1 jz .1
mov eax, 15cd2401h ; mov ax, 2401h & int 15h mov ax, 2401h
int 15h
cli ; disable interrupts cli ; disable interrupts
jnc .2 jnc .2
.1: .1:
@ -111,43 +108,34 @@ _BackFromUserCode:
or al, 2 or al, 2
out 92h, al ; deactivate A20M# out 92h, al ; deactivate A20M#
.2: .2:
xor ax, ax ; xor eax, eax xor eax, eax
mov eax, ss ; mov ax, ss mov ax, ss
lea bp, [esp + IA32_REGS.size] lea ebp, [esp + IA32_REGS.size]
; mov [bp - IA32_REGS.size + IA32_REGS._ESP], ebp
; rsi in the following 2 instructions is indeed bp in 16-bit code mov ebx, [bp - IA32_REGS.size + IA32_REGS._EIP]
; shl eax, 4 ; shl eax, 4
mov [rsi - IA32_REGS.size + IA32_REGS._ESP], bp add ebp, eax ; add ebp, eax
DB 66h mov eax, cs
mov ebx, [rsi - IA32_REGS.size + IA32_REGS._EIP] shl eax, 4
shl ax, 4 ; shl eax, 4 lea eax, [eax + ebx + (.64BitCode - .Base)]
add bp, ax ; add ebp, eax mov [cs:bx + (.64Eip - .Base)], eax
mov ax, cs
shl ax, 4
lea ax, [eax + ebx + (.64BitCode - .Base)]
DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (.64Eip - .Base)], eax
DW .64Eip - .Base
DB 66h, 0b8h ; mov eax, imm32 DB 66h, 0b8h ; mov eax, imm32
.SavedCr4: DD 0 .SavedCr4: DD 0
mov cr4, rax mov cr4, eax
; o32 lgdt [cs:bx + (SavedGdt - .Base)]
; rdi in the instruction below is indeed bx in 16-bit code
;
DB 66h, 2eh ; 2eh is "cs:" segment override
lgdt [rdi + (SavedGdt - .Base)]
DB 66h
mov ecx, 0c0000080h mov ecx, 0c0000080h
rdmsr rdmsr
or ah, 1 or ah, 1
wrmsr wrmsr
DB 66h, 0b8h ; mov eax, imm32 DB 66h, 0b8h ; mov eax, imm32
.SavedCr0: DD 0 .SavedCr0: DD 0
mov cr0, rax mov cr0, eax
DB 66h, 0eah ; jmp far cs:.64Bit DB 66h, 0eah ; jmp far cs:.64Bit
.64Eip: DD 0 .64Eip: DD 0
.SavedCs: DW 0 .SavedCs: DW 0
.64BitCode: .64BitCode:
db 090h BITS 64
nop
db 048h, 0bch ; mov rsp, imm64 db 048h, 0bch ; mov rsp, imm64
.SavedSp: DQ 0 ; restore stack .SavedSp: DQ 0 ; restore stack
nop nop
@ -169,40 +157,40 @@ _16Idtr:
; It will be shadowed to somewhere in memory below 1MB. ; It will be shadowed to somewhere in memory below 1MB.
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
_ToUserCode: _ToUserCode:
mov ss, edx ; set new segment selectors BITS 16
mov ds, edx mov ss, dx ; set new segment selectors
mov es, edx mov ds, dx
mov fs, edx mov es, dx
mov gs, edx mov fs, dx
DB 66h mov gs, dx
mov ecx, 0c0000080h mov ecx, 0c0000080h
mov cr0, rax ; real mode starts at next instruction mov cr0, eax ; real mode starts at next instruction
rdmsr rdmsr
and ah, ~1 and ah, ~1
wrmsr wrmsr
mov cr4, rbp mov cr4, ebp
mov ss, esi ; set up 16-bit stack segment mov ss, si ; set up 16-bit stack segment
mov sp, bx ; set up 16-bit stack pointer mov esp, ebx ; set up 16-bit stack pointer
DB 66h ; make the following call 32-bit call dword .Base ; push eip
call .Base ; push eip
.Base: .Base:
pop bp ; ebp <- address of .Base pop ebp ; ebp <- address of .Base
push qword [esp + IA32_REGS.size + 2] push word [dword esp + IA32_REGS.size + 2]
lea eax, [rsi + (.RealMode - .Base)] ; rsi is "bp" in 16-bit code lea ax, [bp + (.RealMode - .Base)]
push rax push ax
retf ; execution begins at next instruction retf ; execution begins at next instruction
.RealMode: .RealMode:
DB 66h, 2eh ; CS and operand size override
lidt [rsi + (_16Idtr - .Base)] o32 lidt [cs:bp + (_16Idtr - .Base)]
DB 66h, 61h ; popad
DB 1fh ; pop ds popad
DB 07h ; pop es pop ds
pop es
pop fs pop fs
pop gs pop gs
popfw ; popfd popfd
lea sp, [esp + 4] ; skip high order 32 bits of EFlags lea esp, [esp + 4] ; skip high order 32 bits of EFlags
DB 66h ; make the following retf 32-bit
retf ; transfer control to user code o32 retf ; transfer control to user code
ALIGN 8 ALIGN 8
@ -245,6 +233,7 @@ GDT_SIZE equ $ - _NullSeg
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
global ASM_PFX(InternalAsmThunk16) global ASM_PFX(InternalAsmThunk16)
ASM_PFX(InternalAsmThunk16): ASM_PFX(InternalAsmThunk16):
BITS 64
push rbp push rbp
push rbx push rbx
push rsi push rsi
@ -300,7 +289,7 @@ ASM_PFX(InternalAsmThunk16):
mov [rcx], ebp ; save CR4 in _BackFromUserCode.SavedCr4 mov [rcx], ebp ; save CR4 in _BackFromUserCode.SavedCr4
and ebp, ~30h ; clear PAE, PSE bits and ebp, ~30h ; clear PAE, PSE bits
mov esi, r8d ; esi <- 16-bit stack segment mov esi, r8d ; esi <- 16-bit stack segment
DB 6ah, DATA32 ; push DATA32 push DATA32
pop rdx ; rdx <- 32-bit data segment selector pop rdx ; rdx <- 32-bit data segment selector
lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4)] lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4)]
mov ss, edx mov ss, edx