Updated BaseLib for THUNK functions and some CPU functions

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@158 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
bxing 2006-05-15 11:14:20 +00:00
parent 7c28d0e095
commit 97d92bdaf0
9 changed files with 664 additions and 256 deletions

View File

@ -2969,15 +2969,16 @@ typedef union {
// Byte packed structure for an 16-bit real mode thunks
//
typedef struct {
IA32_REGISTER_SET RealModeState;
IA32_REGISTER_SET *RealModeState;
VOID *RealModeBuffer;
UINTN RealModeBufferSize;
VOID *CallStack;
UINTN CallStackSize;
VOID *RealModeCode;
UINTN RealModeCodeSize;
UINT32 RealModeBufferSize;
UINT32 ThunkAttributes;
} THUNK_CONTEXT;
#define THUNK_ATTRIBUTE_BIG_REAL_MODE 0x00000001
#define THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 0x00000002
#define THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL 0x00000004
/**
Retrieves CPUID information.
@ -4798,6 +4799,34 @@ AsmDisablePaging64 (
// 16-bit thunking services
//
/**
Retrieves the properties for 16-bit thunk functions.
Computes the size of the buffer and stack below 1MB required to use the
AsmPrepareThunk16(), AsmThunk16() and AsmPrepareAndThunk16() functions. This
buffer size is returned in RealModeBufferSize, and the stack size is returned
in ExtraStackSize. If parameters are passed to the 16-bit real mode code,
then the actual minimum stack size is ExtraStackSize plus the maximum number
of bytes that need to be passed to the 16-bit real mode code.
If RealModeBufferSize is NULL, then ASSERT().
If ExtraStackSize is NULL, then ASSERT().
@param RealModeBufferSize A pointer to the size of the buffer below 1MB
required to use the 16-bit thunk functions.
@param ExtraStackSize A pointer to the extra size of stack below 1MB
that the 16-bit thunk functions require for
temporary storage in the transition to and from
16-bit real mode.
**/
VOID
EFIAPI
AsmGetThunk16Properties (
OUT UINT32 *RealModeBufferSize,
OUT UINT32 *ExtraStackSize
);
/**
Prepares all structures a code required to use AsmThunk16().

View File

@ -272,6 +272,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
<Filename>Ipf/InterlockedCompareExchange32.s</Filename>
<Filename>Ipf/InterlockedCompareExchange64.s</Filename>
<Filename>Ipf/Synchronization.c</Filename>
<Filename>Ipf/CpuPause.s</Filename>
</Arch>
<Arch ArchType="EBC">
<Filename>Math64.c</Filename>
@ -279,9 +280,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
<Filename>SetJumpLongJump.c</Filename>
<Filename>Unaligned.c</Filename>
<Filename>Ebc/CpuBreakpoint.c</Filename>
<Filename>Ebc/Synchronization.c</Filename>
</Arch>
</SourceFiles>
<Includes>
<Includes>
<PackageName>MdePkg</PackageName>
</Includes>
<PCDs>

View File

@ -98,3 +98,67 @@ GetInterruptState (
ASSERT (FALSE);
return FALSE;
}
/**
Enables CPU interrupts for the smallest window required to capture any
pending interrupts.
Enables CPU interrupts for the smallest window required to capture any
pending interrupts.
**/
VOID
EFIAPI
EnableDisableInterrupts (
VOID
)
{
EnableInterrupts ();
DisableInterrupts ();
}
/**
Requests CPU to pause for a short period of time.
Requests CPU to pause for a short period of time. Typically used in MP
systems to prevent memory starvation while waiting for a spin lock.
**/
VOID
EFIAPI
CpuPause (
VOID
)
{
}
/**
Flushes all the Translation Lookaside Buffers(TLB) entries in a CPU.
Flushes all the Translation Lookaside Buffers(TLB) entries in a CPU.
**/
VOID
EFIAPI
CpuFlushTlb (
VOID
)
{
ASSERT (FALSE);
}
/**
Places the CPU in a sleep state until an interrupt is received.
Places the CPU in a sleep state until an interrupt is received. If interrupts
are disabled prior to calling this function, then the CPU will be placed in a
sleep state indefinitely.
**/
VOID
EFIAPI
CpuSleep (
VOID
)
{
}

View File

@ -0,0 +1,57 @@
/** @file
Implementation of synchronization functions on EBC.
Copyright (c) 2006, Intel Corporation<BR>
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
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name: Synchronization.c
**/
UINT32
EFIAPI
InternalSyncCompareExchange32 (
IN volatile UINT32 *Value,
IN UINT32 CompareValue,
IN UINT32 ExchangeValue
)
{
return *Value != CompareValue ? *Value :
((*Value = ExchangeValue), CompareValue);
}
UINT64
EFIAPI
InternalSyncCompareExchange64 (
IN volatile UINT64 *Value,
IN UINT64 CompareValue,
IN UINT64 ExchangeValue
)
{
return *Value != CompareValue ? *Value :
((*Value = ExchangeValue), CompareValue);
}
UINT32
EFIAPI
InternalSyncIncrement (
IN volatile UINT32 *Value
)
{
return ++*Value;
}
UINT32
EFIAPI
InternalSyncDecrement (
IN volatile UINT32 *Value
)
{
return --*Value;
}

View File

@ -22,34 +22,16 @@
.686p
.model flat,C
.data
EXTERNDEF C m16Start:BYTE
EXTERNDEF C m16Size:WORD
EXTERNDEF C mThunk16Attr:WORD
EXTERNDEF C m16Gdt:WORD
EXTERNDEF C m16GdtrBase:WORD
EXTERNDEF C mTransition:WORD
NullSegSel DQ 0
_16BitCsSel LABEL QWORD
DW -1
DW 0
DB 0
DB 9bh
DB 8fh ; 16-bit segment
DB 0
_16BitDsSel LABEL QWORD
DW -1
DW 0
DB 0
DB 93h
DB 8fh ; 16-bit segment
DB 0
GdtEnd LABEL QWORD
.const
_16Gdtr LABEL FWORD
DW offset GdtEnd - offset NullSegSel - 1
DD offset NullSegSel
_16Idtr FWORD (1 SHL 10) - 1
.code
THUNK_ATTRIBUTE_BIG_REAL_MODE EQU 1
THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 EQU 2
THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL EQU 4
IA32_REGS STRUC 4t
_EDI DD ?
@ -70,93 +52,165 @@ _CS DW ?
_SS DW ?
IA32_REGS ENDS
InternalAsmThunk16 PROC USES ebp ebx esi edi ds es fs gs
mov esi, [esp + 36] ; esi <- RegSet
push sizeof (IA32_REGS)
pop ecx
movzx edx, (IA32_REGS ptr [esi])._SS
mov edi, (IA32_REGS ptr [esi])._ESP
sub edi, ecx ; reserve space on realmode stack
push edi ; save stack offset
imul eax, edx, 16 ; eax <- edx * 16
add edi, eax ; edi <- linear address of 16-bit stack
rep movsb ; copy RegSet
mov esi, edx ; esi <- 16-bit stack segment
pop ebx ; ebx <- 16-bit stack offset
mov edi, [esp + 40] ; edi <- realmode patch
push cs ; save CS segment selector
push offset @BackToThunk ; offset to back from real mode
mov eax, offset @16Return
stosd
xor eax, eax
stosw ; set CS base to 0
mov eax, esp
stosd
mov eax, ss
stosd
mov eax, cr0
mov ecx, eax ; ecx <- CR0
and ecx, 7ffffffeh ; clear PE, PG bits
stosd
mov eax, cr4
mov ebp, eax
and ebp, 300h ; clear all but PCE and OSFXSR bits
stosd
sidt fword ptr [esp + 44] ; use parameter space to save IDTR
sgdt fword ptr [edi]
lidt _16Idtr
push 10h
pop eax
push 8
push offset @16Start
lgdt _16Gdtr
retf
@16Start: ; 16-bit starts here
mov ss, eax ; set SS to be a 16-bit segment
mov cr0, ecx
mov cr4, ebp
mov ss, esi ; set up 16-bit stack
mov sp, bx ; mov esp, ebx actually
popaw ; popad actually
pop ds
pop es
pop fs
pop gs
add sp, 4 ; skip _EFLAGS
.const
m16Size DW offset InternalAsmThunk16 - offset m16Start
mThunk16Attr DW offset _ThunkAttr - offset m16Start
m16Gdt DW offset _NullSegDesc - offset m16Start
m16GdtrBase DW offset _16GdtrBase - offset m16Start
mTransition DW offset _EntryPoint - offset m16Start
.code
m16Start LABEL BYTE
SavedGdt LABEL FWORD
DW ?
DD ?
_BackFromUserCode PROC
push ss
push cs
DB 66h
retf ; transfer control to 16-bit code
@16Return:
call @Base ; push eip
@Base:
pushf ; pushfd actually
cli ; disable interrupts
push gs
push fs
push es
push ds
pushaw ; pushad actually
DB 67h, 66h
lds esi, fword ptr (IA32_REGS ptr [esp])._EIP
DB 67h, 66h
mov eax, [esi + 12]
mov cr4, eax ; restore CR4
DB 67h, 66h
lgdt fword ptr [esi + 16]
DB 67h, 66h
mov eax, [esi + 8]
mov cr0, eax ; restore CR0
xor ax, ax ; xor eax, eax actually
DB 66h, 0bah ; mov edx, imm32
_ThunkAttr DD ?
test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
jz @1
mov eax, 15cd2401h ; mov ax, 2401h & int 15h
cli ; disable interrupts
jnc @2
@1:
test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
jz @2
in al, 92h
or al, 2
out 92h, al ; deactivate A20M#
@2:
mov eax, ss
DB 67h
mov dword ptr (IA32_REGS ptr [esp])._SS, eax
shl ax, 4 ; shl eax, 4 actually
add ax, sp ; add eax, esp actually
add sp, sizeof (IA32_REGS) ; add esp, sizeof (IA32_REGS)
DB 67h, 66h
mov dword ptr (IA32_REGS ptr [esp - sizeof (IA32_REGS)])._ESP, esp
DB 67h, 66h
lss esp, fword ptr [esi] ; restore protected mode stack
lea bp, [esp + sizeof (IA32_REGS)]
mov word ptr (IA32_REGS ptr [esi - sizeof (IA32_REGS)])._ESP, bp
mov ebx, (IA32_REGS ptr [esi - sizeof (IA32_REGS)])._EIP
shl ax, 4 ; shl eax, 4
add bp, ax ; add ebp, eax
DB 66h, 0b8h ; mov eax, imm32
SavedCr4 DD ?
mov cr4, eax
DB 66h
retf ; go back to protected mode
@BackToThunk:
lgdt fword ptr cs:[edi + (offset SavedGdt - offset @Base)]
DB 66h, 0b8h ; mov eax, imm32
SavedCr0 DD ?
mov cr0, eax
DB 0b8h ; mov ax, imm16
SavedSs DW ?
mov ss, eax
DB 66h, 0bch ; mov esp, imm32
SavedEsp DD ?
DB 66h
retf ; return to protected mode
_BackFromUserCode ENDP
_EntryPoint DD offset _ToUserCode - offset m16Start
DW 8h
_16Idtr FWORD (1 SHL 10) - 1
_16Gdtr LABEL FWORD
DW offset GdtEnd - offset _NullSegDesc - 1
_16GdtrBase DD offset _NullSegDesc
_ToUserCode PROC
mov edx, ss
mov ss, ecx ; set new segment selectors
mov ds, ecx
mov es, ecx
mov fs, ecx
mov gs, ecx
mov cr0, eax
mov cr4, ebp ; real mode starts at next instruction
mov ss, esi ; set up 16-bit stack segment
xchg sp, bx ; set up 16-bit stack pointer
DB 66h
call @Base ; push eip
@Base:
pop bp ; ebp <- offset @Base
mov cs:[esi + (offset SavedSs - offset @Base)], edx
mov cs:[esi + (offset SavedEsp - offset @Base)], bx
DB 66h
lidt fword ptr cs:[esi + (offset _16Idtr - offset @Base)]
popaw ; popad actually
pop ds
pop es
pop fs
pop gs
popf ; popfd
DB 66h
retf ; transfer control to user code
_ToUserCode ENDP
_NullSegDesc DQ 0
_16CsDesc LABEL QWORD
DW -1
DW 0
DB 0
DB 9bh
DB 8fh ; 16-bit segment, 4GB limit
DB 0
_16DsDesc LABEL QWORD
DW -1
DW 0
DB 0
DB 93h
DB 8fh ; 16-bit segment, 4GB limit
DB 0
GdtEnd LABEL QWORD
;
; @param RegSet Pointer to a IA32_DWORD_REGS structure
; @param Transition Pointer to the transition code
; @return The address of the 16-bit stack after returning from user code
;
InternalAsmThunk16 PROC USES ebp ebx esi edi ds es fs gs
mov esi, [esp + 36] ; esi <- RegSet
movzx edx, (IA32_REGS ptr [esi])._SS
mov edi, (IA32_REGS ptr [esi])._ESP
add edi, - (sizeof (IA32_REGS) + 4) ; reserve stack space
mov ebx, edi ; ebx <- stack offset
imul eax, edx, 16 ; eax <- edx * 16
push sizeof (IA32_REGS) / 4
add edi, eax ; edi <- linear address of 16-bit stack
pop ecx
rep movsd ; copy RegSet
mov eax, [esp + 40] ; eax <- address of transition code
mov esi, edx ; esi <- 16-bit stack segment
lea edx, [eax + (offset SavedCr0 - offset m16Start)]
mov ecx, eax
and ecx, 0fh
shl eax, 12
lea ecx, [ecx + (offset _BackFromUserCode - offset m16Start)]
mov ax, cx
stosd ; [edi] <- return address of user code
sgdt fword ptr [edx + (offset SavedGdt - offset SavedCr0)]
sidt fword ptr [esp + 36] ; save IDT stack in argument space
mov eax, cr0
mov [edx], eax ; save CR0 in SavedCr0
and eax, 7ffffffeh ; clear PE, PG bits
mov ebp, cr4
mov [edx + (offset SavedCr4 - offset SavedCr0)], ebp
and ebp, 300h ; clear all but PCE and OSFXSR bits
push 10h
pop ecx ; ecx <- selector for data segments
lgdt fword ptr [edx + (offset _16Gdtr - offset SavedCr0)]
call fword ptr [edx + (offset _EntryPoint - offset SavedCr0)]
lidt fword ptr [esp + 36] ; restore protected mode IDTR
lea eax, [ebp - sizeof (IA32_REGS)]
ret
InternalAsmThunk16 ENDP

View File

@ -99,3 +99,21 @@ GetInterruptState (
{
return FALSE;
}
/**
Enables CPU interrupts for the smallest window required to capture any
pending interrupts.
Enables CPU interrupts for the smallest window required to capture any
pending interrupts.
**/
VOID
EFIAPI
EnableDisableInterrupts (
VOID
)
{
EnableInterrupts ();
DisableInterrupts ();
}

View File

@ -0,0 +1,25 @@
/// @file
/// CpuPause() function for Itanium-based architecture.
///
/// Copyright (c) 2006, 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
/// http://opensource.org/licenses/bsd-license.php
///
/// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
/// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
///
/// Module Name: CpuPause.s
///
///
.auto
.text
.proc CpuPause
.type CpuPause, @function
CpuPause::
hint @pause
br.ret.sptk.many b0
.endp

View File

@ -19,34 +19,16 @@
;
;------------------------------------------------------------------------------
.data
EXTERNDEF m16Start:BYTE
EXTERNDEF m16Size:WORD
EXTERNDEF mThunk16Attr:WORD
EXTERNDEF m16Gdt:WORD
EXTERNDEF m16GdtrBase:WORD
EXTERNDEF mTransition:WORD
NullSegSel DQ 0
_16CsSegSel LABEL QWORD
DW -1
DW 0
DB 0
DB 9bh
DB 8fh ; 16-bit segment
DB 0
_16BitDsSel LABEL QWORD
DW -1
DW 0
DB 0
DB 93h
DB 8fh ; 16-bit segment
DB 0
GdtEnd LABEL QWORD
.const
_16Gdtr LABEL FWORD
DW offset GdtEnd - offset NullSegSel - 1
DQ offset NullSegSel
_16Idtr FWORD (1 SHL 10) - 1
.code
THUNK_ATTRIBUTE_BIG_REAL_MODE EQU 1
THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 EQU 2
THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL EQU 4
IA32_REGS STRUC 4t
_EDI DD ?
@ -61,128 +43,192 @@ _DS DW ?
_ES DW ?
_FS DW ?
_GS DW ?
_RFLAGS DQ ?
_EFLAGS DQ ?
_EIP DD ?
_CS DW ?
_SS DW ?
IA32_REGS ENDS
InternalAsmThunk16 PROC USES rbp rbx rsi rdi r12 r13 r14 r15
mov eax, ds
push rax
mov eax, es
push rax
push fs
push gs
mov rsi, rcx ; rsi <- RegSet
push sizeof (IA32_REGS)
pop rcx
movzx r8, (IA32_REGS ptr [rsi])._SS
xor rdi, rdi
mov edi, (IA32_REGS ptr [rsi])._ESP
sub rdi, rcx ; reserve space on realmode stack
push rdi ; save stack offset
imul rax, r8, 16
add rdi, rax ; rdi <- linear address of 16-bit stack
rep movsb ; copy RegSet
mov rsi, r8 ; si <- 16-bit stack segment
pop rbx ; rbx <- 16-bit stack offset
mov rdi, rdx ; rdi <- realmode patch
lea eax, @BackToThunk ; rax <- address to back from real mode
push rax ; use in a far return
mov eax, cs
mov [rsp + 4], eax ; save CS
lea eax, @16Return ; thus @Return must < 4GB
stosd ; set ret address offset
xor eax, eax
stosw ; set ret CS base to 0
mov eax, esp
stosd ; rsp must < 4GB
mov eax, ss
stosd
mov rax, cr0
mov ecx, eax ; ecx <- CR0
and ecx, 7ffffffeh ; clear PE, PG bits
stosd
mov rax, cr4
mov ebp, eax
and ebp, 300h ; clear all but PCE and OSFXSR bits
stosd
sidt fword ptr [rsp + 70h] ; use parameter space to save IDTR
sgdt fword ptr [rdi]
lea edi, _16Idtr
lea eax, @16Start ; rax <- seg:offset of @16Start
push rax
mov dword ptr [rsp + 4], 8
push 10h
pop rax ; rax <- 10h as dataseg selector
lgdt _16Gdtr
retf
@16Start: ; 16-bit starts here
mov ss, eax ; set SS to be a 16-bit segment
mov cr0, rcx ; disable protected mode
mov cr4, rbp
.const
m16Size DW offset InternalAsmThunk16 - offset m16Start
mThunk16Attr DW offset _ThunkAttr - offset m16Start
m16Gdt DW offset _NullSegDesc - offset m16Start
m16GdtrBase DW offset _16GdtrBase - offset m16Start
mTransition DW offset _EntryPoint - offset m16Start
.code
m16Start LABEL BYTE
SavedGdt LABEL FWORD
DW ?
DQ ?
_BackFromUserCode PROC
DB 16h ; push ss
DB 0eh ; push cs
DB 66h
mov ecx, 0c0000080h
rdmsr
and ah, NOT 1 ; clear LME
wrmsr
mov ss, esi ; set up 16-bit stack
mov sp, bx ; mov esp, ebx actually
lidt fword ptr [edi]
DB 66h, 61h ; popad
DB 1fh ; pop ds
DB 7 ; pop es
pop fs
pop gs
add sp, 8 ; skip _RFLAGS
call @Base ; push eip
@Base:
DB 66h
retf ; transfer control to 16-bit code
@16Return:
DB 66h
push 0 ; high order 32 bits of rflags
push 0 ; reserved high order 32 bits of EFlags
pushf ; pushfd actually
cli ; disable interrupts
push gs
push fs
DB 6 ; push es
DB 1eh ; push ds
DB 66h, 60h ; pushad
DB 67h, 66h, 0c5h, 74h, 24h, 30h ; lds esi, [esp + 12*4]
DB 66h
mov eax, [esi + 12]
mov cr4, rax ; restore CR4
DB 66h
lgdt fword ptr [esi + 16]
DB 66h, 0bah ; mov edx, imm32
_ThunkAttr DD ?
test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
jz @1
mov eax, 15cd2401h ; mov ax, 2401h & int 15h
cli ; disable interrupts
jnc @2
@1:
test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
jz @2
in al, 92h
or al, 2
out 92h, al ; deactivate A20M#
@2:
mov eax, ss
lea bp, [esp + sizeof (IA32_REGS)]
mov word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp
mov ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP
shl ax, 4 ; shl eax, 4
add bp, ax ; add ebp, eax
DB 66h, 0b8h ; mov eax, imm32
SavedCr4 DD ?
mov cr4, rax
DB 66h, 2eh
lgdt fword ptr [rdi + (offset SavedGdt - offset @Base)]
DB 66h
mov ecx, 0c0000080h
rdmsr
or ah, 1 ; set LME
or ah, 1
wrmsr
DB 66h, 0b8h ; mov eax, imm32
SavedCr0 DD ?
mov cr0, rax
DB 0b8h ; mov ax, imm16
SavedSs DW ?
mov ss, eax
DB 66h, 0bch ; mov esp, imm32
SavedEsp DD ?
DB 66h
mov eax, [esi + 8]
mov cr0, rax ; restore CR0
xor ax, ax ; xor eax, eax actually
mov eax, ss
mov dword ptr (IA32_REGS ptr [esp])._SS, eax
shl ax, 4 ; shl eax, 4 actually
add ax, sp ; add eax, esp actually
add sp, sizeof (IA32_REGS) ; add esp, sizeof (IA32_REGS)
retf ; return to protected mode
_BackFromUserCode ENDP
_EntryPoint DD offset _ToUserCode - offset m16Start
DW 8h
_16Gdtr LABEL FWORD
DW offset GdtEnd - offset _NullSegDesc - 1
_16GdtrBase DQ offset _NullSegDesc
_16Idtr FWORD (1 SHL 10) - 1
_ToUserCode PROC
mov edi, ss
mov ss, edx ; set new segment selectors
mov ds, edx
mov es, edx
mov fs, edx
mov gs, edx
DB 66h
mov dword ptr (IA32_REGS ptr [esp - sizeof (IA32_REGS)])._ESP, esp
mov ecx, 0c0000080h
mov cr0, rax ; real mode starts at next instruction
rdmsr
and ah, NOT 1
wrmsr
mov cr4, rbp
mov ss, esi ; set up 16-bit stack segment
xchg sp, bx ; set up 16-bit stack pointer
DB 66h
lss esp, fword ptr [esi] ; restore protected mode stack
call @Base ; push eip
@Base:
pop bp ; ebp <- offset @Base
DB 2eh ; cs:
mov [rsi + (offset SavedSs - offset @Base)], edi
DB 2eh ; cs:
mov [rsi + (offset SavedEsp - offset @Base)], bx
DB 66h, 2eh ; CS and operand size override
lidt fword ptr [rsi + (offset _16Idtr - offset @Base)]
DB 66h, 61h ; popad
DB 1fh ; pop ds
DB 07h ; pop es
pop fs
pop gs
popf ; popfd
lea sp, [esp + 4] ; skip high order 32 bits of EFlags
DB 66h
retf ; go back to protected mode
@BackToThunk:
lidt fword ptr [rsp + 68h] ; restore protected mode IDTR
shl rax, 32
shr rax, 32 ; clear high order 32 bits of RAX
retf ; transfer control to user code
_ToUserCode ENDP
_NullSegDesc DQ 0
_16CsDesc LABEL QWORD
DW -1
DW 0
DB 0
DB 9bh
DB 8fh ; 16-bit segment, 4GB limit
DB 0
_16DsDesc LABEL QWORD
DW -1
DW 0
DB 0
DB 93h
DB 8fh ; 16-bit segment, 4GB limit
DB 0
GdtEnd LABEL QWORD
;
; @param RegSet Pointer to a IA32_DWORD_REGS structure
; @param Transition Pointer to the transition code
; @return The address of the 16-bit stack after returning from user code
;
InternalAsmThunk16 PROC USES rbp rbx rsi rdi
mov r10d, ds
mov r11d, es
push fs
push gs
mov rsi, rcx
movzx r8d, (IA32_REGS ptr [rsi])._SS
mov edi, (IA32_REGS ptr [rsi])._ESP
lea rdi, [edi - (sizeof (IA32_REGS) + 4)]
imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16
mov ebx, edi ; ebx <- stack offset for 16-bit code
push sizeof (IA32_REGS) / 4
add edi, eax ; edi <- linear address of 16-bit stack
pop rcx
rep movsd ; copy RegSet
lea ecx, [rdx + (offset SavedCr4 - offset m16Start)]
mov eax, edx ; eax <- transition code address
and edx, 0fh
shl eax, 12
lea edx, [rdx + (offset _BackFromUserCode - offset m16Start)]
mov ax, dx
stosd ; [edi] <- return address of user code
sgdt fword ptr [rcx + (offset SavedGdt - offset SavedCr4)]
sidt fword ptr [rsp + 38h] ; save IDT stack in argument space
mov rax, cr0
mov [rcx + (offset SavedCr0 - offset SavedCr4)], eax
and eax, 7ffffffeh ; clear PE, PG bits
mov rbp, cr4
mov [rcx], ebp ; save CR4 in SavedCr4
and ebp, 300h ; clear all but PCE and OSFXSR bits
mov esi, r8d ; esi <- 16-bit stack segment
push 10h
pop rdx ; rdx <- selector for data segments
lgdt fword ptr [rcx + (offset _16Gdtr - offset SavedCr4)]
call fword ptr [rcx + (offset _EntryPoint - offset SavedCr4)]
lidt fword ptr [rsp + 38h] ; restore protected mode IDTR
lea eax, [rbp - sizeof (IA32_REGS)]
pop gs
pop fs
pop rcx
mov es, ecx
pop rcx
mov ds, ecx
mov es, r11d
mov ds, r10d
ret
InternalAsmThunk16 ENDP

View File

@ -14,6 +14,35 @@
**/
//
// Byte packed structure for a segment descriptor in a GDT/LDT
//
typedef union {
struct {
UINT32 LimitLow:16;
UINT32 BaseLow:16;
UINT32 BaseMid:8;
UINT32 Type:4;
UINT32 S:1;
UINT32 DPL:2;
UINT32 P:1;
UINT32 LimitHigh:4;
UINT32 AVL:1;
UINT32 L:1;
UINT32 DB:1;
UINT32 G:1;
UINT32 BaseHigh:8;
} Bits;
UINT64 Uint64;
} IA32_SEGMENT_DESCRIPTOR;
extern CONST UINT8 m16Start;
extern CONST UINT16 m16Size;
extern CONST UINT16 mThunk16Attr;
extern CONST UINT16 m16Gdt;
extern CONST UINT16 m16GdtrBase;
extern CONST UINT16 mTransition;
/**
Invokes 16-bit code in big real mode and returns the updated register set.
@ -22,7 +51,7 @@
on the real mode stack and the starting address of the save area is returned.
@param RegisterSet Values of registers before invocation of 16-bit code.
@param Patch Pointer to the area following the 16-bit code.
@param Transition Pointer to the transition code under 1MB.
@return The pointer to a IA32_REGISTER_SET structure containing the updated
register values.
@ -31,9 +60,44 @@
IA32_REGISTER_SET *
InternalAsmThunk16 (
IN IA32_REGISTER_SET *RegisterSet,
IN OUT VOID *Patch
IN OUT VOID *Transition
);
/**
Retrieves the properties for 16-bit thunk functions.
Computes the size of the buffer and stack below 1MB required to use the
AsmPrepareThunk16(), AsmThunk16() and AsmPrepareAndThunk16() functions. This
buffer size is returned in RealModeBufferSize, and the stack size is returned
in ExtraStackSize. If parameters are passed to the 16-bit real mode code,
then the actual minimum stack size is ExtraStackSize plus the maximum number
of bytes that need to be passed to the 16-bit real mode code.
If RealModeBufferSize is NULL, then ASSERT().
If ExtraStackSize is NULL, then ASSERT().
@param RealModeBufferSize A pointer to the size of the buffer below 1MB
required to use the 16-bit thunk functions.
@param ExtraStackSize A pointer to the extra size of stack below 1MB
that the 16-bit thunk functions require for
temporary storage in the transition to and from
16-bit real mode.
**/
VOID
EFIAPI
AsmGetThunk16Properties (
OUT UINT32 *RealModeBufferSize,
OUT UINT32 *ExtraStackSize
)
{
ASSERT (RealModeBufferSize != NULL);
ASSERT (ExtraStackSize != NULL);
*RealModeBufferSize = m16Size;
*ExtraStackSize = sizeof (IA32_DWORD_REGS) + 8;
}
/**
Prepares all structures a code required to use AsmThunk16().
@ -51,7 +115,64 @@ AsmPrepareThunk16 (
OUT THUNK_CONTEXT *ThunkContext
)
{
IA32_SEGMENT_DESCRIPTOR *RealModeGdt;
ASSERT (ThunkContext != NULL);
ASSERT ((UINTN)ThunkContext->RealModeBuffer < 0x100000);
ASSERT (ThunkContext->RealModeBufferSize >= m16Size);
ASSERT ((UINTN)ThunkContext->RealModeBuffer + m16Size <= 0x100000);
ASSERT (((UINTN)ThunkContext->RealModeBuffer & 0x0f) == 0);
CopyMem (ThunkContext->RealModeBuffer, &m16Start, m16Size);
//
// Point RealModeGdt to the GDT to be used in transition
//
// RealModeGdt[0]: Reserved as NULL descriptor
// RealModeGdt[1]: Code Segment
// RealModeGdt[2]: Data Segment
// RealModeGdt[3]: Call Gate
//
RealModeGdt = (IA32_SEGMENT_DESCRIPTOR*)(
(UINTN)ThunkContext->RealModeBuffer + m16Gdt);
//
// Update Code & Data Segment Descriptor
//
RealModeGdt[1].Bits.BaseLow =
(UINT32)(UINTN)ThunkContext->RealModeBuffer & ~0xf;
RealModeGdt[1].Bits.BaseMid =
(UINT32)(UINTN)ThunkContext->RealModeBuffer >> 16;
//
// Update transition code entry point offset
//
*(UINT32*)((UINTN)ThunkContext->RealModeBuffer + mTransition) +=
(UINT32)(UINTN)ThunkContext->RealModeBuffer & 0xf;
//
// Update Segment Limits for both Code and Data Segment Descriptors
//
if ((ThunkContext->ThunkAttributes & THUNK_ATTRIBUTE_BIG_REAL_MODE) == 0) {
//
// Set segment limits to 64KB
//
RealModeGdt[1].Bits.LimitHigh = 0;
RealModeGdt[1].Bits.G = 0;
RealModeGdt[2].Bits.LimitHigh = 0;
RealModeGdt[2].Bits.G = 0;
}
//
// Update GDTBASE for this thunk context
//
*(VOID**)((UINTN)ThunkContext->RealModeBuffer + m16GdtrBase) = RealModeGdt;
//
// Update Thunk Attributes
//
*(UINT32*)((UINTN)ThunkContext->RealModeBuffer + mThunk16Attr) =
ThunkContext->ThunkAttributes;
}
/**
@ -74,28 +195,20 @@ AsmThunk16 (
IN OUT THUNK_CONTEXT *ThunkContext
)
{
UINT16 *Patch;
IA32_REGISTER_SET *UpdatedRegs;
ASSERT (ThunkContext != NULL);
ASSERT ((UINTN)ThunkContext->RealModeBuffer < 0x100000);
ASSERT (ThunkContext->RealModeBufferSize >= m16Size);
ASSERT ((UINTN)ThunkContext->RealModeBuffer + m16Size <= 0x100000);
ASSERT (((UINTN)ThunkContext->RealModeBuffer & 0x0f) == 0);
Patch = (UINT16*)(
(UINTN)ThunkContext->RealModeCode +
ThunkContext->RealModeCodeSize
);
UpdatedRegs = InternalAsmThunk16 (
ThunkContext->RealModeState,
ThunkContext->RealModeBuffer
);
//
// 0x9a66 is the OpCode of far call with an operand size override.
//
*Patch = 0x9a66;
//
// CopyMem() here copies the updated register values back to RealModeState
//
CopyMem (
&ThunkContext->RealModeState,
InternalAsmThunk16 (&ThunkContext->RealModeState, Patch + 1),
sizeof (ThunkContext->RealModeState)
);
CopyMem (ThunkContext->RealModeState, UpdatedRegs, sizeof (*UpdatedRegs));
}
/**