diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c index 28e9571d1d..46d4731355 100644 --- a/MdeModulePkg/Core/Dxe/Image/Image.c +++ b/MdeModulePkg/Core/Dxe/Image/Image.c @@ -9,6 +9,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include "DxeMain.h" #include "Image.h" +#include + // // Module Globals // @@ -1599,6 +1601,7 @@ CoreStartImage ( VOID *BaseOfStack; VOID *TopOfStack; UINTN SizeOfStack; + UINT64 Msr; Handle = ImageHandle; @@ -1713,6 +1716,7 @@ CoreStartImage ( TopOfStack = (VOID *)((UINTN)BaseOfStack + SizeOfStack - CPU_STACK_ALIGNMENT); TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT); // DEBUG ((DEBUG_ERROR, "RING3_CODE64_SEL = 0x%x RING3_DATA64_SEL = 0x%x\n", (UINT16)RING3_CODE64_SEL, (UINT16)RING3_DATA64_SEL)); + // DEBUG ((DEBUG_ERROR, "Core: BootServices = %p\n", Image->Info.SystemTable->BootServices)); // // Necessary fix for ProcessLibraryConstructorList() -> DxeCcProbeLibConstructor() @@ -1723,6 +1727,19 @@ CoreStartImage ( EFI_MEMORY_XP | EFI_MEMORY_USER ); + // + // Initialize MSR_IA32_STAR and MSR_IA32_LSTAR for SYSCALL and SYSRET. + // + Msr = ((((UINT64)RING3_CODE64_SEL - 16) << 16) | (UINT64)RING0_CODE64_SEL) << 32; + AsmWriteMsr64 (MSR_IA32_STAR, Msr); + + Msr = (UINT64)(UINTN)CoreBootServices; + AsmWriteMsr64 (MSR_IA32_LSTAR, Msr); + + // protection keys + // Software can access the old stack, if necessary, by referencing the old + // stack-segment selector and stack pointer saved on the new process stack. + EnterUserImage ( (SWITCH_STACK_ENTRY_POINT)(UINTN)Image->EntryPoint, ImageHandle, diff --git a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c index b3e58595b7..7b56175268 100644 --- a/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c +++ b/MdeModulePkg/Core/DxeIplPeim/X64/VirtualMemory.c @@ -22,7 +22,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent **/ +#include #include + #include "DxeIpl.h" #include "VirtualMemory.h" @@ -705,8 +707,11 @@ CreateIdentityMappingPageTables ( IA32_CR4 Cr4; IA32_EFLAGS32 Eflags; UINT32 Ebx; + UINT32 Edx; + MSR_IA32_EFER_REGISTER MsrEfer; Ebx = 0; + Edx = 0; // // Set PageMapLevel5Entry to suppress incorrect compiler/analyzer warnings @@ -982,7 +987,11 @@ CreateIdentityMappingPageTables ( // SMEP and SMAP must be supported. // AsmCpuidEx (0x07, 0x0, NULL, &Ebx, NULL, NULL); - if (((Ebx & BIT20) != 0) && ((Ebx & BIT7) != 0)) { + // + // SYSCALL and SYSRET must be also supported. + // + AsmCpuidEx (0x80000001, 0x0, NULL, NULL, NULL, &Edx); + if (((Ebx & BIT20) != 0) && ((Ebx & BIT7) != 0) && ((Edx & BIT11) != 0)) { Cr4.UintN = AsmReadCr4 (); Cr4.Bits.SMAP = 1; Cr4.Bits.SMEP = 1; @@ -995,6 +1004,12 @@ CreateIdentityMappingPageTables ( // Eflags.Bits.IOPL = 3; AsmWriteEflags (Eflags.UintN); + // + // Enable SYSCALL and SYSRET + // + MsrEfer.Uint64 = AsmReadMsr64 (MSR_IA32_EFER); + MsrEfer.Bits.SCE = 1; + AsmWriteMsr64 (MSR_IA32_EFER, MsrEfer.Uint64); } return (UINTN)PageMap; diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h index c88e9ad498..db098ce227 100644 --- a/MdePkg/Include/Library/BaseLib.h +++ b/MdePkg/Include/Library/BaseLib.h @@ -5290,16 +5290,17 @@ typedef struct { DATA_SEGMENT_32 SysData; CODE_SEGMENT_32 SysCode; CODE_SEGMENT_32 SysCode16; - DATA_SEGMENT_32 LinearData64; CODE_SEGMENT_64 LinearCode64; + DATA_SEGMENT_32 LinearData64; SEGMENT_DESCRIPTOR Spare5; DATA_SEGMENT_32 Ring3Data64; CODE_SEGMENT_64 Ring3Code64; - // CALL_GATE_64 FromRing3ToRing0; } GDT; #pragma pack () +#define RING0_DATA64_SEL OFFSET_OF (GDT, LinearData64) +#define RING0_CODE64_SEL OFFSET_OF (GDT, LinearCode64) #define RING3_DATA64_SEL OFFSET_OF (GDT, Ring3Data64) #define RING3_CODE64_SEL OFFSET_OF (GDT, Ring3Code64) @@ -6311,6 +6312,13 @@ AsmReadEflags ( VOID ); +UINTN +EFIAPI +CoreBootServices ( + IN UINTN FunctionAddress, + ... + ); + /** Reads the current value of the Control Register 0 (CR0). diff --git a/MdePkg/Library/BaseLib/X64/SwitchStack.nasm b/MdePkg/Library/BaseLib/X64/SwitchStack.nasm index 0f8aa12014..986e5eab41 100644 --- a/MdePkg/Library/BaseLib/X64/SwitchStack.nasm +++ b/MdePkg/Library/BaseLib/X64/SwitchStack.nasm @@ -91,3 +91,49 @@ o16 mov gs, ax ; Pass control to user image retfq + +;------------------------------------------------------------------------------ +; UINTN +; EFIAPI +; CoreBootServices ( +; IN UINTN FunctionAddress, +; ... +; ); +; +; (rcx) RIP of the next instruction saved by SYSCALL in SysCall(). +; (rdx) Argument 1 of the called function. +; (r8) Argument 2 of the called function. +; (r9) Argument 3 of the called function. +; (r10) FunctionAddress. +; (r11) RFLAGS saved by SYSCALL in SysCall(). +;On stack Argument 4, 5, ... +;------------------------------------------------------------------------------ +global ASM_PFX(CoreBootServices) +ASM_PFX(CoreBootServices): + cmp r10, 0 + je readMemory + + ; Save return address and RFLAGS for SYSRET. + mov [rsp], rcx + mov [rsp + 8], r11 + + ; Replace argument according to UEFI calling convention. + mov rcx, rdx + mov rdx, r8 + mov r8, r9 + mov r9, [rsp + 8*3] + + ; Call Boot Service by FunctionAddress. + call r10 + + ; Prepare SYSRET arguments. + mov rcx, [rsp] + mov r11, [rsp + 8] + + ; SYSCALL saves RFLAGS into R11 and the RIP of the next instruction into RCX. +o64 sysret + ; SYSRET copies the value in RCX into RIP and loads RFLAGS from R11. + +readMemory: + mov rax, [rdx] +o64 sysret diff --git a/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3.h b/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3.h index eb2b5ff660..11d8819e4e 100644 --- a/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3.h +++ b/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3.h @@ -1,3 +1,18 @@ +/** @file + + Copyright (c) 2024, Mikhail Krichanov. All rights reserved. + SPDX-License-Identifier: BSD-3-Clause + +**/ + +UINTN +EFIAPI +SysCall ( + IN UINTN FunctionAddress, + ... + ); + + /** Raise the task priority level to the new level. High level is implemented by disabling processor interrupts. diff --git a/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3UefiBootServicesTableLib.c b/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3UefiBootServicesTableLib.c index 663d74f806..cb5e21107e 100644 --- a/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3UefiBootServicesTableLib.c +++ b/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3UefiBootServicesTableLib.c @@ -9,6 +9,7 @@ #include #include +#include #include "Ring3.h" @@ -66,9 +67,8 @@ EFI_BOOT_SERVICES mBootServices = { (EFI_CREATE_EVENT_EX)Ring3CreateEventEx // CreateEventEx }; -// EFI_HANDLE gImageHandle = NULL; -// EFI_SYSTEM_TABLE *gST = NULL; -EFI_BOOT_SERVICES *gBS = &mBootServices; +EFI_BOOT_SERVICES *gBS = &mBootServices; +EFI_BOOT_SERVICES *mCoreBS = NULL; /** The function constructs Ring 3 wrappers for the EFI_BOOT_SERVICES. @@ -86,23 +86,15 @@ UefiBootServicesTableLibConstructor ( IN EFI_SYSTEM_TABLE *SystemTable ) { - // - // Cache the Image Handle - // - // gImageHandle = ImageHandle; - // ASSERT (gImageHandle != NULL); - - // - // Cache pointer to the EFI System Table - // - // gST = SystemTable; - // ASSERT (gST != NULL); - // // Cache pointer to the EFI Boot Services Table // - // gBS = SystemTable->BootServices; - // ASSERT (gBS != NULL); + mCoreBS = (EFI_BOOT_SERVICES *)SysCall ( + 0, + (UINTN)SystemTable + OFFSET_OF (EFI_SYSTEM_TABLE, BootServices) + ); + ASSERT (mCoreBS != NULL); + // DEBUG ((DEBUG_ERROR, "User: BootServices = %p\n", mCoreBS)); return EFI_SUCCESS; } @@ -512,7 +504,16 @@ Ring3LocateProtocol ( OUT VOID **Interface ) { - return EFI_SUCCESS; + EFI_STATUS Status; + + Status = (EFI_STATUS)SysCall ( + (UINTN)mCoreBS + OFFSET_OF (EFI_BOOT_SERVICES, LocateProtocol), + Protocol, + Registration, + Interface + ); + + return Status; } EFI_STATUS diff --git a/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3UefiBootServicesTableLib.inf b/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3UefiBootServicesTableLib.inf index fd2b92ed50..f1128c94d3 100644 --- a/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3UefiBootServicesTableLib.inf +++ b/MdePkg/Library/Ring3UefiBootServicesTableLib/Ring3UefiBootServicesTableLib.inf @@ -26,9 +26,12 @@ Ring3.h Ring3UefiBootServicesTableLib.c +[Sources.X64] + X64/SysCall.nasm + [Packages] MdePkg/MdePkg.dec - [LibraryClasses] BaseMemoryLib + DebugLib diff --git a/MdePkg/Library/Ring3UefiBootServicesTableLib/X64/SysCall.nasm b/MdePkg/Library/Ring3UefiBootServicesTableLib/X64/SysCall.nasm new file mode 100644 index 0000000000..64670a6a25 --- /dev/null +++ b/MdePkg/Library/Ring3UefiBootServicesTableLib/X64/SysCall.nasm @@ -0,0 +1,26 @@ +;------------------------------------------------------------------------------ +; Copyright (c) 2024, Mikhail Krichanov. All rights reserved. +; SPDX-License-Identifier: BSD-3-Clause +;------------------------------------------------------------------------------ + + DEFAULT REL + SECTION .text + +;------------------------------------------------------------------------------ +; UINTN +; EFIAPI +; SysCall ( +; IN UINTN FunctionAddress, +; ... +; ); +;------------------------------------------------------------------------------ +global ASM_PFX(SysCall) +ASM_PFX(SysCall): + ; Save FunctionAddress for CoreBootServices(). + mov r10, rcx + + ; SYSCALL saves RFLAGS into R11 and the RIP of the next instruction into RCX. + syscall + ; SYSRET copies the value in RCX into RIP and loads RFLAGS from R11. + + ret diff --git a/UefiCpuPkg/Library/CpuArchLib/CpuGdt.c b/UefiCpuPkg/Library/CpuArchLib/CpuGdt.c index e8047b1207..415d4126aa 100644 --- a/UefiCpuPkg/Library/CpuArchLib/CpuGdt.c +++ b/UefiCpuPkg/Library/CpuArchLib/CpuGdt.c @@ -129,6 +129,25 @@ STATIC GDT mGdtTemplate = { .Granularity = 1, .BaseAddress_31_24 = 0x0 }, + .LinearCode64 = { + .Reserved1 = 0x0, + .Reserved2 = 0x0, + + .Accessed = 0, + .Readable = 1, + .Conforming = 0, + .IsCode = 1, + .IsNotSystemSegment = 1, + .DescriptorPrivilegeLevel = 0, + .SegmentPresent = 1, + + .Reserved3 = 0x0, + .Available = 0, + .LongMode = 1, + .Is32Bit = 0, + .Granularity = 1, + .Reserved4 = 0x0 + }, .LinearData64 = { .SegmentLimit_15_0 = 0xFFFF, .BaseAddress_15_0 = 0x0, @@ -149,25 +168,6 @@ STATIC GDT mGdtTemplate = { .Granularity = 1, .BaseAddress_31_24 = 0x0 }, - .LinearCode64 = { - .Reserved1 = 0x0, - .Reserved2 = 0x0, - - .Accessed = 0, - .Readable = 1, - .Conforming = 0, - .IsCode = 1, - .IsNotSystemSegment = 1, - .DescriptorPrivilegeLevel = 0, - .SegmentPresent = 1, - - .Reserved3 = 0x0, - .Available = 0, - .LongMode = 1, - .Is32Bit = 0, - .Granularity = 1, - .Reserved4 = 0x0 - }, .Spare5 = { .SegmentLimit_15_0 = 0x0, .BaseAddress_15_0 = 0x0, @@ -203,7 +203,7 @@ STATIC GDT mGdtTemplate = { .Granularity = 1, .BaseAddress_31_24 = 0x0 }, - .Ring3Code64 = { // SetCodeSelector () | 5.8.6 Returning from a Called Procedure + .Ring3Code64 = { .Reserved1 = 0x0, .Reserved2 = 0x0, @@ -222,21 +222,6 @@ STATIC GDT mGdtTemplate = { .Granularity = 1, .Reserved4 = 0x0 }, - // .FromRing3ToRing0 = { - // .Common.OffsetInSegment_15_0 = 0x?, - // .Common.SegmentSelector = (UINT16)LINEAR_CODE64_SEL, - // - // .Common.ParameterCount = 0, - // .Common.Reserved = 0, - // - // .Common.Type = 0xC, - // .Common.IsNotSystemSegment = 0, - // .Common.DescriptorPrivilegeLevel = 3, - // .Common.SegmentPresent = 1, - // .Common.OffsetInSegment_31_16 = 0x?, - // .OffsetInSegment_63_31 = 0x?, - // .Reserved = 0x0 - // }, }; /** diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c index b1763e756b..4e85880ed4 100644 --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c @@ -249,8 +249,6 @@ ArchSetupExceptionStack ( IdtTable[Vector].Bits.Reserved_0 = (UINT8)(Index + 1); } - // Tss->RSP0 = %rsp - // // Publish GDT //