Added support for L2 (4K) page tables and made the CPU driver change cachability attributes on request. Also got the DebugUncache infrastructure working for the first time. Looks like it works for the simple case. Checking in so we can get more eyes looking at the code.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9734 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@@ -16,6 +16,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
#include "CpuDxe.h"
|
||||
|
||||
//
|
||||
// For debug switch me back to to EFI_D_PAGE when done
|
||||
//
|
||||
#define L_EFI_D_PAGE EFI_D_ERROR
|
||||
|
||||
//
|
||||
// Translation/page table definitions
|
||||
//
|
||||
@@ -170,13 +175,12 @@ SectionToGcdAttributes (
|
||||
break;
|
||||
default:
|
||||
return EFI_UNSUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
// determine protection attributes
|
||||
switch(SectionAttributes & ARM_SECTION_RW_PERMISSIONS_MASK) {
|
||||
case ARM_SECTION_NO_ACCESS: // no read, no write
|
||||
*GcdAttributes |= EFI_MEMORY_WP | EFI_MEMORY_RP;
|
||||
//*GcdAttributes |= EFI_MEMORY_WP | EFI_MEMORY_RP;
|
||||
break;
|
||||
|
||||
case ARM_SECTION_PRIV_ACCESS_ONLY:
|
||||
@@ -193,7 +197,6 @@ SectionToGcdAttributes (
|
||||
|
||||
default:
|
||||
return EFI_UNSUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
// now process eXectue Never attribute
|
||||
@@ -204,6 +207,132 @@ SectionToGcdAttributes (
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Searches memory descriptors covered by given memory range.
|
||||
|
||||
This function searches into the Gcd Memory Space for descriptors
|
||||
(from StartIndex to EndIndex) that contains the memory range
|
||||
specified by BaseAddress and Length.
|
||||
|
||||
@param MemorySpaceMap Gcd Memory Space Map as array.
|
||||
@param NumberOfDescriptors Number of descriptors in map.
|
||||
@param BaseAddress BaseAddress for the requested range.
|
||||
@param Length Length for the requested range.
|
||||
@param StartIndex Start index into the Gcd Memory Space Map.
|
||||
@param EndIndex End index into the Gcd Memory Space Map.
|
||||
|
||||
@retval EFI_SUCCESS Search successfully.
|
||||
@retval EFI_NOT_FOUND The requested descriptors does not exist.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
SearchGcdMemorySpaces (
|
||||
IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
|
||||
IN UINTN NumberOfDescriptors,
|
||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
OUT UINTN *StartIndex,
|
||||
OUT UINTN *EndIndex
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
*StartIndex = 0;
|
||||
*EndIndex = 0;
|
||||
for (Index = 0; Index < NumberOfDescriptors; Index++) {
|
||||
if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&
|
||||
BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
|
||||
*StartIndex = Index;
|
||||
}
|
||||
if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&
|
||||
BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
|
||||
*EndIndex = Index;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Sets the attributes for a specified range in Gcd Memory Space Map.
|
||||
|
||||
This function sets the attributes for a specified range in
|
||||
Gcd Memory Space Map.
|
||||
|
||||
@param MemorySpaceMap Gcd Memory Space Map as array
|
||||
@param NumberOfDescriptors Number of descriptors in map
|
||||
@param BaseAddress BaseAddress for the range
|
||||
@param Length Length for the range
|
||||
@param Attributes Attributes to set
|
||||
|
||||
@retval EFI_SUCCESS Memory attributes set successfully
|
||||
@retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
SetGcdMemorySpaceAttributes (
|
||||
IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
|
||||
IN UINTN NumberOfDescriptors,
|
||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
||||
IN UINT64 Length,
|
||||
IN UINT64 Attributes
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
UINTN StartIndex;
|
||||
UINTN EndIndex;
|
||||
EFI_PHYSICAL_ADDRESS RegionStart;
|
||||
UINT64 RegionLength;
|
||||
|
||||
//
|
||||
// Get all memory descriptors covered by the memory range
|
||||
//
|
||||
Status = SearchGcdMemorySpaces (
|
||||
MemorySpaceMap,
|
||||
NumberOfDescriptors,
|
||||
BaseAddress,
|
||||
Length,
|
||||
&StartIndex,
|
||||
&EndIndex
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Go through all related descriptors and set attributes accordingly
|
||||
//
|
||||
for (Index = StartIndex; Index <= EndIndex; Index++) {
|
||||
if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Calculate the start and end address of the overlapping range
|
||||
//
|
||||
if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
|
||||
RegionStart = BaseAddress;
|
||||
} else {
|
||||
RegionStart = MemorySpaceMap[Index].BaseAddress;
|
||||
}
|
||||
if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
|
||||
RegionLength = BaseAddress + Length - RegionStart;
|
||||
} else {
|
||||
RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
|
||||
}
|
||||
//
|
||||
// Set memory attributes according to MTRR attribute and the original attribute of descriptor
|
||||
//
|
||||
gDS->SetMemorySpaceAttributes (
|
||||
RegionStart,
|
||||
RegionLength,
|
||||
(MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
|
||||
);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
EFI_STATUS
|
||||
@@ -211,20 +340,31 @@ SyncCacheConfig (
|
||||
IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT32 i;
|
||||
UINT32 Descriptor;
|
||||
UINT32 SectionAttributes;
|
||||
EFI_PHYSICAL_ADDRESS NextRegionBase;
|
||||
UINT64 NextRegionLength;
|
||||
UINT64 GcdAttributes;
|
||||
UINT32 NextRegionAttributes = 0;
|
||||
EFI_STATUS Status;
|
||||
UINT32 i;
|
||||
UINT32 Descriptor;
|
||||
UINT32 SectionAttributes;
|
||||
EFI_PHYSICAL_ADDRESS NextRegionBase;
|
||||
UINT64 NextRegionLength;
|
||||
UINT64 GcdAttributes;
|
||||
UINT32 NextRegionAttributes = 0;
|
||||
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
|
||||
UINTN NumberOfDescriptors;
|
||||
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
|
||||
|
||||
|
||||
DEBUG ((L_EFI_D_PAGE, "SyncCacheConfig()\n"));
|
||||
|
||||
// This code assumes MMU is enabled and filed with section translations
|
||||
ASSERT (ArmMmuEnabled ());
|
||||
|
||||
//
|
||||
// Get the memory space map from GCD
|
||||
//
|
||||
MemorySpaceMap = NULL;
|
||||
Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
|
||||
// The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs
|
||||
// to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a
|
||||
@@ -240,8 +380,8 @@ SyncCacheConfig (
|
||||
NextRegionBase = NextRegionLength = 0;
|
||||
for (i=0; i< FIRST_LEVEL_ENTRY_COUNT; i++) {
|
||||
|
||||
// obtain existing descriptor
|
||||
Descriptor = FirstLevelTable[i];
|
||||
// obtain existing descriptor and make sure it contains a valid Base Address even if it is a fault section
|
||||
Descriptor = FirstLevelTable[i] | (ARM_SECTION_BASE_MASK & (i << ARM_SECTION_BASE_SHIFT));
|
||||
|
||||
// extract attributes (cacheability and permissions)
|
||||
SectionAttributes = Descriptor & 0xDEC;
|
||||
@@ -254,11 +394,11 @@ SyncCacheConfig (
|
||||
|
||||
// convert section entry attributes to GCD bitmask
|
||||
Status = SectionToGcdAttributes (NextRegionAttributes, &GcdAttributes);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
// update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
|
||||
Status = gDS->SetMemorySpaceAttributes (NextRegionBase, NextRegionLength, GcdAttributes);
|
||||
ASSERT_EFI_ERROR(Status);
|
||||
SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
|
||||
|
||||
|
||||
// start on a new region
|
||||
NextRegionLength = 0;
|
||||
@@ -343,12 +483,11 @@ UpdatePageEntries (
|
||||
// Cause a page fault if these ranges are accessed.
|
||||
EntryMask = 0x3;
|
||||
EntryValue = 0;
|
||||
DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting page %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));
|
||||
DEBUG ((L_EFI_D_PAGE, "SetMemoryAttributes(): setting page %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));
|
||||
break;
|
||||
|
||||
default:
|
||||
return EFI_UNSUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
// obtain page table base
|
||||
@@ -369,7 +508,7 @@ UpdatePageEntries (
|
||||
Descriptor = FirstLevelTable[FirstLevelIdx];
|
||||
|
||||
// does this descriptor need to be converted from section entry to 4K pages?
|
||||
if ((Descriptor & ARM_DESC_TYPE_MASK) == ARM_DESC_TYPE_SECTION ) {
|
||||
if ((Descriptor & ARM_DESC_TYPE_MASK) != ARM_DESC_TYPE_PAGE_TABLE ) {
|
||||
Status = ConvertSectionToPages (FirstLevelIdx << ARM_SECTION_BASE_SHIFT);
|
||||
if (EFI_ERROR(Status)) {
|
||||
// exit for loop
|
||||
@@ -385,7 +524,7 @@ UpdatePageEntries (
|
||||
|
||||
// calculate index into the page table
|
||||
PageTableIndex = ((BaseAddress + Offset) & ARM_SMALL_PAGE_INDEX_MASK) >> ARM_SMALL_PAGE_BASE_SHIFT;
|
||||
ASSERT(PageTableIndex < SMALL_PAGE_TABLE_ENTRY_COUNT);
|
||||
ASSERT (PageTableIndex < SMALL_PAGE_TABLE_ENTRY_COUNT);
|
||||
|
||||
// get the entry
|
||||
PageTableEntry = PageTable[PageTableIndex];
|
||||
@@ -436,35 +575,39 @@ UpdateSectionEntries (
|
||||
// EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)
|
||||
// EntryValue: values at bit positions specified by EntryMask
|
||||
|
||||
// Make sure we handle a section range that is unmapped
|
||||
EntryMask = ARM_DESC_TYPE_MASK;
|
||||
EntryValue = ARM_DESC_TYPE_SECTION;
|
||||
|
||||
// Although the PI spec is unclear on this the GCD guarantees that only
|
||||
// one Attribute bit is set at a time, so we can safely use a switch statement
|
||||
switch(Attributes) {
|
||||
case EFI_MEMORY_UC:
|
||||
// modify cacheability attributes
|
||||
EntryMask = ARM_SECTION_TEX_MASK | ARM_SECTION_C | ARM_SECTION_B;
|
||||
EntryMask |= ARM_SECTION_TEX_MASK | ARM_SECTION_C | ARM_SECTION_B;
|
||||
// map to strongly ordered
|
||||
EntryValue = 0; // TEX[2:0] = 0, C=0, B=0
|
||||
EntryValue |= 0; // TEX[2:0] = 0, C=0, B=0
|
||||
break;
|
||||
|
||||
case EFI_MEMORY_WC:
|
||||
// modify cacheability attributes
|
||||
EntryMask = ARM_SECTION_TEX_MASK | ARM_SECTION_C | ARM_SECTION_B;
|
||||
EntryMask |= ARM_SECTION_TEX_MASK | ARM_SECTION_C | ARM_SECTION_B;
|
||||
// map to normal non-cachable
|
||||
EntryValue = (0x1 << ARM_SECTION_TEX_SHIFT); // TEX [2:0]= 001 = 0x2, B=0, C=0
|
||||
EntryValue |= (0x1 << ARM_SECTION_TEX_SHIFT); // TEX [2:0]= 001 = 0x2, B=0, C=0
|
||||
break;
|
||||
|
||||
case EFI_MEMORY_WT:
|
||||
// modify cacheability attributes
|
||||
EntryMask = ARM_SECTION_TEX_MASK | ARM_SECTION_C | ARM_SECTION_B;
|
||||
EntryMask |= ARM_SECTION_TEX_MASK | ARM_SECTION_C | ARM_SECTION_B;
|
||||
// write through with no-allocate
|
||||
EntryValue = ARM_SECTION_C; // TEX [2:0] = 0, C=1, B=0
|
||||
EntryValue |= ARM_SECTION_C; // TEX [2:0] = 0, C=1, B=0
|
||||
break;
|
||||
|
||||
case EFI_MEMORY_WB:
|
||||
// modify cacheability attributes
|
||||
EntryMask = ARM_SECTION_TEX_MASK | ARM_SECTION_C | ARM_SECTION_B;
|
||||
EntryMask |= ARM_SECTION_TEX_MASK | ARM_SECTION_C | ARM_SECTION_B;
|
||||
// write back (with allocate)
|
||||
EntryValue = (0x1 << ARM_SECTION_TEX_SHIFT) | ARM_SECTION_C | ARM_SECTION_B; // TEX [2:0] = 001, C=1, B=1
|
||||
EntryValue |= (0x1 << ARM_SECTION_TEX_SHIFT) | ARM_SECTION_C | ARM_SECTION_B; // TEX [2:0] = 001, C=1, B=1
|
||||
break;
|
||||
|
||||
case EFI_MEMORY_WP:
|
||||
@@ -473,15 +616,13 @@ UpdateSectionEntries (
|
||||
case EFI_MEMORY_UCE:
|
||||
// cannot be implemented UEFI definition unclear for ARM
|
||||
// Cause a page fault if these ranges are accessed.
|
||||
EntryMask = 0x3;
|
||||
EntryValue = 0;
|
||||
DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting section %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));
|
||||
EntryValue = ARM_DESC_TYPE_FAULT;
|
||||
DEBUG ((L_EFI_D_PAGE, "SetMemoryAttributes(): setting section %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return EFI_UNSUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
// obtain page table base
|
||||
@@ -499,7 +640,7 @@ UpdateSectionEntries (
|
||||
Descriptor = FirstLevelTable[FirstLevelIdx + i];
|
||||
|
||||
// has this descriptor already been coverted to pages?
|
||||
if ((Descriptor & ARM_DESC_TYPE_MASK) == ARM_DESC_TYPE_PAGE_TABLE ) {
|
||||
if ((Descriptor & ARM_DESC_TYPE_MASK) != ARM_DESC_TYPE_PAGE_TABLE ) {
|
||||
// forward this 1MB range to page table function instead
|
||||
Status = UpdatePageEntries ((FirstLevelIdx + i) << ARM_SECTION_BASE_SHIFT, ARM_PAGE_DESC_ENTRY_MVA_SIZE, Attributes, VirtualMask);
|
||||
} else {
|
||||
@@ -539,14 +680,14 @@ ConvertSectionToPages (
|
||||
volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
|
||||
volatile ARM_PAGE_TABLE_ENTRY *PageTable;
|
||||
|
||||
DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));
|
||||
DEBUG ((L_EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));
|
||||
|
||||
// obtain page table base
|
||||
FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTranslationTableBaseAddress ();
|
||||
|
||||
// calculate index into first level translation table for start of modification
|
||||
FirstLevelIdx = (BaseAddress & ARM_SECTION_BASE_MASK) >> ARM_SECTION_BASE_SHIFT;
|
||||
ASSERT(FirstLevelIdx < FIRST_LEVEL_ENTRY_COUNT);
|
||||
ASSERT (FirstLevelIdx < FIRST_LEVEL_ENTRY_COUNT);
|
||||
|
||||
// get section attributes and convert to page attributes
|
||||
SectionDescriptor = FirstLevelTable[FirstLevelIdx];
|
||||
@@ -588,7 +729,9 @@ ConvertSectionToPages (
|
||||
// flush d-cache so descriptors make it back to uncached memory for subsequent table walks
|
||||
// TODO: change to use only PageTable base and length
|
||||
// ArmInvalidateDataCache ();
|
||||
InvalidateDataCacheRange ((VOID *)&PageTableAddr, EFI_PAGE_SIZE);
|
||||
DEBUG ((EFI_D_ERROR, "InvalidateDataCacheRange (%x, %x)\n", (UINTN)PageTableAddr, EFI_PAGE_SIZE));
|
||||
|
||||
InvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, EFI_PAGE_SIZE);
|
||||
|
||||
// formulate page table entry, Domain=0, NS=0
|
||||
PageTableDescriptor = (((UINTN)PageTableAddr) & ARM_PAGE_DESC_BASE_MASK) | ARM_DESC_TYPE_PAGE_TABLE;
|
||||
@@ -613,11 +756,11 @@ SetMemoryAttributes (
|
||||
|
||||
if(((BaseAddress & 0xFFFFF) == 0) && ((Length & 0xFFFFF) == 0)) {
|
||||
// is the base and length a multiple of 1 MB?
|
||||
DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));
|
||||
DEBUG ((L_EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));
|
||||
Status = UpdateSectionEntries (BaseAddress, Length, Attributes, VirtualMask);
|
||||
} else {
|
||||
// base and/or length is not a multiple of 1 MB
|
||||
DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU page 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));
|
||||
DEBUG ((L_EFI_D_PAGE, "SetMemoryAttributes(): MMU page 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));
|
||||
Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask);
|
||||
}
|
||||
|
||||
@@ -664,8 +807,10 @@ CpuSetMemoryAttributes (
|
||||
IN UINT64 Attributes
|
||||
)
|
||||
{
|
||||
DEBUG ((L_EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx)\n", BaseAddress, Length, Attributes));
|
||||
if ( ((BaseAddress & (EFI_PAGE_SIZE-1)) != 0) || ((Length & (EFI_PAGE_SIZE-1)) != 0)){
|
||||
// minimum granularity is EFI_PAGE_SIZE (4KB on ARM)
|
||||
DEBUG ((L_EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx): minimum ganularity is EFI_PAGE_SIZE\n", BaseAddress, Length, Attributes));
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@@ -698,13 +843,13 @@ CpuConvertPagesToUncachedVirtualAddress (
|
||||
*Attributes = GcdDescriptor.Attributes;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT (FALSE);
|
||||
//
|
||||
// Make this address range page fault if accessed. If it is a DMA buffer than this would
|
||||
// be the PCI address. Code should always use the CPU address, and we will or in VirtualMask
|
||||
// to that address.
|
||||
//
|
||||
Status = SetMemoryAttributes (Address, Length, EFI_MEMORY_XP, 0);
|
||||
Status = SetMemoryAttributes (Address, Length, EFI_MEMORY_WP, 0);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_UC, VirtualMask);
|
||||
}
|
||||
@@ -715,7 +860,7 @@ CpuConvertPagesToUncachedVirtualAddress (
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
CpuFreeConvertedPages (
|
||||
CpuReconvertPagesPages (
|
||||
IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This,
|
||||
IN EFI_PHYSICAL_ADDRESS Address,
|
||||
IN UINTN Length,
|
||||
@@ -728,7 +873,7 @@ CpuFreeConvertedPages (
|
||||
//
|
||||
// Unmap the alaised Address
|
||||
//
|
||||
Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_XP, 0);
|
||||
Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_WP, 0);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
//
|
||||
// Restore atttributes
|
||||
@@ -742,7 +887,7 @@ CpuFreeConvertedPages (
|
||||
|
||||
VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages = {
|
||||
CpuConvertPagesToUncachedVirtualAddress,
|
||||
CpuFreeConvertedPages
|
||||
CpuReconvertPagesPages
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user