Skip to content

Commit

Permalink
MdeModulePkg DxeIpl: Add stack NX support
Browse files Browse the repository at this point in the history
This feature is added for UEFI spec that says
"Stack may be marked as non-executable in identity mapped page tables".
A PCD PcdSetNxForStack is added to turn on/off this feature, and it is
FALSE by default.

Cc: Jiewen Yao <jiewen.yao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: "Yao, Jiewen" <Jiewen.yao@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18166 6f19259b-4bc3-4df7-8a09-765794883524
  • Loading branch information
lzeng14 authored and lersek committed Aug 5, 2015
1 parent edaea0e commit 5630cdf
Show file tree
Hide file tree
Showing 7 changed files with 392 additions and 38 deletions.
3 changes: 2 additions & 1 deletion MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
Expand Up @@ -5,7 +5,7 @@
# PPI to discover and dispatch the DXE Foundation and components that are
# needed to run the DXE Foundation.
#
# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
# 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
Expand Down Expand Up @@ -104,6 +104,7 @@

[Pcd.IA32,Pcd.X64]
gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack ## SOMETIMES_CONSUMES

[Depex]
gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiLoadFilePpiGuid AND gEfiPeiMasterBootModePpiGuid
Expand Down
185 changes: 177 additions & 8 deletions MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
@@ -1,7 +1,7 @@
/** @file
Ia32-specific functionality for DxeLoad.
Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
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
Expand Down Expand Up @@ -56,6 +56,151 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR gLidtDescriptor = {
0
};

/**
Allocates and fills in the Page Directory and Page Table Entries to
establish a 4G page table.
@param[in] StackBase Stack base address.
@param[in] StackSize Stack size.
@return The address of page table.
**/
UINTN
Create4GPageTablesIa32Pae (
IN EFI_PHYSICAL_ADDRESS StackBase,
IN UINTN StackSize
)
{
UINT8 PhysicalAddressBits;
EFI_PHYSICAL_ADDRESS PhysicalAddress;
UINTN IndexOfPdpEntries;
UINTN IndexOfPageDirectoryEntries;
UINT32 NumberOfPdpEntriesNeeded;
PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;
PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
PAGE_TABLE_ENTRY *PageDirectoryEntry;
UINTN TotalPagesNum;
UINTN PageAddress;

PhysicalAddressBits = 32;

//
// Calculate the table entries needed.
//
NumberOfPdpEntriesNeeded = (UINT32) LShiftU64 (1, (PhysicalAddressBits - 30));

TotalPagesNum = NumberOfPdpEntriesNeeded + 1;
PageAddress = (UINTN) AllocatePages (TotalPagesNum);
ASSERT (PageAddress != 0);

PageMap = (VOID *) PageAddress;
PageAddress += SIZE_4KB;

PageDirectoryPointerEntry = PageMap;
PhysicalAddress = 0;

for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
//
// Each Directory Pointer entries points to a page of Page Directory entires.
// So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
//
PageDirectoryEntry = (VOID *) PageAddress;
PageAddress += SIZE_4KB;

//
// Fill in a Page Directory Pointer Entries
//
PageDirectoryPointerEntry->Uint64 = (UINT64) (UINTN) PageDirectoryEntry;
PageDirectoryPointerEntry->Bits.Present = 1;

for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress += SIZE_2MB) {
if ((PhysicalAddress < StackBase + StackSize) && ((PhysicalAddress + SIZE_2MB) > StackBase)) {
//
// Need to split this 2M page that covers stack range.
//
Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
} else {
//
// Fill in the Page Directory entries
//
PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress;
PageDirectoryEntry->Bits.ReadWrite = 1;
PageDirectoryEntry->Bits.Present = 1;
PageDirectoryEntry->Bits.MustBe1 = 1;
}
}
}

for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
ZeroMem (
PageDirectoryPointerEntry,
sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)
);
}

return (UINTN) PageMap;
}

/**
The function will check if IA32 PAE is supported.
@retval TRUE IA32 PAE is supported.
@retval FALSE IA32 PAE is not supported.
**/
BOOLEAN
IsIa32PaeSupport (
VOID
)
{
UINT32 RegEax;
UINT32 RegEdx;
BOOLEAN Ia32PaeSupport;

Ia32PaeSupport = FALSE;
AsmCpuid (0x0, &RegEax, NULL, NULL, NULL);
if (RegEax >= 0x1) {
AsmCpuid (0x1, NULL, NULL, NULL, &RegEdx);
if ((RegEdx & BIT6) != 0) {
Ia32PaeSupport = TRUE;
}
}

return Ia32PaeSupport;
}

/**
The function will check if Execute Disable Bit is available.
@retval TRUE Execute Disable Bit is available.
@retval FALSE Execute Disable Bit is not available.
**/
BOOLEAN
IsExecuteDisableBitAvailable (
VOID
)
{
UINT32 RegEax;
UINT32 RegEdx;
BOOLEAN Available;

Available = FALSE;
AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
if (RegEax >= 0x80000001) {
AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
if ((RegEdx & BIT20) != 0) {
//
// Bit 20: Execute Disable Bit available.
//
Available = TRUE;
}
}

return Available;
}

/**
Transfers control to DxeCore.
Expand Down Expand Up @@ -85,6 +230,7 @@ HandOffToDxeCore (
X64_IDT_TABLE *IdtTableForX64;
EFI_VECTOR_HANDOFF_INFO *VectorInfo;
EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;
BOOLEAN BuildPageTablesIa32Pae;

Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);
ASSERT_EFI_ERROR (Status);
Expand Down Expand Up @@ -114,7 +260,7 @@ HandOffToDxeCore (
//
// Create page table and save PageMapLevel4 to CR3
//
PageTables = CreateIdentityMappingPageTables ();
PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);

//
// End of PEI phase signal
Expand Down Expand Up @@ -215,12 +361,26 @@ HandOffToDxeCore (
TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT;
TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);

BuildPageTablesIa32Pae = (BOOLEAN) (PcdGetBool (PcdSetNxForStack) && IsIa32PaeSupport () && IsExecuteDisableBitAvailable ());
if (BuildPageTablesIa32Pae) {
PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);
EnableExecuteDisableBit ();
}

//
// End of PEI phase signal
//
Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);
ASSERT_EFI_ERROR (Status);

if (BuildPageTablesIa32Pae) {
AsmWriteCr3 (PageTables);
//
// Set Physical Address Extension (bit 5 of CR4).
//
AsmWriteCr4 (AsmReadCr4 () | BIT5);
}

//
// Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
//
Expand All @@ -229,12 +389,21 @@ HandOffToDxeCore (
//
// Transfer the control to the entry point of DxeCore.
//
SwitchStack (
(SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
HobList.Raw,
NULL,
(VOID *) (UINTN) TopOfStack
);
if (BuildPageTablesIa32Pae) {
AsmEnablePaging32 (
(SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
HobList.Raw,
NULL,
(VOID *) (UINTN) TopOfStack
);
} else {
SwitchStack (
(SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
HobList.Raw,
NULL,
(VOID *) (UINTN) TopOfStack
);
}
}
}

10 changes: 8 additions & 2 deletions MdeModulePkg/Core/DxeIplPeim/X64/DxeLoadFunc.c
@@ -1,7 +1,7 @@
/** @file
x64-specifc functionality for DxeLoad.
Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
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
Expand Down Expand Up @@ -84,7 +84,13 @@ HandOffToDxeCore (
//
// Create page table and save PageMapLevel4 to CR3
//
PageTables = CreateIdentityMappingPageTables ();
PageTables = CreateIdentityMappingPageTables ((EFI_PHYSICAL_ADDRESS) (UINTN) BaseOfStack, STACK_SIZE);
} else {
//
// Set NX for stack feature also require PcdDxeIplBuildPageTables be TRUE
// for the DxeIpl and the DxeCore are both X64.
//
ASSERT (PcdGetBool (PcdSetNxForStack) == FALSE);
}

//
Expand Down

0 comments on commit 5630cdf

Please sign in to comment.