X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=MdePkg%2FLibrary%2FBaseLib%2Fx86Thunk.c;h=7045924014e614d2f2c854ad899fbdaf1853a0e2;hp=8cb5f4f8bdfce04b3dcecd41f0c2dbfb506a5b00;hb=97d92bdaf05d9307d494444cead97c41272eca62;hpb=7c28d0e095a592063410d2c5f7d8ff040cf89d10 diff --git a/MdePkg/Library/BaseLib/x86Thunk.c b/MdePkg/Library/BaseLib/x86Thunk.c index 8cb5f4f8bd..7045924014 100644 --- a/MdePkg/Library/BaseLib/x86Thunk.c +++ b/MdePkg/Library/BaseLib/x86Thunk.c @@ -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)); } /**