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 // Byte packed structure for an 16-bit real mode thunks
// //
typedef struct { typedef struct {
IA32_REGISTER_SET RealModeState; IA32_REGISTER_SET *RealModeState;
VOID *RealModeBuffer; VOID *RealModeBuffer;
UINTN RealModeBufferSize; UINT32 RealModeBufferSize;
VOID *CallStack; UINT32 ThunkAttributes;
UINTN CallStackSize;
VOID *RealModeCode;
UINTN RealModeCodeSize;
} THUNK_CONTEXT; } 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. Retrieves CPUID information.
@ -4798,6 +4799,34 @@ AsmDisablePaging64 (
// 16-bit thunking services // 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(). 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/InterlockedCompareExchange32.s</Filename>
<Filename>Ipf/InterlockedCompareExchange64.s</Filename> <Filename>Ipf/InterlockedCompareExchange64.s</Filename>
<Filename>Ipf/Synchronization.c</Filename> <Filename>Ipf/Synchronization.c</Filename>
<Filename>Ipf/CpuPause.s</Filename>
</Arch> </Arch>
<Arch ArchType="EBC"> <Arch ArchType="EBC">
<Filename>Math64.c</Filename> <Filename>Math64.c</Filename>
@ -279,9 +280,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
<Filename>SetJumpLongJump.c</Filename> <Filename>SetJumpLongJump.c</Filename>
<Filename>Unaligned.c</Filename> <Filename>Unaligned.c</Filename>
<Filename>Ebc/CpuBreakpoint.c</Filename> <Filename>Ebc/CpuBreakpoint.c</Filename>
<Filename>Ebc/Synchronization.c</Filename>
</Arch> </Arch>
</SourceFiles> </SourceFiles>
<Includes> <Includes>
<PackageName>MdePkg</PackageName> <PackageName>MdePkg</PackageName>
</Includes> </Includes>
<PCDs> <PCDs>

View File

@ -98,3 +98,67 @@ GetInterruptState (
ASSERT (FALSE); ASSERT (FALSE);
return 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 .686p
.model flat,C .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 THUNK_ATTRIBUTE_BIG_REAL_MODE EQU 1
_16BitCsSel LABEL QWORD THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 EQU 2
DW -1 THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL EQU 4
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
IA32_REGS STRUC 4t IA32_REGS STRUC 4t
_EDI DD ? _EDI DD ?
@ -70,93 +52,165 @@ _CS DW ?
_SS DW ? _SS DW ?
IA32_REGS ENDS IA32_REGS ENDS
InternalAsmThunk16 PROC USES ebp ebx esi edi ds es fs gs .const
mov esi, [esp + 36] ; esi <- RegSet
push sizeof (IA32_REGS) m16Size DW offset InternalAsmThunk16 - offset m16Start
pop ecx mThunk16Attr DW offset _ThunkAttr - offset m16Start
movzx edx, (IA32_REGS ptr [esi])._SS m16Gdt DW offset _NullSegDesc - offset m16Start
mov edi, (IA32_REGS ptr [esi])._ESP m16GdtrBase DW offset _16GdtrBase - offset m16Start
sub edi, ecx ; reserve space on realmode stack mTransition DW offset _EntryPoint - offset m16Start
push edi ; save stack offset
imul eax, edx, 16 ; eax <- edx * 16 .code
add edi, eax ; edi <- linear address of 16-bit stack
rep movsb ; copy RegSet m16Start LABEL BYTE
mov esi, edx ; esi <- 16-bit stack segment
pop ebx ; ebx <- 16-bit stack offset SavedGdt LABEL FWORD
mov edi, [esp + 40] ; edi <- realmode patch DW ?
push cs ; save CS segment selector DD ?
push offset @BackToThunk ; offset to back from real mode
mov eax, offset @16Return _BackFromUserCode PROC
stosd push ss
xor eax, eax push cs
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
DB 66h DB 66h
retf ; transfer control to 16-bit code call @Base ; push eip
@16Return: @Base:
pushf ; pushfd actually pushf ; pushfd actually
cli ; disable interrupts
push gs push gs
push fs push fs
push es push es
push ds push ds
pushaw ; pushad actually pushaw ; pushad actually
DB 67h, 66h DB 66h, 0bah ; mov edx, imm32
lds esi, fword ptr (IA32_REGS ptr [esp])._EIP _ThunkAttr DD ?
DB 67h, 66h test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
mov eax, [esi + 12] jz @1
mov cr4, eax ; restore CR4 mov eax, 15cd2401h ; mov ax, 2401h & int 15h
DB 67h, 66h cli ; disable interrupts
lgdt fword ptr [esi + 16] jnc @2
DB 67h, 66h @1:
mov eax, [esi + 8] test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
mov cr0, eax ; restore CR0 jz @2
xor ax, ax ; xor eax, eax actually in al, 92h
or al, 2
out 92h, al ; deactivate A20M#
@2:
mov eax, ss mov eax, ss
DB 67h DB 67h
mov dword ptr (IA32_REGS ptr [esp])._SS, eax lea bp, [esp + sizeof (IA32_REGS)]
shl ax, 4 ; shl eax, 4 actually mov word ptr (IA32_REGS ptr [esi - sizeof (IA32_REGS)])._ESP, bp
add ax, sp ; add eax, esp actually mov ebx, (IA32_REGS ptr [esi - sizeof (IA32_REGS)])._EIP
add sp, sizeof (IA32_REGS) ; add esp, sizeof (IA32_REGS) shl ax, 4 ; shl eax, 4
DB 67h, 66h add bp, ax ; add ebp, eax
mov dword ptr (IA32_REGS ptr [esp - sizeof (IA32_REGS)])._ESP, esp DB 66h, 0b8h ; mov eax, imm32
DB 67h, 66h SavedCr4 DD ?
lss esp, fword ptr [esi] ; restore protected mode stack mov cr4, eax
DB 66h DB 66h
retf ; go back to protected mode lgdt fword ptr cs:[edi + (offset SavedGdt - offset @Base)]
@BackToThunk: 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 lidt fword ptr [esp + 36] ; restore protected mode IDTR
lea eax, [ebp - sizeof (IA32_REGS)]
ret ret
InternalAsmThunk16 ENDP InternalAsmThunk16 ENDP

View File

@ -99,3 +99,21 @@ GetInterruptState (
{ {
return 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 ();
}

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 THUNK_ATTRIBUTE_BIG_REAL_MODE EQU 1
_16CsSegSel LABEL QWORD THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 EQU 2
DW -1 THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL EQU 4
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
IA32_REGS STRUC 4t IA32_REGS STRUC 4t
_EDI DD ? _EDI DD ?
@ -61,128 +43,192 @@ _DS DW ?
_ES DW ? _ES DW ?
_FS DW ? _FS DW ?
_GS DW ? _GS DW ?
_RFLAGS DQ ? _EFLAGS DQ ?
_EIP DD ? _EIP DD ?
_CS DW ? _CS DW ?
_SS DW ? _SS DW ?
IA32_REGS ENDS IA32_REGS ENDS
InternalAsmThunk16 PROC USES rbp rbx rsi rdi r12 r13 r14 r15 .const
mov eax, ds
push rax m16Size DW offset InternalAsmThunk16 - offset m16Start
mov eax, es mThunk16Attr DW offset _ThunkAttr - offset m16Start
push rax m16Gdt DW offset _NullSegDesc - offset m16Start
push fs m16GdtrBase DW offset _16GdtrBase - offset m16Start
push gs mTransition DW offset _EntryPoint - offset m16Start
mov rsi, rcx ; rsi <- RegSet
push sizeof (IA32_REGS) .code
pop rcx
movzx r8, (IA32_REGS ptr [rsi])._SS m16Start LABEL BYTE
xor rdi, rdi
mov edi, (IA32_REGS ptr [rsi])._ESP SavedGdt LABEL FWORD
sub rdi, rcx ; reserve space on realmode stack DW ?
push rdi ; save stack offset DQ ?
imul rax, r8, 16
add rdi, rax ; rdi <- linear address of 16-bit stack _BackFromUserCode PROC
rep movsb ; copy RegSet DB 16h ; push ss
mov rsi, r8 ; si <- 16-bit stack segment DB 0eh ; push cs
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
DB 66h DB 66h
mov ecx, 0c0000080h call @Base ; push eip
rdmsr @Base:
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
DB 66h DB 66h
retf ; transfer control to 16-bit code push 0 ; reserved high order 32 bits of EFlags
@16Return:
DB 66h
push 0 ; high order 32 bits of rflags
pushf ; pushfd actually pushf ; pushfd actually
cli ; disable interrupts
push gs push gs
push fs push fs
DB 6 ; push es DB 6 ; push es
DB 1eh ; push ds DB 1eh ; push ds
DB 66h, 60h ; pushad DB 66h, 60h ; pushad
DB 67h, 66h, 0c5h, 74h, 24h, 30h ; lds esi, [esp + 12*4] DB 66h, 0bah ; mov edx, imm32
DB 66h _ThunkAttr DD ?
mov eax, [esi + 12] test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
mov cr4, rax ; restore CR4 jz @1
DB 66h mov eax, 15cd2401h ; mov ax, 2401h & int 15h
lgdt fword ptr [esi + 16] 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 DB 66h
mov ecx, 0c0000080h mov ecx, 0c0000080h
rdmsr rdmsr
or ah, 1 ; set LME or ah, 1
wrmsr 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 DB 66h
mov eax, [esi + 8] retf ; return to protected mode
mov cr0, rax ; restore CR0 _BackFromUserCode ENDP
xor ax, ax ; xor eax, eax actually
mov eax, ss _EntryPoint DD offset _ToUserCode - offset m16Start
mov dword ptr (IA32_REGS ptr [esp])._SS, eax DW 8h
shl ax, 4 ; shl eax, 4 actually _16Gdtr LABEL FWORD
add ax, sp ; add eax, esp actually DW offset GdtEnd - offset _NullSegDesc - 1
add sp, sizeof (IA32_REGS) ; add esp, sizeof (IA32_REGS) _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 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 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 DB 66h
retf ; go back to protected mode retf ; transfer control to user code
@BackToThunk: _ToUserCode ENDP
lidt fword ptr [rsp + 68h] ; restore protected mode IDTR
shl rax, 32 _NullSegDesc DQ 0
shr rax, 32 ; clear high order 32 bits of RAX _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 gs
pop fs pop fs
pop rcx mov es, r11d
mov es, ecx mov ds, r10d
pop rcx
mov ds, ecx
ret ret
InternalAsmThunk16 ENDP 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. 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. 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 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 @return The pointer to a IA32_REGISTER_SET structure containing the updated
register values. register values.
@ -31,9 +60,44 @@
IA32_REGISTER_SET * IA32_REGISTER_SET *
InternalAsmThunk16 ( InternalAsmThunk16 (
IN IA32_REGISTER_SET *RegisterSet, 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(). Prepares all structures a code required to use AsmThunk16().
@ -51,7 +115,64 @@ AsmPrepareThunk16 (
OUT THUNK_CONTEXT *ThunkContext OUT THUNK_CONTEXT *ThunkContext
) )
{ {
IA32_SEGMENT_DESCRIPTOR *RealModeGdt;
ASSERT (ThunkContext != NULL); 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 IN OUT THUNK_CONTEXT *ThunkContext
) )
{ {
UINT16 *Patch; IA32_REGISTER_SET *UpdatedRegs;
ASSERT (ThunkContext != NULL); 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*)( UpdatedRegs = InternalAsmThunk16 (
(UINTN)ThunkContext->RealModeCode + ThunkContext->RealModeState,
ThunkContext->RealModeCodeSize ThunkContext->RealModeBuffer
); );
// CopyMem (ThunkContext->RealModeState, UpdatedRegs, sizeof (*UpdatedRegs));
// 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)
);
} }
/** /**