Skip to content

Commit

Permalink
Ring3: Added EnterUserImage().
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikhail Krichanov committed Jan 16, 2024
1 parent b9452b7 commit 3b6aec0
Show file tree
Hide file tree
Showing 9 changed files with 298 additions and 169 deletions.
16 changes: 16 additions & 0 deletions MdeModulePkg/Core/Dxe/DxeMain.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -2794,4 +2796,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
30 changes: 29 additions & 1 deletion MdeModulePkg/Core/Dxe/Image/Image.c
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,9 @@ CoreStartImage (
UINTN SetJumpFlag;
EFI_HANDLE Handle;
UINT64 Attributes;
VOID *BaseOfStack;
VOID *TopOfStack;
UINTN SizeOfStack;

Handle = ImageHandle;

Expand Down Expand Up @@ -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;
}

//
Expand Down
5 changes: 3 additions & 2 deletions MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ 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 (
IN UEFI_IMAGE_RECORD *ImageRecord,
IN BOOLEAN IsUser
IN UEFI_IMAGE_RECORD *ImageRecord,
IN BOOLEAN IsUser
)
{
UEFI_IMAGE_RECORD_SEGMENT *ImageRecordSegment;
Expand Down
157 changes: 157 additions & 0 deletions MdePkg/Include/Library/BaseLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -4830,6 +4830,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.
Expand Down Expand Up @@ -5146,6 +5157,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.
///
Expand Down
11 changes: 11 additions & 0 deletions MdePkg/Library/BaseLib/BaseLibInternals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
22 changes: 22 additions & 0 deletions MdePkg/Library/BaseLib/SwitchStack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
48 changes: 48 additions & 0 deletions MdePkg/Library/BaseLib/X64/SwitchStack.nasm
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
6 changes: 3 additions & 3 deletions UefiCpuPkg/Library/CpuArchLib/CpuGdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -249,7 +249,7 @@ InitGlobalDescriptorTable (
)
{
EFI_STATUS Status;
GDT_ENTRIES *Gdt;
GDT *Gdt;
IA32_DESCRIPTOR Gdtr;
EFI_PHYSICAL_ADDRESS Memory;

Expand All @@ -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
Expand Down
Loading

0 comments on commit 3b6aec0

Please sign in to comment.