diff options
author | AJFISH <AJFISH@6f19259b-4bc3-4df7-8a09-765794883524> | 2010-01-14 03:25:08 +0000 |
---|---|---|
committer | AJFISH <AJFISH@6f19259b-4bc3-4df7-8a09-765794883524> | 2010-01-14 03:25:08 +0000 |
commit | f659880bfa42ded20a00d3e371c998b42dcdd0fd (patch) | |
tree | 1f5c258cb3169db81493b2b0d43a2bae347d5417 /ArmPkg | |
parent | 66b631f5e0beb4792a0f54c31aab5b08b97dc329 (diff) | |
download | edk2-f659880bfa42ded20a00d3e371c998b42dcdd0fd.zip edk2-f659880bfa42ded20a00d3e371c998b42dcdd0fd.tar.gz edk2-f659880bfa42ded20a00d3e371c998b42dcdd0fd.tar.bz2 |
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
Diffstat (limited to 'ArmPkg')
-rw-r--r-- | ArmPkg/ArmPkg.dsc | 1 | ||||
-rw-r--r-- | ArmPkg/Drivers/CpuDxe/CpuDxe.c | 113 | ||||
-rw-r--r-- | ArmPkg/Drivers/CpuDxe/CpuDxe.h | 39 | ||||
-rw-r--r-- | ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 9 | ||||
-rw-r--r-- | ArmPkg/Drivers/CpuDxe/Exception.c | 114 | ||||
-rw-r--r-- | ArmPkg/Drivers/CpuDxe/Mmu.c | 231 | ||||
-rw-r--r-- | ArmPkg/Include/Library/ArmLib.h | 1 | ||||
-rw-r--r-- | ArmPkg/Include/Protocol/VirtualUncachedPages.h | 4 | ||||
-rw-r--r-- | ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.c | 12 | ||||
-rw-r--r-- | ArmPkg/Library/ArmLib/Common/ArmLibSupport.asm | 2 | ||||
-rw-r--r-- | ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.c | 4 | ||||
-rw-r--r-- | ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.inf | 10 |
12 files changed, 461 insertions, 79 deletions
diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc index 7cd6018..7001f28 100644 --- a/ArmPkg/ArmPkg.dsc +++ b/ArmPkg/ArmPkg.dsc @@ -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] # diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c index d3f0ff5..a4ac97c 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c @@ -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;
}
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h index 36133e1..8a71075 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h @@ -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 \
+ )
/**
@@ -84,8 +99,30 @@ 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__
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf index f22b255..d4b4945 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf @@ -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
diff --git a/ArmPkg/Drivers/CpuDxe/Exception.c b/ArmPkg/Drivers/CpuDxe/Exception.c index 9910bd2..1f84e31 100644 --- a/ArmPkg/Drivers/CpuDxe/Exception.c +++ b/ArmPkg/Drivers/CpuDxe/Exception.c @@ -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
//
diff --git a/ArmPkg/Drivers/CpuDxe/Mmu.c b/ArmPkg/Drivers/CpuDxe/Mmu.c index c6b5c08..a0977dd 100644 --- a/ArmPkg/Drivers/CpuDxe/Mmu.c +++ b/ArmPkg/Drivers/CpuDxe/Mmu.c @@ -17,6 +17,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
};
diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h index 5cadb3c..371075b 100644 --- a/ArmPkg/Include/Library/ArmLib.h +++ b/ArmPkg/Include/Library/ArmLib.h @@ -263,6 +263,7 @@ ArmSetTranslationTableBaseAddress ( VOID * EFIAPI ArmGetTranslationTableBaseAddress ( + VOID ); VOID diff --git a/ArmPkg/Include/Protocol/VirtualUncachedPages.h b/ArmPkg/Include/Protocol/VirtualUncachedPages.h index 32deec2..cd39796 100644 --- a/ArmPkg/Include/Protocol/VirtualUncachedPages.h +++ b/ArmPkg/Include/Protocol/VirtualUncachedPages.h @@ -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
\ No newline at end of file +#endif
diff --git a/ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.c b/ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.c index 7da6b42..b5754e6 100644 --- a/ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.c +++ b/ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.c @@ -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; } diff --git a/ArmPkg/Library/ArmLib/Common/ArmLibSupport.asm b/ArmPkg/Library/ArmLib/Common/ArmLibSupport.asm index ecae8a3..630c72f 100644 --- a/ArmPkg/Library/ArmLib/Common/ArmLibSupport.asm +++ b/ArmPkg/Library/ArmLib/Common/ArmLibSupport.asm @@ -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 diff --git a/ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.c b/ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.c index b4c1c5f..80e7c8c 100644 --- a/ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.c +++ b/ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.c @@ -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);
diff --git a/ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.inf b/ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.inf index 102ef78..9cf2901 100644 --- a/ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.inf +++ b/ArmPkg/Library/DebugUncachedMemoryAllocationLib/DebugUncachedMemoryAllocationLib.inf @@ -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
\ No newline at end of file + gEfiCpuArchProtocolGuid AND gVirtualUncachedPagesProtocolGuid
\ No newline at end of file |