Ring3: Added EnterUserImage().

This commit is contained in:
Mikhail Krichanov 2024-01-16 17:06:50 +03:00
parent db50e4edf1
commit 1112ad7822
9 changed files with 296 additions and 167 deletions
MdeModulePkg/Core/Dxe
MdePkg
UefiCpuPkg/Library/CpuArchLib

View File

@ -113,6 +113,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
///
#define DEPEX_STACK_SIZE_INCREMENT 0x1000
#define USER_STACK_SIZE 0x20000
typedef struct {
EFI_GUID *ProtocolGuid;
VOID **Protocol;
@ -2800,4 +2802,18 @@ MergeMemoryMap (
IN UINTN DescriptorSize
);
/**
Set UEFI image memory attributes.
@param[in] BaseAddress Specified start address
@param[in] Length Specified length
@param[in] Attributes Specified attributes
**/
VOID
SetUefiImageMemoryAttributes (
IN UINT64 BaseAddress,
IN UINT64 Length,
IN UINT64 Attributes
);
#endif

View File

@ -1596,6 +1596,9 @@ CoreStartImage (
UINTN SetJumpFlag;
EFI_HANDLE Handle;
UINT64 Attributes;
VOID *BaseOfStack;
VOID *TopOfStack;
UINTN SizeOfStack;
Handle = ImageHandle;
@ -1694,7 +1697,32 @@ CoreStartImage (
gCpu->GetMemoryAttributes (gCpu, (EFI_PHYSICAL_ADDRESS)Image->EntryPoint, &Attributes);
ASSERT ((Attributes & EFI_MEMORY_USER) != 0);
Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
//
// Allocate 128KB for the User Stack.
//
BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (USER_STACK_SIZE));
ASSERT (BaseOfStack != NULL);
SizeOfStack = EFI_SIZE_TO_PAGES (USER_STACK_SIZE) * EFI_PAGE_SIZE;
SetUefiImageMemoryAttributes ((UINTN)BaseOfStack, SizeOfStack, EFI_MEMORY_XP | EFI_MEMORY_USER);
//
// Compute the top of the allocated stack. Pre-allocate a UINTN for safety.
//
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));
EnterUserImage (
(SWITCH_STACK_ENTRY_POINT)(UINTN)Image->EntryPoint,
ImageHandle,
Image->Info.SystemTable,
TopOfStack,
(UINT16)RING3_CODE64_SEL,
(UINT16)RING3_DATA64_SEL
);
Image->Status = EFI_SUCCESS;
}
//

View File

@ -91,6 +91,7 @@ SetUefiImageMemoryAttributes (
Set UEFI image protection attributes.
@param[in] ImageRecord A UEFI image record
@param[in] IsUser Whether UEFI image record is User Image.
**/
VOID
SetUefiImageProtectionAttributes (

View File

@ -5114,6 +5114,17 @@ SwitchStack (
...
);
VOID
EFIAPI
EnterUserImage (
IN SWITCH_STACK_ENTRY_POINT EntryPoint,
IN VOID *Context1 OPTIONAL,
IN VOID *Context2 OPTIONAL,
IN VOID *NewStack,
IN UINT16 CodeSelector,
IN UINT16 DataSelector
);
/**
Generates a breakpoint on the CPU.
@ -5430,6 +5441,152 @@ typedef union {
UINTN UintN;
} IA32_CR4;
#pragma pack (1)
//
// Global Descriptor Entry structures
//
typedef struct {
UINT16 SegmentLimit_15_0;
UINT16 BaseAddress_15_0;
UINT8 BaseAddress_23_16;
UINT8 Type : 4;
UINT8 S : 1;
UINT8 DPL : 2;
UINT8 P : 1;
UINT8 SegmentLimit_19_16 : 4;
UINT8 AVL : 1;
UINT8 L : 1;
UINT8 D_B : 1;
UINT8 G : 1;
UINT8 BaseAddress_31_24;
} SEGMENT_DESCRIPTOR;
typedef struct {
UINT16 SegmentLimit_15_0;
UINT16 BaseAddress_15_0;
UINT8 BaseAddress_23_16;
//
// Type
//
UINT8 Accessed : 1;
UINT8 Writable : 1;
UINT8 ExpansionDirection : 1;
UINT8 IsCode : 1;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT8 SegmentLimit_19_16 : 4;
UINT8 Available : 1;
UINT8 Reserved : 1;
UINT8 UpperBound : 1;
UINT8 Granularity : 1;
UINT8 BaseAddress_31_24;
} DATA_SEGMENT_32;
typedef struct {
UINT16 SegmentLimit_15_0;
UINT16 BaseAddress_15_0;
UINT8 BaseAddress_23_16;
//
// Type
//
UINT8 Accessed : 1;
UINT8 Readable : 1;
UINT8 Conforming : 1;
UINT8 IsCode : 1;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT8 SegmentLimit_19_16 : 4;
UINT8 Available : 1;
UINT8 Reserved : 1;
UINT8 Is32Bit : 1;
UINT8 Granularity : 1;
UINT8 BaseAddress_31_24;
} CODE_SEGMENT_32;
typedef struct {
UINT32 Reserved1;
UINT8 Reserved2;
//
// Type
//
UINT8 Accessed : 1;
UINT8 Readable : 1;
UINT8 Conforming : 1;
UINT8 IsCode : 1;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT8 Reserved3 : 4;
UINT8 Available : 1;
UINT8 LongMode : 1;
UINT8 Is32Bit : 1;
UINT8 Granularity : 1;
UINT8 Reserved4;
} CODE_SEGMENT_64;
typedef struct {
UINT16 SegmentLimit_15_0;
UINT16 BaseAddress_15_0;
UINT8 BaseAddress_23_16;
UINT8 Type : 4;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT8 SegmentLimit_19_16 : 4;
UINT8 Reserved : 3;
UINT8 Granularity : 1;
UINT8 BaseAddress_31_24;
} SYSTEM_SEGMENT;
typedef struct {
UINT16 OffsetInSegment_15_0;
UINT16 SegmentSelector;
UINT8 ParameterCount : 5;
UINT8 Reserved : 3;
UINT8 Type : 4;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT16 OffsetInSegment_31_16;
} CALL_GATE_32;
typedef struct {
CALL_GATE_32 Common;
UINT32 OffsetInSegment_63_31;
UINT32 Reserved;
} CALL_GATE_64;
typedef struct {
SEGMENT_DESCRIPTOR Null;
DATA_SEGMENT_32 Linear;
CODE_SEGMENT_32 LinearCode;
DATA_SEGMENT_32 SysData;
CODE_SEGMENT_32 SysCode;
CODE_SEGMENT_32 SysCode16;
DATA_SEGMENT_32 LinearData64;
CODE_SEGMENT_64 LinearCode64;
SEGMENT_DESCRIPTOR Spare5;
DATA_SEGMENT_32 Ring3Data64;
CODE_SEGMENT_64 Ring3Code64;
// CALL_GATE_64 FromRing3ToRing0;
} GDT;
#pragma pack ()
#define RING3_DATA64_SEL OFFSET_OF (GDT, Ring3Data64)
#define RING3_CODE64_SEL OFFSET_OF (GDT, Ring3Code64)
///
/// Byte packed structure for a segment descriptor in a GDT/LDT.
///

View File

@ -332,6 +332,17 @@ InternalSwitchStack (
IN VA_LIST Marker
);
VOID
EFIAPI
InternalEnterUserImage (
IN SWITCH_STACK_ENTRY_POINT EntryPoint,
IN VOID *Context1 OPTIONAL,
IN VOID *Context2 OPTIONAL,
IN VOID *NewStack,
IN UINT16 CodeSelector,
IN UINT16 DataSelector
);
/**
Worker function that returns a bit field from Operand.

View File

@ -68,3 +68,25 @@ SwitchStack (
//
ASSERT (FALSE);
}
VOID
EFIAPI
EnterUserImage (
IN SWITCH_STACK_ENTRY_POINT EntryPoint,
IN VOID *Context1 OPTIONAL,
IN VOID *Context2 OPTIONAL,
IN VOID *NewStack,
IN UINT16 CodeSelector,
IN UINT16 DataSelector
)
{
ASSERT (EntryPoint != NULL);
ASSERT (NewStack != NULL);
//
// New stack must be aligned with CPU_STACK_ALIGNMENT
//
ASSERT (((UINTN)NewStack & (CPU_STACK_ALIGNMENT - 1)) == 0);
InternalEnterUserImage (EntryPoint, Context1, Context2, NewStack, CodeSelector, DataSelector);
}

View File

@ -1,4 +1,6 @@
;------------------------------------------------------------------------------
; Copyright (c) 2024, Mikhail Krichanov. All rights reserved.
; SPDX-License-Identifier: BSD-3-Clause
;
; Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
; SPDX-License-Identifier: BSD-2-Clause-Patent
@ -43,3 +45,49 @@ ASM_PFX(InternalSwitchStack):
lea rsp, [r9 - 0x20]
call rax
;------------------------------------------------------------------------------
; Routine Description:
;
; Routine for transfering control to user image with 2 parameters
;
; Arguments:
;
; (rcx) EntryPoint - Entry point with new stack.
; (rdx) Context1 - Parameter1 for entry point.
; (r8) Context2 - Parameter2 for entry point.
; (r9) NewStack - The pointer to new stack.
;On stack CodeSelector - Segment selector for code.
;On stack DataSelector - Segment selector for data.
;
; Returns:
;
; None
;
;------------------------------------------------------------------------------
global ASM_PFX(InternalEnterUserImage)
ASM_PFX(InternalEnterUserImage):
; Set Data selectors
mov rax, [rsp + 8*6]
or rax, 3H ; RPL = 3
o16 mov ds, ax
o16 mov es, ax
o16 mov fs, ax
o16 mov gs, ax
; Save Code selector
mov r10, [rsp + 8*5]
or r10, 3H ; RPL = 3
; Prepare stack before swithcing
push rax ; ss
push r9 ; rsp
push r10 ; cs
push rcx ; rip
; Save 2 parameters
mov rcx, rdx
mov rdx, r8
; Pass control to user image
retfq

View File

@ -13,7 +13,7 @@
//
// Global descriptor table (GDT) Template
//
STATIC GDT_ENTRIES mGdtTemplate = {
STATIC GDT mGdtTemplate = {
.Null = {
.SegmentLimit_15_0 = 0x0,
.BaseAddress_15_0 = 0x0,
@ -249,7 +249,7 @@ InitGlobalDescriptorTable (
)
{
EFI_STATUS Status;
GDT_ENTRIES *Gdt;
GDT *Gdt;
IA32_DESCRIPTOR Gdtr;
EFI_PHYSICAL_ADDRESS Memory;
@ -267,7 +267,7 @@ InitGlobalDescriptorTable (
);
ASSERT_EFI_ERROR (Status);
ASSERT ((Memory != 0) && (Memory < SIZE_4GB));
Gdt = (GDT_ENTRIES *)(UINTN)Memory;
Gdt = (GDT *)(UINTN)Memory;
//
// Initialize all GDT entries

View File

@ -14,169 +14,15 @@
// Local structure definitions
//
#pragma pack (1)
//
// Global Descriptor Entry structures
//
typedef struct {
UINT16 SegmentLimit_15_0;
UINT16 BaseAddress_15_0;
UINT8 BaseAddress_23_16;
UINT8 Type : 4;
UINT8 S : 1;
UINT8 DPL : 2;
UINT8 P : 1;
UINT8 SegmentLimit_19_16 : 4;
UINT8 AVL : 1;
UINT8 L : 1;
UINT8 D_B : 1;
UINT8 G : 1;
UINT8 BaseAddress_31_24;
} SEGMENT_DESCRIPTOR;
typedef struct {
UINT16 SegmentLimit_15_0;
UINT16 BaseAddress_15_0;
UINT8 BaseAddress_23_16;
//
// Type
//
UINT8 Accessed : 1;
UINT8 Writable : 1;
UINT8 ExpansionDirection : 1;
UINT8 IsCode : 1;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT8 SegmentLimit_19_16 : 4;
UINT8 Available : 1;
UINT8 Reserved : 1;
UINT8 UpperBound : 1;
UINT8 Granularity : 1;
UINT8 BaseAddress_31_24;
} DATA_SEGMENT_32;
typedef struct {
UINT16 SegmentLimit_15_0;
UINT16 BaseAddress_15_0;
UINT8 BaseAddress_23_16;
//
// Type
//
UINT8 Accessed : 1;
UINT8 Readable : 1;
UINT8 Conforming : 1;
UINT8 IsCode : 1;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT8 SegmentLimit_19_16 : 4;
UINT8 Available : 1;
UINT8 Reserved : 1;
UINT8 Is32Bit : 1;
UINT8 Granularity : 1;
UINT8 BaseAddress_31_24;
} CODE_SEGMENT_32;
typedef struct {
UINT32 Reserved1;
UINT8 Reserved2;
//
// Type
//
UINT8 Accessed : 1;
UINT8 Readable : 1;
UINT8 Conforming : 1;
UINT8 IsCode : 1;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT8 Reserved3 : 4;
UINT8 Available : 1;
UINT8 LongMode : 1;
UINT8 Is32Bit : 1;
UINT8 Granularity : 1;
UINT8 Reserved4;
} CODE_SEGMENT_64;
typedef struct {
UINT16 SegmentLimit_15_0;
UINT16 BaseAddress_15_0;
UINT8 BaseAddress_23_16;
UINT8 Type : 4;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT8 SegmentLimit_19_16 : 4;
UINT8 Reserved : 3;
UINT8 Granularity : 1;
UINT8 BaseAddress_31_24;
} SYSTEM_SEGMENT;
typedef struct {
UINT16 OffsetInSegment_15_0;
UINT16 SegmentSelector;
UINT8 ParameterCount : 5;
UINT8 Reserved : 3;
UINT8 Type : 4;
UINT8 IsNotSystemSegment : 1;
UINT8 DescriptorPrivilegeLevel : 2;
UINT8 SegmentPresent : 1;
UINT16 OffsetInSegment_31_16;
} CALL_GATE_32;
typedef struct {
CALL_GATE_32 Common;
UINT32 OffsetInSegment_63_31;
UINT32 Reserved;
} CALL_GATE_64;
typedef union {
DATA_SEGMENT_32 DataSegment32;
CODE_SEGMENT_32 CodeSegment32;
CODE_SEGMENT_64 CodeSegment64;
CALL_GATE_32 CallGate32;
SYSTEM_SEGMENT SystemSegment;
SEGMENT_DESCRIPTOR SegmentDescriptor;
} GDT_ENTRY;
typedef struct {
SEGMENT_DESCRIPTOR Null;
DATA_SEGMENT_32 Linear;
CODE_SEGMENT_32 LinearCode;
DATA_SEGMENT_32 SysData;
CODE_SEGMENT_32 SysCode;
CODE_SEGMENT_32 SysCode16;
DATA_SEGMENT_32 LinearData64;
CODE_SEGMENT_64 LinearCode64;
SEGMENT_DESCRIPTOR Spare5;
DATA_SEGMENT_32 Ring3Data64;
CODE_SEGMENT_64 Ring3Code64;
// CALL_GATE_64 FromRing3ToRing0;
} GDT_ENTRIES;
#pragma pack ()
#define NULL_SEL OFFSET_OF (GDT_ENTRIES, Null)
#define LINEAR_SEL OFFSET_OF (GDT_ENTRIES, Linear)
#define LINEAR_CODE_SEL OFFSET_OF (GDT_ENTRIES, LinearCode)
#define SYS_DATA_SEL OFFSET_OF (GDT_ENTRIES, SysData)
#define SYS_CODE_SEL OFFSET_OF (GDT_ENTRIES, SysCode)
#define SYS_CODE16_SEL OFFSET_OF (GDT_ENTRIES, SysCode16)
#define LINEAR_DATA64_SEL OFFSET_OF (GDT_ENTRIES, LinearData64)
#define LINEAR_CODE64_SEL OFFSET_OF (GDT_ENTRIES, LinearCode64)
#define SPARE5_SEL OFFSET_OF (GDT_ENTRIES, Spare5)
#define RING3_DATA64_SEL OFFSET_OF (GDT_ENTRIES, Ring3Data64)
#define RING3_CODE64_SEL OFFSET_OF (GDT_ENTRIES, Ring3Code64)
#define NULL_SEL OFFSET_OF (GDT, Null)
#define LINEAR_SEL OFFSET_OF (GDT, Linear)
#define LINEAR_CODE_SEL OFFSET_OF (GDT, LinearCode)
#define SYS_DATA_SEL OFFSET_OF (GDT, SysData)
#define SYS_CODE_SEL OFFSET_OF (GDT, SysCode)
#define SYS_CODE16_SEL OFFSET_OF (GDT, SysCode16)
#define LINEAR_DATA64_SEL OFFSET_OF (GDT, LinearData64)
#define LINEAR_CODE64_SEL OFFSET_OF (GDT, LinearCode64)
#define SPARE5_SEL OFFSET_OF (GDT, Spare5)
#if defined (MDE_CPU_IA32)
#define CPU_CODE_SEL LINEAR_CODE_SEL