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:
AJFISH 2010-01-14 03:25:08 +00:00
parent 66b631f5e0
commit f659880bfa
14 changed files with 478 additions and 118 deletions

View File

@ -49,6 +49,7 @@
DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
ArmLib|ArmPkg/Library/ArmLib/ArmCortexA/ArmCortexArmLib.inf
CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
[LibraryClasses.ARM]
#

View File

@ -16,6 +16,34 @@
BOOLEAN mInterruptState = FALSE;
/**
This function flushes the range of addresses from Start to Start+Length
from the processor's data cache. If Start is not aligned to a cache line
boundary, then the bytes before Start to the preceding cache line boundary
are also flushed. If Start+Length is not aligned to a cache line boundary,
then the bytes past Start+Length to the end of the next cache line boundary
are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
supported. If the data cache is fully coherent with all DMA operations, then
this function can just return EFI_SUCCESS. If the processor does not support
flushing a range of the data cache, then the entire data cache can be flushed.
@param This The EFI_CPU_ARCH_PROTOCOL instance.
@param Start The beginning physical address to flush from the processor's data
cache.
@param Length The number of bytes to flush from the processor's data cache. This
function may flush more bytes than Length specifies depending upon
the granularity of the flush operation that the processor supports.
@param FlushType Specifies the type of flush operation to perform.
@retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
the processor's data cache.
@retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified
by FlushType.
@retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed
from the processor's data cache.
**/
EFI_STATUS
EFIAPI
CpuFlushCpuDataCache (
@ -25,6 +53,8 @@ CpuFlushCpuDataCache (
IN EFI_CPU_FLUSH_TYPE FlushType
)
{
DEBUG ((EFI_D_ERROR, "CpuFlushCpuDataCache (%lx, %lx, %x)\n", Start, Length, FlushType));
switch (FlushType) {
case EfiCpuFlushTypeWriteBack:
WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
@ -42,6 +72,16 @@ CpuFlushCpuDataCache (
return EFI_SUCCESS;
}
/**
This function enables interrupt processing by the processor.
@param This The EFI_CPU_ARCH_PROTOCOL instance.
@retval EFI_SUCCESS Interrupts are enabled on the processor.
@retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.
**/
EFI_STATUS
EFIAPI
CpuEnableInterrupt (
@ -55,6 +95,15 @@ CpuEnableInterrupt (
}
/**
This function disables interrupt processing by the processor.
@param This The EFI_CPU_ARCH_PROTOCOL instance.
@retval EFI_SUCCESS Interrupts are disabled on the processor.
@retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
**/
EFI_STATUS
EFIAPI
CpuDisableInterrupt (
@ -67,6 +116,20 @@ CpuDisableInterrupt (
return EFI_SUCCESS;
}
/**
This function retrieves the processor's current interrupt state a returns it in
State. If interrupts are currently enabled, then TRUE is returned. If interrupts
are currently disabled, then FALSE is returned.
@param This The EFI_CPU_ARCH_PROTOCOL instance.
@param State A pointer to the processor's current interrupt state. Set to TRUE if
interrupts are enabled and FALSE if interrupts are disabled.
@retval EFI_SUCCESS The processor's current interrupt state was returned in State.
@retval EFI_INVALID_PARAMETER State is NULL.
**/
EFI_STATUS
EFIAPI
CpuGetInterruptState (
@ -82,6 +145,23 @@ CpuGetInterruptState (
return EFI_SUCCESS;
}
/**
This function generates an INIT on the processor. If this function succeeds, then the
processor will be reset, and control will not be returned to the caller. If InitType is
not supported by this processor, or the processor cannot programmatically generate an
INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
@param This The EFI_CPU_ARCH_PROTOCOL instance.
@param InitType The type of processor INIT to perform.
@retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
@retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
by this processor.
@retval EFI_DEVICE_ERROR The processor INIT failed.
**/
EFI_STATUS
EFIAPI
CpuInit (
@ -115,17 +195,6 @@ CpuGetTimerValue (
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
CpuSetMemoryAttributes (
IN EFI_CPU_ARCH_PROTOCOL *This,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN UINT64 Attributes
)
{
return EFI_UNSUPPORTED;
}
//
// Globals used to initialize the protocol
@ -149,8 +218,26 @@ CpuDxeInitialize (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
{
EFI_STATUS Status;
InitializeExceptions (&mCpu);
return gBS->InstallMultipleProtocolInterfaces (&mCpuHandle, &gEfiCpuArchProtocolGuid, &mCpu, NULL);
Status = gBS->InstallMultipleProtocolInterfaces (
&mCpuHandle,
&gEfiCpuArchProtocolGuid, &mCpu,
&gVirtualUncachedPagesProtocolGuid, &gVirtualUncachedPages,
NULL
);
//
// Make sure GCD and MMU settings match. This API calls gDS->SetMemorySpaceAttributes ()
// and that calls EFI_CPU_ARCH_PROTOCOL.SetMemoryAttributes, so this code needs to go
// after the protocol is installed
//
SyncCacheConfig (&mCpu);
return Status;
}

View File

@ -19,14 +19,29 @@
#include <Library/ArmLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/CacheMaintenanceLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/CacheMaintenanceLib.h>
#include <Library/PeCoffGetEntryPointLib.h>
#include <Library/UefiLib.h>
#include <Library/CpuLib.h>
#include <Guid/DebugImageInfoTable.h>
#include <Protocol/Cpu.h>
#include <Protocol/DebugSupport.h>
#include <Protocol/DebugSupportPeriodicCallback.h>
#include <Protocol/VirtualUncachedPages.h>
#include <Protocol/LoadedImage.h>
#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \
EFI_MEMORY_WC | \
EFI_MEMORY_WT | \
EFI_MEMORY_WB | \
EFI_MEMORY_UCE \
)
/**
@ -83,9 +98,31 @@ RegisterDebuggerInterruptHandler (
);
EFI_STATUS
EFIAPI
CpuSetMemoryAttributes (
IN EFI_CPU_ARCH_PROTOCOL *This,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN UINT64 Attributes
);
EFI_STATUS
InitializeExceptions (
IN EFI_CPU_ARCH_PROTOCOL *Cpu
);
EFI_STATUS
SyncCacheConfig (
IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
);
EFI_STATUS
ConvertSectionToPages (
IN EFI_PHYSICAL_ADDRESS BaseAddress
);
extern VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages;
#endif // __CPU_DXE_ARM_EXCEPTION_H__

View File

@ -39,6 +39,7 @@
#
ExceptionSupport.ARMv6.asm | RVCT
# ExceptionSupport.ARMv6.S | GCC
Mmu.c
[Packages]
ArmPkg/ArmPkg.dec
@ -50,10 +51,18 @@
CacheMaintenanceLib
UefiDriverEntryPoint
ArmLib
DxeServicesTableLib
PeCoffGetEntryPointLib
UefiLib
CpuLib
[Protocols]
gEfiCpuArchProtocolGuid
gEfiDebugSupportPeriodicCallbackProtocolGuid
gVirtualUncachedPagesProtocolGuid
[Guids]
gEfiDebugImageInfoTableGuid
[Pcd.common]
gArmTokenSpaceGuid.PcdCpuVectorBaseAddress

View File

@ -13,7 +13,8 @@
**/
#include "CpuDxe.h"
#include <Library/CacheMaintenanceLib.h>
EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL;
VOID
ExceptionHandlersStart (
@ -120,6 +121,76 @@ RegisterDebuggerInterruptHandler (
return EFI_SUCCESS;
}
UINT32
EFIAPI
PeCoffGetSizeOfHeaders (
IN VOID *Pe32Data
)
{
EFI_IMAGE_DOS_HEADER *DosHdr;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
UINTN SizeOfHeaders;
DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
//
// DOS image header is present, so read the PE header after the DOS image header.
//
Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
} else {
//
// DOS image header is not present, so PE header is at the image base.
//
Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
}
if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
} else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
}
return SizeOfHeaders;
}
CHAR8 *
GetImageName (
IN UINT32 FaultAddress,
OUT UINT32 *ImageBase,
OUT UINT32 *PeCoffSizeOfHeaders
)
{
EFI_DEBUG_IMAGE_INFO *DebugTable;
UINTN Entry;
CHAR8 *Address;
DebugTable = gDebugImageTableHeader->EfiDebugImageInfoTable;
if (DebugTable == NULL) {
return NULL;
}
Address = (CHAR8 *)(UINTN)FaultAddress;
for (Entry = 0; Entry < gDebugImageTableHeader->TableSize; Entry++, DebugTable++) {
if (DebugTable->NormalImage != NULL) {
if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) &&
(DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {
if ((Address >= DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase) &&
(Address <= ((CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase + DebugTable->NormalImage->LoadedImageProtocolInstance->ImageSize))) {
*ImageBase = (UINT32)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase;
*PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)*ImageBase);
return PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase);
}
}
}
}
return NULL;
}
CHAR8 *gExceptionTypeString[] = {
"Reset",
"Undefined Instruction",
@ -174,11 +245,41 @@ CommonCExceptionHandler (
}
//
// Code after here is the default exception handler...
// Code after here is the default exception handler... Dump the context
//
DEBUG ((EFI_D_ERROR, "%a Exception from %08x\n", gExceptionTypeString[ExceptionType], SystemContext.SystemContextArm->PC));
ASSERT (FALSE);
DEBUG ((EFI_D_ERROR, "\n%a Exception from instruction at 0x%08x CPSR 0x%08x\n", gExceptionTypeString[ExceptionType], SystemContext.SystemContextArm->PC, SystemContext.SystemContextArm->CPSR));
DEBUG_CODE_BEGIN ();
CHAR8 *Pdb;
UINT32 ImageBase;
UINT32 PeCoffSizeOfHeader;
UINT32 Offset;
Pdb = GetImageName (SystemContext.SystemContextArm->PC, &ImageBase, &PeCoffSizeOfHeader);
Offset = SystemContext.SystemContextArm->PC - ImageBase;
if (Pdb != NULL) {
DEBUG ((EFI_D_ERROR, "%a\n", Pdb));
//
// A PE/COFF image loads its headers into memory so the headers are
// included in the linked addressess. ELF and Mach-O images do not
// include the headers so the first byte of the image is usually
// text (code). If you look at link maps from ELF or Mach-O images
// you need to subtact out the size of the PE/COFF header to get
// get the offset that matches the link map.
//
DEBUG ((EFI_D_ERROR, "loadded at 0x%08x (PE/COFF offset) 0x%08x (ELF or Mach-O offset) 0x%08x\n", ImageBase, Offset, Offset - PeCoffSizeOfHeader));
}
DEBUG_CODE_END ();
DEBUG ((EFI_D_ERROR, " R0 0x%08x R1 0x%08x R2 0x%08x R3 0x%08x\n", SystemContext.SystemContextArm->R0, SystemContext.SystemContextArm->R1, SystemContext.SystemContextArm->R2, SystemContext.SystemContextArm->R3));
DEBUG ((EFI_D_ERROR, " R4 0x%08x R5 0x%08x R6 0x%08x R7 0x%08x\n", SystemContext.SystemContextArm->R4, SystemContext.SystemContextArm->R5, SystemContext.SystemContextArm->R6, SystemContext.SystemContextArm->R7));
DEBUG ((EFI_D_ERROR, " R8 0x%08x R9 0x%08x R10 0x%08x R11 0x%08x\n", SystemContext.SystemContextArm->R8, SystemContext.SystemContextArm->R9, SystemContext.SystemContextArm->R10, SystemContext.SystemContextArm->R11));
DEBUG ((EFI_D_ERROR, "R12 0x%08x SP 0x%08x LR 0x%08x PC 0x%08x\n", SystemContext.SystemContextArm->R12, SystemContext.SystemContextArm->SP, SystemContext.SystemContextArm->LR, SystemContext.SystemContextArm->PC));
DEBUG ((EFI_D_ERROR, "DFSR 0x%08x DFAR 0x%08x IFSR 0x%08x IFAR 0x%08x\n\n", SystemContext.SystemContextArm->DFSR, SystemContext.SystemContextArm->DFAR, SystemContext.SystemContextArm->IFSR, SystemContext.SystemContextArm->IFAR));
ASSERT (FALSE);
// while (TRUE) {
// CpuSleep ();
// }
}
@ -195,6 +296,11 @@ InitializeExceptions (
BOOLEAN Enabled;
EFI_PHYSICAL_ADDRESS Base;
Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&gDebugImageTableHeader);
if (EFI_ERROR (Status)) {
gDebugImageTableHeader = NULL;
}
//
// Disable interrupts
//

View File

@ -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
};

View File

@ -263,6 +263,7 @@ ArmSetTranslationTableBaseAddress (
VOID *
EFIAPI
ArmGetTranslationTableBaseAddress (
VOID
);
VOID

View File

@ -52,9 +52,9 @@ EFI_STATUS
struct _VIRTUAL_UNCACHED_PAGES_PROTOCOL {
CONVERT_PAGES_TO_UNCACHED_VIRTUAL_ADDRESS ConvertPages;
FREE_CONVERTED_PAGES FreeConvertedPages;
FREE_CONVERTED_PAGES RevertPages;
};
extern EFI_GUID gVirtualUncachedPagesProtocolGuid;
#endif
#endif

View File

@ -27,19 +27,15 @@ CacheRangeOperation (
UINTN ArmCacheLineAlignmentMask = ArmCacheLineLength - 1;
UINTN ArmCacheOperationThreshold = PcdGet32(PcdArmCacheOperationThreshold);
if ((CacheOperation != NULL) && (Length >= ArmCacheOperationThreshold))
{
CacheOperation();
}
else
{
if ((CacheOperation != NULL) && (Length >= ArmCacheOperationThreshold)) {
CacheOperation ();
} else {
// Align address (rounding down)
UINTN AlignedAddress = (UINTN)Start - ((UINTN)Start & ArmCacheLineAlignmentMask);
UINTN EndAddress = (UINTN)Start + Length;
// Perform the line operation on an address in each cache line
while (AlignedAddress < EndAddress)
{
while (AlignedAddress < EndAddress) {
LineOperation(AlignedAddress);
AlignedAddress += ArmCacheLineLength;
}

View File

@ -66,7 +66,7 @@ ArmSetTranslationTableBaseAddress
mcr p15,0,r0,c2,c0,0
bx lr
ArmSetTranslationTableBaseAddress
ArmGetTranslationTableBaseAddress
mrc p15,0,r0,c2,c0,0
bx lr

View File

@ -49,7 +49,7 @@ UncachedInternalAllocateAlignedPages (
EFI_CPU_ARCH_PROTOCOL *gCpu;
EFI_CPU_ARCH_PROTOCOL *gDebugUncachedCpu;
VIRTUAL_UNCACHED_PAGES_PROTOCOL *gVirtualUncachedPages;
//
@ -641,7 +641,7 @@ DebugUncachedMemoryAllocationLibConstructor (
{
EFI_STATUS Status;
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gDebugUncachedCpu);
ASSERT_EFI_ERROR(Status);
Status = gBS->LocateProtocol (&gVirtualUncachedPagesProtocolGuid, NULL, (VOID **)&gVirtualUncachedPages);

View File

@ -29,19 +29,19 @@
MdePkg/MdePkg.dec
ArmPkg/ArmPkg.dec
[Protocols]
gEfiCpuArchProtocolGuid
[LibraryClasses]
BaseLib
UefiMemoryAllocationLib
MemoryAllocationLib
ArmLib
[Protocols]
gEfiCpuArchProtocolGuid
gVirtualUncachedPagesProtocolGuid
[FixedPcd]
gArmTokenSpaceGuid.PcdArmUncachedMemoryMask
[Depex]
gEfiCpuArchProtocolGuid
gVirtualUncachedPagesProtocolGuid
gEfiCpuArchProtocolGuid AND gVirtualUncachedPagesProtocolGuid

View File

@ -40,6 +40,7 @@
ArmLib|ArmPkg/Library/ArmLib/ArmCortexA/ArmCortexArmLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
@ -90,7 +91,10 @@
UefiUsbLib|MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
EblAddExternalCommandLib|EmbeddedPkg/Library/EblAddExternalCommandLib/EblAddExternalCommandLib.inf
UncachedMemoryAllocationLib|ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf
# UncachedMemoryAllocationLib|ArmPkg/Library/UncachedMemoryAllocationLib/UncachedMemoryAllocationLib.inf
UncachedMemoryAllocationLib|ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.inf
CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf
TimerLib|BeagleBoardPkg/Library/BeagleBoardTimerLib/BeagleBoardTimerLib.inf
OmapLib|BeagleBoardPkg/Library/OmapLib/OmapLib.inf
@ -206,49 +210,29 @@
gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|320
# DEBUG_ASSERT_ENABLED 0x01
# DEBUG_PRINT_ENABLED 0x02
# DEBUG_CODE_ENABLED 0x04
# CLEAR_MEMORY_ENABLED 0x08
# ASSERT_BREAKPOINT_ENABLED 0x10
# ASSERT_DEADLOOP_ENABLED 0x20
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2f
# DEBUG_INIT 0x00000001 // Initialization
# DEBUG_WARN 0x00000002 // Warnings
# DEBUG_LOAD 0x00000004 // Load events
# DEBUG_FS 0x00000008 // EFI File system
# DEBUG_POOL 0x00000010 // Alloc & Free's
# DEBUG_PAGE 0x00000020 // Alloc & Free's
# DEBUG_INFO 0x00000040 // Verbose
# DEBUG_DISPATCH 0x00000080 // PEI/DXE Dispatchers
# DEBUG_VARIABLE 0x00000100 // Variable
# DEBUG_BM 0x00000400 // Boot Manager
# DEBUG_BLKIO 0x00001000 // BlkIo Driver
# DEBUG_NET 0x00004000 // SNI Driver
# DEBUG_UNDI 0x00010000 // UNDI Driver
# DEBUG_LOADFILE 0x00020000 // UNDI Driver
# DEBUG_EVENT 0x00080000 // Event messages
# DEBUG_ERROR 0x80000000 // Error
gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000004

View File

@ -58,29 +58,23 @@ InitCache (
MemoryTable[0].Length = MemoryLength;
MemoryTable[0].Attributes = (ARM_MEMORY_REGION_ATTRIBUTES)CacheAttributes;
// Uncached DDR Mirror
MemoryTable[1].PhysicalBase = MemoryBase;
MemoryTable[1].VirtualBase = MemoryBase | UncachedMemoryMask;
MemoryTable[1].Length = MemoryLength;
MemoryTable[1].Attributes = DDR_ATTRIBUTES_UNCACHED;
// SOC Registers. L3 interconnects
MemoryTable[2].PhysicalBase = SOC_REGISTERS_L3_PHYSICAL_BASE;
MemoryTable[2].VirtualBase = SOC_REGISTERS_L3_PHYSICAL_BASE;
MemoryTable[2].Length = SOC_REGISTERS_L3_PHYSICAL_LENGTH;
MemoryTable[2].Attributes = SOC_REGISTERS_L3_ATTRIBUTES;
MemoryTable[1].PhysicalBase = SOC_REGISTERS_L3_PHYSICAL_BASE;
MemoryTable[1].VirtualBase = SOC_REGISTERS_L3_PHYSICAL_BASE;
MemoryTable[1].Length = SOC_REGISTERS_L3_PHYSICAL_LENGTH;
MemoryTable[1].Attributes = SOC_REGISTERS_L3_ATTRIBUTES;
// SOC Registers. L4 interconnects
MemoryTable[3].PhysicalBase = SOC_REGISTERS_L4_PHYSICAL_BASE;
MemoryTable[3].VirtualBase = SOC_REGISTERS_L4_PHYSICAL_BASE;
MemoryTable[3].Length = SOC_REGISTERS_L4_PHYSICAL_LENGTH;
MemoryTable[3].Attributes = SOC_REGISTERS_L4_ATTRIBUTES;
MemoryTable[2].PhysicalBase = SOC_REGISTERS_L4_PHYSICAL_BASE;
MemoryTable[2].VirtualBase = SOC_REGISTERS_L4_PHYSICAL_BASE;
MemoryTable[2].Length = SOC_REGISTERS_L4_PHYSICAL_LENGTH;
MemoryTable[2].Attributes = SOC_REGISTERS_L4_ATTRIBUTES;
// End of Table
MemoryTable[4].PhysicalBase = 0;
MemoryTable[4].VirtualBase = 0;
MemoryTable[4].Length = 0;
MemoryTable[4].Attributes = (ARM_MEMORY_REGION_ATTRIBUTES)0;
MemoryTable[3].PhysicalBase = 0;
MemoryTable[3].VirtualBase = 0;
MemoryTable[3].Length = 0;
MemoryTable[3].Attributes = (ARM_MEMORY_REGION_ATTRIBUTES)0;
ArmConfigureMmu (MemoryTable, &TranslationTableBase, &TranslationTableSize);