MdeModulePkg DxeIpl: Add stack NX support
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
This commit is contained in:
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
//
|
||||
|
@@ -15,7 +15,7 @@
|
||||
2) IA-32 Intel(R) Architecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel
|
||||
3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel
|
||||
|
||||
Copyright (c) 2006 - 2011, 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
|
||||
@@ -29,21 +29,126 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#include "DxeIpl.h"
|
||||
#include "VirtualMemory.h"
|
||||
|
||||
/**
|
||||
Enable Execute Disable Bit.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EnableExecuteDisableBit (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINT64 MsrRegisters;
|
||||
|
||||
MsrRegisters = AsmReadMsr64 (0xC0000080);
|
||||
MsrRegisters |= BIT11;
|
||||
AsmWriteMsr64 (0xC0000080, MsrRegisters);
|
||||
}
|
||||
|
||||
/**
|
||||
Split 2M page to 4K.
|
||||
|
||||
@param[in] PhysicalAddress Start physical address the 2M page covered.
|
||||
@param[in, out] PageEntry2M Pointer to 2M page entry.
|
||||
@param[in] StackBase Stack base address.
|
||||
@param[in] StackSize Stack size.
|
||||
|
||||
**/
|
||||
VOID
|
||||
Split2MPageTo4K (
|
||||
IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN OUT UINT64 *PageEntry2M,
|
||||
IN EFI_PHYSICAL_ADDRESS StackBase,
|
||||
IN UINTN StackSize
|
||||
)
|
||||
{
|
||||
EFI_PHYSICAL_ADDRESS PhysicalAddress4K;
|
||||
UINTN IndexOfPageTableEntries;
|
||||
PAGE_TABLE_4K_ENTRY *PageTableEntry;
|
||||
|
||||
PageTableEntry = AllocatePages (1);
|
||||
//
|
||||
// Fill in 2M page entry.
|
||||
//
|
||||
*PageEntry2M = (UINT64) (UINTN) PageTableEntry | IA32_PG_P | IA32_PG_RW;
|
||||
|
||||
PhysicalAddress4K = PhysicalAddress;
|
||||
for (IndexOfPageTableEntries = 0; IndexOfPageTableEntries < 512; IndexOfPageTableEntries++, PageTableEntry++, PhysicalAddress4K += SIZE_4KB) {
|
||||
//
|
||||
// Fill in the Page Table entries
|
||||
//
|
||||
PageTableEntry->Uint64 = (UINT64) PhysicalAddress4K;
|
||||
PageTableEntry->Bits.ReadWrite = 1;
|
||||
PageTableEntry->Bits.Present = 1;
|
||||
if ((PhysicalAddress4K >= StackBase) && (PhysicalAddress4K < StackBase + StackSize)) {
|
||||
//
|
||||
// Set Nx bit for stack.
|
||||
//
|
||||
PageTableEntry->Bits.Nx = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Split 1G page to 2M.
|
||||
|
||||
@param[in] PhysicalAddress Start physical address the 1G page covered.
|
||||
@param[in, out] PageEntry1G Pointer to 1G page entry.
|
||||
@param[in] StackBase Stack base address.
|
||||
@param[in] StackSize Stack size.
|
||||
|
||||
**/
|
||||
VOID
|
||||
Split1GPageTo2M (
|
||||
IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN OUT UINT64 *PageEntry1G,
|
||||
IN EFI_PHYSICAL_ADDRESS StackBase,
|
||||
IN UINTN StackSize
|
||||
)
|
||||
{
|
||||
EFI_PHYSICAL_ADDRESS PhysicalAddress2M;
|
||||
UINTN IndexOfPageDirectoryEntries;
|
||||
PAGE_TABLE_ENTRY *PageDirectoryEntry;
|
||||
|
||||
PageDirectoryEntry = AllocatePages (1);
|
||||
//
|
||||
// Fill in 1G page entry.
|
||||
//
|
||||
*PageEntry1G = (UINT64) (UINTN) PageDirectoryEntry | IA32_PG_P | IA32_PG_RW;
|
||||
|
||||
PhysicalAddress2M = PhysicalAddress;
|
||||
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress2M += SIZE_2MB) {
|
||||
if ((PhysicalAddress2M < StackBase + StackSize) && ((PhysicalAddress2M + SIZE_2MB) > StackBase)) {
|
||||
//
|
||||
// Need to split this 2M page that covers stack range.
|
||||
//
|
||||
Split2MPageTo4K (PhysicalAddress2M, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
|
||||
} else {
|
||||
//
|
||||
// Fill in the Page Directory entries
|
||||
//
|
||||
PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress2M;
|
||||
PageDirectoryEntry->Bits.ReadWrite = 1;
|
||||
PageDirectoryEntry->Bits.Present = 1;
|
||||
PageDirectoryEntry->Bits.MustBe1 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Allocates and fills in the Page Directory and Page Table Entries to
|
||||
establish a 1:1 Virtual to Physical mapping.
|
||||
|
||||
@param NumberOfProcessorPhysicalAddressBits Number of processor address bits
|
||||
to use. Limits the number of page
|
||||
table entries to the physical
|
||||
address space.
|
||||
@param[in] StackBase Stack base address.
|
||||
@param[in] StackSize Stack size.
|
||||
|
||||
@return The address of 4 level page map.
|
||||
|
||||
**/
|
||||
UINTN
|
||||
CreateIdentityMappingPageTables (
|
||||
VOID
|
||||
IN EFI_PHYSICAL_ADDRESS StackBase,
|
||||
IN UINTN StackSize
|
||||
)
|
||||
{
|
||||
UINT32 RegEax;
|
||||
@@ -149,13 +254,17 @@ CreateIdentityMappingPageTables (
|
||||
PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
|
||||
|
||||
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
|
||||
//
|
||||
// Fill in the Page Directory entries
|
||||
//
|
||||
PageDirectory1GEntry->Uint64 = (UINT64)PageAddress;
|
||||
PageDirectory1GEntry->Bits.ReadWrite = 1;
|
||||
PageDirectory1GEntry->Bits.Present = 1;
|
||||
PageDirectory1GEntry->Bits.MustBe1 = 1;
|
||||
if (PcdGetBool (PcdSetNxForStack) && (PageAddress < StackBase + StackSize) && ((PageAddress + SIZE_1GB) > StackBase)) {
|
||||
Split1GPageTo2M (PageAddress, (UINT64 *) PageDirectory1GEntry, StackBase, StackSize);
|
||||
} else {
|
||||
//
|
||||
// Fill in the Page Directory entries
|
||||
//
|
||||
PageDirectory1GEntry->Uint64 = (UINT64)PageAddress;
|
||||
PageDirectory1GEntry->Bits.ReadWrite = 1;
|
||||
PageDirectory1GEntry->Bits.Present = 1;
|
||||
PageDirectory1GEntry->Bits.MustBe1 = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
|
||||
@@ -174,13 +283,20 @@ CreateIdentityMappingPageTables (
|
||||
PageDirectoryPointerEntry->Bits.Present = 1;
|
||||
|
||||
for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
|
||||
//
|
||||
// Fill in the Page Directory entries
|
||||
//
|
||||
PageDirectoryEntry->Uint64 = (UINT64)PageAddress;
|
||||
PageDirectoryEntry->Bits.ReadWrite = 1;
|
||||
PageDirectoryEntry->Bits.Present = 1;
|
||||
PageDirectoryEntry->Bits.MustBe1 = 1;
|
||||
if (PcdGetBool (PcdSetNxForStack) && (PageAddress < StackBase + StackSize) && ((PageAddress + SIZE_2MB) > StackBase)) {
|
||||
//
|
||||
// Need to split this 2M page that covers stack range.
|
||||
//
|
||||
Split2MPageTo4K (PageAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);
|
||||
} else {
|
||||
//
|
||||
// Fill in the Page Directory entries
|
||||
//
|
||||
PageDirectoryEntry->Uint64 = (UINT64)PageAddress;
|
||||
PageDirectoryEntry->Bits.ReadWrite = 1;
|
||||
PageDirectoryEntry->Bits.Present = 1;
|
||||
PageDirectoryEntry->Bits.MustBe1 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +319,10 @@ CreateIdentityMappingPageTables (
|
||||
);
|
||||
}
|
||||
|
||||
if (PcdGetBool (PcdSetNxForStack)) {
|
||||
EnableExecuteDisableBit ();
|
||||
}
|
||||
|
||||
return (UINTN)PageMap;
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
3) IA-32 Intel(R) Architecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel
|
||||
4) AMD64 Architecture Programmer's Manual Volume 2: System Programming
|
||||
|
||||
Copyright (c) 2006 - 2011, 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
|
||||
@@ -73,6 +73,28 @@ typedef union {
|
||||
UINT64 Uint64;
|
||||
} PAGE_MAP_AND_DIRECTORY_POINTER;
|
||||
|
||||
//
|
||||
// Page Table Entry 4KB
|
||||
//
|
||||
typedef union {
|
||||
struct {
|
||||
UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
|
||||
UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
|
||||
UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
|
||||
UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
|
||||
UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
|
||||
UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
|
||||
UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
|
||||
UINT64 PAT:1; //
|
||||
UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
|
||||
UINT64 Available:3; // Available for use by system software
|
||||
UINT64 PageTableBaseAddress:40; // Page Table Base Address
|
||||
UINT64 AvabilableHigh:11; // Available for use by system software
|
||||
UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
|
||||
} Bits;
|
||||
UINT64 Uint64;
|
||||
} PAGE_TABLE_4K_ENTRY;
|
||||
|
||||
//
|
||||
// Page Table Entry 2MB
|
||||
//
|
||||
@@ -123,22 +145,49 @@ typedef union {
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#define IA32_PG_P BIT0
|
||||
#define IA32_PG_RW BIT1
|
||||
|
||||
/**
|
||||
Enable Execute Disable Bit.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EnableExecuteDisableBit (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Split 2M page to 4K.
|
||||
|
||||
@param[in] PhysicalAddress Start physical address the 2M page covered.
|
||||
@param[in, out] PageEntry2M Pointer to 2M page entry.
|
||||
@param[in] StackBase Stack base address.
|
||||
@param[in] StackSize Stack size.
|
||||
|
||||
**/
|
||||
VOID
|
||||
Split2MPageTo4K (
|
||||
IN EFI_PHYSICAL_ADDRESS PhysicalAddress,
|
||||
IN OUT UINT64 *PageEntry2M,
|
||||
IN EFI_PHYSICAL_ADDRESS StackBase,
|
||||
IN UINTN StackSize
|
||||
);
|
||||
|
||||
/**
|
||||
Allocates and fills in the Page Directory and Page Table Entries to
|
||||
establish a 1:1 Virtual to Physical mapping.
|
||||
|
||||
@param NumberOfProcessorPhysicalAddressBits Number of processor address bits
|
||||
to use. Limits the number of page
|
||||
table entries to the physical
|
||||
address space.
|
||||
@param[in] StackBase Stack base address.
|
||||
@param[in] StackSize Stack size.
|
||||
|
||||
@return The address of 4 level page map.
|
||||
|
||||
**/
|
||||
UINTN
|
||||
CreateIdentityMappingPageTables (
|
||||
VOID
|
||||
IN EFI_PHYSICAL_ADDRESS StackBase,
|
||||
IN UINTN StackSize
|
||||
);
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user