aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/ArmPkg/Drivers/CpuDxe
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/ArmPkg/Drivers/CpuDxe
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/ArmPkg/Drivers/CpuDxe')
-rw-r--r--roms/edk2/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c402
-rw-r--r--roms/edk2/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c511
-rw-r--r--roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.c283
-rw-r--r--roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.h146
-rw-r--r--roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.inf71
-rw-r--r--roms/edk2/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c211
-rw-r--r--roms/edk2/ArmPkg/Drivers/CpuDxe/CpuMpCore.c97
-rw-r--r--roms/edk2/ArmPkg/Drivers/CpuDxe/Exception.c98
8 files changed, 1819 insertions, 0 deletions
diff --git a/roms/edk2/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c b/roms/edk2/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
new file mode 100644
index 000000000..fca2d4f76
--- /dev/null
+++ b/roms/edk2/ArmPkg/Drivers/CpuDxe/AArch64/Mmu.c
@@ -0,0 +1,402 @@
+/*++
+
+Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
+Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
+Portions copyright (c) 2011-2013, ARM Ltd. All rights reserved.<BR>
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+--*/
+
+#include <Library/MemoryAllocationLib.h>
+#include "CpuDxe.h"
+
+#define INVALID_ENTRY ((UINT32)~0)
+
+#define MIN_T0SZ 16
+#define BITS_PER_LEVEL 9
+
+STATIC
+VOID
+GetRootTranslationTableInfo (
+ IN UINTN T0SZ,
+ OUT UINTN *RootTableLevel,
+ OUT UINTN *RootTableEntryCount
+ )
+{
+ *RootTableLevel = (T0SZ - MIN_T0SZ) / BITS_PER_LEVEL;
+ *RootTableEntryCount = TT_ENTRY_COUNT >> (T0SZ - MIN_T0SZ) % BITS_PER_LEVEL;
+}
+
+STATIC
+UINT64
+PageAttributeToGcdAttribute (
+ IN UINT64 PageAttributes
+ )
+{
+ UINT64 GcdAttributes;
+
+ switch (PageAttributes & TT_ATTR_INDX_MASK) {
+ case TT_ATTR_INDX_DEVICE_MEMORY:
+ GcdAttributes = EFI_MEMORY_UC;
+ break;
+ case TT_ATTR_INDX_MEMORY_NON_CACHEABLE:
+ GcdAttributes = EFI_MEMORY_WC;
+ break;
+ case TT_ATTR_INDX_MEMORY_WRITE_THROUGH:
+ GcdAttributes = EFI_MEMORY_WT;
+ break;
+ case TT_ATTR_INDX_MEMORY_WRITE_BACK:
+ GcdAttributes = EFI_MEMORY_WB;
+ break;
+ default:
+ DEBUG ((DEBUG_ERROR,
+ "PageAttributeToGcdAttribute: PageAttributes:0x%lX not supported.\n",
+ PageAttributes));
+ ASSERT (0);
+ // The Global Coherency Domain (GCD) value is defined as a bit set.
+ // Returning 0 means no attribute has been set.
+ GcdAttributes = 0;
+ }
+
+ // Determine protection attributes
+ if (((PageAttributes & TT_AP_MASK) == TT_AP_NO_RO) ||
+ ((PageAttributes & TT_AP_MASK) == TT_AP_RO_RO)) {
+ // Read only cases map to write-protect
+ GcdAttributes |= EFI_MEMORY_RO;
+ }
+
+ // Process eXecute Never attribute
+ if ((PageAttributes & (TT_PXN_MASK | TT_UXN_MASK)) != 0) {
+ GcdAttributes |= EFI_MEMORY_XP;
+ }
+
+ return GcdAttributes;
+}
+
+STATIC
+UINT64
+GetFirstPageAttribute (
+ IN UINT64 *FirstLevelTableAddress,
+ IN UINTN TableLevel
+ )
+{
+ UINT64 FirstEntry;
+
+ // Get the first entry of the table
+ FirstEntry = *FirstLevelTableAddress;
+
+ if ((TableLevel != 3) && (FirstEntry & TT_TYPE_MASK) == TT_TYPE_TABLE_ENTRY) {
+ // Only valid for Levels 0, 1 and 2
+
+ // Get the attribute of the subsequent table
+ return GetFirstPageAttribute ((UINT64*)(FirstEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE), TableLevel + 1);
+ } else if (((FirstEntry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY) ||
+ ((TableLevel == 3) && ((FirstEntry & TT_TYPE_MASK) == TT_TYPE_BLOCK_ENTRY_LEVEL3)))
+ {
+ return FirstEntry & TT_ATTR_INDX_MASK;
+ } else {
+ return INVALID_ENTRY;
+ }
+}
+
+STATIC
+UINT64
+GetNextEntryAttribute (
+ IN UINT64 *TableAddress,
+ IN UINTN EntryCount,
+ IN UINTN TableLevel,
+ IN UINT64 BaseAddress,
+ IN OUT UINT32 *PrevEntryAttribute,
+ IN OUT UINT64 *StartGcdRegion
+ )
+{
+ UINTN Index;
+ UINT64 Entry;
+ UINT32 EntryAttribute;
+ UINT32 EntryType;
+ EFI_STATUS Status;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+
+ // Get the memory space map from GCD
+ MemorySpaceMap = NULL;
+ Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
+ ASSERT_EFI_ERROR (Status);
+
+ // We cannot get more than 3-level page table
+ ASSERT (TableLevel <= 3);
+
+ // While the top level table might not contain TT_ENTRY_COUNT entries;
+ // the subsequent ones should be filled up
+ for (Index = 0; Index < EntryCount; Index++) {
+ Entry = TableAddress[Index];
+ EntryType = Entry & TT_TYPE_MASK;
+ EntryAttribute = Entry & TT_ATTR_INDX_MASK;
+
+ // If Entry is a Table Descriptor type entry then go through the sub-level table
+ if ((EntryType == TT_TYPE_BLOCK_ENTRY) ||
+ ((TableLevel == 3) && (EntryType == TT_TYPE_BLOCK_ENTRY_LEVEL3))) {
+ if ((*PrevEntryAttribute == INVALID_ENTRY) || (EntryAttribute != *PrevEntryAttribute)) {
+ if (*PrevEntryAttribute != INVALID_ENTRY) {
+ // Update GCD with the last region
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors,
+ *StartGcdRegion,
+ (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel))) - *StartGcdRegion,
+ PageAttributeToGcdAttribute (*PrevEntryAttribute));
+ }
+
+ // Start of the new region
+ *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel));
+ *PrevEntryAttribute = EntryAttribute;
+ } else {
+ continue;
+ }
+ } else if (EntryType == TT_TYPE_TABLE_ENTRY) {
+ // Table Entry type is only valid for Level 0, 1, 2
+ ASSERT (TableLevel < 3);
+
+ // Increase the level number and scan the sub-level table
+ GetNextEntryAttribute ((UINT64*)(Entry & TT_ADDRESS_MASK_DESCRIPTION_TABLE),
+ TT_ENTRY_COUNT, TableLevel + 1,
+ (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel))),
+ PrevEntryAttribute, StartGcdRegion);
+ } else {
+ if (*PrevEntryAttribute != INVALID_ENTRY) {
+ // Update GCD with the last region
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors,
+ *StartGcdRegion,
+ (BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel))) - *StartGcdRegion,
+ PageAttributeToGcdAttribute (*PrevEntryAttribute));
+
+ // Start of the new region
+ *StartGcdRegion = BaseAddress + (Index * TT_ADDRESS_AT_LEVEL(TableLevel));
+ *PrevEntryAttribute = INVALID_ENTRY;
+ }
+ }
+ }
+
+ FreePool (MemorySpaceMap);
+
+ return BaseAddress + (EntryCount * TT_ADDRESS_AT_LEVEL(TableLevel));
+}
+
+EFI_STATUS
+SyncCacheConfig (
+ IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
+ )
+{
+ EFI_STATUS Status;
+ UINT32 PageAttribute = 0;
+ UINT64 *FirstLevelTableAddress;
+ UINTN TableLevel;
+ UINTN TableCount;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN Tcr;
+ UINTN T0SZ;
+ UINT64 BaseAddressGcdRegion;
+ UINT64 EndAddressGcdRegion;
+
+ // 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
+ // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were
+ // a client) to update its copy of the attributes. This is bad architecture and should be replaced
+ // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.
+
+ // Obtain page table base
+ FirstLevelTableAddress = (UINT64*)(ArmGetTTBR0BaseAddress ());
+
+ // Get Translation Control Register value
+ Tcr = ArmGetTCR ();
+ // Get Address Region Size
+ T0SZ = Tcr & TCR_T0SZ_MASK;
+
+ // Get the level of the first table for the indicated Address Region Size
+ GetRootTranslationTableInfo (T0SZ, &TableLevel, &TableCount);
+
+ // First Attribute of the Page Tables
+ PageAttribute = GetFirstPageAttribute (FirstLevelTableAddress, TableLevel);
+
+ // We scan from the start of the memory map (ie: at the address 0x0)
+ BaseAddressGcdRegion = 0x0;
+ EndAddressGcdRegion = GetNextEntryAttribute (FirstLevelTableAddress,
+ TableCount, TableLevel,
+ BaseAddressGcdRegion,
+ &PageAttribute, &BaseAddressGcdRegion);
+
+ // Update GCD with the last region if valid
+ if (PageAttribute != INVALID_ENTRY) {
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors,
+ BaseAddressGcdRegion,
+ EndAddressGcdRegion - BaseAddressGcdRegion,
+ PageAttributeToGcdAttribute (PageAttribute));
+ }
+
+ FreePool (MemorySpaceMap);
+
+ return EFI_SUCCESS;
+}
+
+UINT64
+EfiAttributeToArmAttribute (
+ IN UINT64 EfiAttributes
+ )
+{
+ UINT64 ArmAttributes;
+
+ switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
+ case EFI_MEMORY_UC:
+ if (ArmReadCurrentEL () == AARCH64_EL2) {
+ ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY | TT_XN_MASK;
+ } else {
+ ArmAttributes = TT_ATTR_INDX_DEVICE_MEMORY | TT_UXN_MASK | TT_PXN_MASK;
+ }
+ break;
+ case EFI_MEMORY_WC:
+ ArmAttributes = TT_ATTR_INDX_MEMORY_NON_CACHEABLE;
+ break;
+ case EFI_MEMORY_WT:
+ ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_THROUGH | TT_SH_INNER_SHAREABLE;
+ break;
+ case EFI_MEMORY_WB:
+ ArmAttributes = TT_ATTR_INDX_MEMORY_WRITE_BACK | TT_SH_INNER_SHAREABLE;
+ break;
+ default:
+ ArmAttributes = TT_ATTR_INDX_MASK;
+ }
+
+ // Set the access flag to match the block attributes
+ ArmAttributes |= TT_AF;
+
+ // Determine protection attributes
+ if (EfiAttributes & EFI_MEMORY_RO) {
+ ArmAttributes |= TT_AP_RO_RO;
+ }
+
+ // Process eXecute Never attribute
+ if (EfiAttributes & EFI_MEMORY_XP) {
+ ArmAttributes |= TT_PXN_MASK;
+ }
+
+ return ArmAttributes;
+}
+
+// This function will recursively go down the page table to find the first block address linked to 'BaseAddress'.
+// And then the function will identify the size of the region that has the same page table attribute.
+EFI_STATUS
+GetMemoryRegionRec (
+ IN UINT64 *TranslationTable,
+ IN UINTN TableLevel,
+ IN UINT64 *LastBlockEntry,
+ IN OUT UINTN *BaseAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ )
+{
+ EFI_STATUS Status;
+ UINT64 *NextTranslationTable;
+ UINT64 *BlockEntry;
+ UINT64 BlockEntryType;
+ UINT64 EntryType;
+
+ if (TableLevel != 3) {
+ BlockEntryType = TT_TYPE_BLOCK_ENTRY;
+ } else {
+ BlockEntryType = TT_TYPE_BLOCK_ENTRY_LEVEL3;
+ }
+
+ // Find the block entry linked to the Base Address
+ BlockEntry = (UINT64*)TT_GET_ENTRY_FOR_ADDRESS (TranslationTable, TableLevel, *BaseAddress);
+ EntryType = *BlockEntry & TT_TYPE_MASK;
+
+ if ((TableLevel < 3) && (EntryType == TT_TYPE_TABLE_ENTRY)) {
+ NextTranslationTable = (UINT64*)(*BlockEntry & TT_ADDRESS_MASK_DESCRIPTION_TABLE);
+
+ // The entry is a page table, so we go to the next level
+ Status = GetMemoryRegionRec (
+ NextTranslationTable, // Address of the next level page table
+ TableLevel + 1, // Next Page Table level
+ (UINTN*)TT_LAST_BLOCK_ADDRESS(NextTranslationTable, TT_ENTRY_COUNT),
+ BaseAddress, RegionLength, RegionAttributes);
+
+ // In case of 'Success', it means the end of the block region has been found into the upper
+ // level translation table
+ if (!EFI_ERROR(Status)) {
+ return EFI_SUCCESS;
+ }
+
+ // Now we processed the table move to the next entry
+ BlockEntry++;
+ } else if (EntryType == BlockEntryType) {
+ // We have found the BlockEntry attached to the address. We save its start address (the start
+ // address might be before the 'BaseAddress') and attributes
+ *BaseAddress = *BaseAddress & ~(TT_ADDRESS_AT_LEVEL(TableLevel) - 1);
+ *RegionLength = 0;
+ *RegionAttributes = *BlockEntry & TT_ATTRIBUTES_MASK;
+ } else {
+ // We have an 'Invalid' entry
+ return EFI_UNSUPPORTED;
+ }
+
+ while (BlockEntry <= LastBlockEntry) {
+ if ((*BlockEntry & TT_ATTRIBUTES_MASK) == *RegionAttributes) {
+ *RegionLength = *RegionLength + TT_BLOCK_ENTRY_SIZE_AT_LEVEL(TableLevel);
+ } else {
+ // In case we have found the end of the region we return success
+ return EFI_SUCCESS;
+ }
+ BlockEntry++;
+ }
+
+ // If we have reached the end of the TranslationTable and we have not found the end of the region then
+ // we return EFI_NOT_FOUND.
+ // The caller will continue to look for the memory region at its level
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+GetMemoryRegion (
+ IN OUT UINTN *BaseAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ )
+{
+ EFI_STATUS Status;
+ UINT64 *TranslationTable;
+ UINTN TableLevel;
+ UINTN EntryCount;
+ UINTN T0SZ;
+
+ ASSERT ((BaseAddress != NULL) && (RegionLength != NULL) && (RegionAttributes != NULL));
+
+ TranslationTable = ArmGetTTBR0BaseAddress ();
+
+ T0SZ = ArmGetTCR () & TCR_T0SZ_MASK;
+ // Get the Table info from T0SZ
+ GetRootTranslationTableInfo (T0SZ, &TableLevel, &EntryCount);
+
+ Status = GetMemoryRegionRec (TranslationTable, TableLevel,
+ (UINTN*)TT_LAST_BLOCK_ADDRESS(TranslationTable, EntryCount),
+ BaseAddress, RegionLength, RegionAttributes);
+
+ // If the region continues up to the end of the root table then GetMemoryRegionRec()
+ // will return EFI_NOT_FOUND
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_SUCCESS;
+ } else {
+ return Status;
+ }
+}
diff --git a/roms/edk2/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c b/roms/edk2/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
new file mode 100644
index 000000000..6fb5112a1
--- /dev/null
+++ b/roms/edk2/ArmPkg/Drivers/CpuDxe/Arm/Mmu.c
@@ -0,0 +1,511 @@
+/*++
+
+Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>
+Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>
+Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+--*/
+
+#include <Library/MemoryAllocationLib.h>
+#include "CpuDxe.h"
+
+EFI_STATUS
+SectionToGcdAttributes (
+ IN UINT32 SectionAttributes,
+ OUT UINT64 *GcdAttributes
+ )
+{
+ *GcdAttributes = 0;
+
+ // determine cacheability attributes
+ switch(SectionAttributes & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) {
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED:
+ *GcdAttributes |= EFI_MEMORY_UC;
+ break;
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE:
+ *GcdAttributes |= EFI_MEMORY_UC;
+ break;
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:
+ *GcdAttributes |= EFI_MEMORY_WT;
+ break;
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_NO_ALLOC:
+ *GcdAttributes |= EFI_MEMORY_WB;
+ break;
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE:
+ *GcdAttributes |= EFI_MEMORY_WC;
+ break;
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC:
+ *GcdAttributes |= EFI_MEMORY_WB;
+ break;
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_SHAREABLE_DEVICE:
+ *GcdAttributes |= EFI_MEMORY_UC;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ // determine protection attributes
+ switch(SectionAttributes & TT_DESCRIPTOR_SECTION_AP_MASK) {
+ case TT_DESCRIPTOR_SECTION_AP_NO_NO: // no read, no write
+ //*GcdAttributes |= EFI_MEMORY_RO | EFI_MEMORY_RP;
+ break;
+
+ case TT_DESCRIPTOR_SECTION_AP_RW_NO:
+ case TT_DESCRIPTOR_SECTION_AP_RW_RW:
+ // normal read/write access, do not add additional attributes
+ break;
+
+ // read only cases map to write-protect
+ case TT_DESCRIPTOR_SECTION_AP_RO_NO:
+ case TT_DESCRIPTOR_SECTION_AP_RO_RO:
+ *GcdAttributes |= EFI_MEMORY_RO;
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ // now process eXectue Never attribute
+ if ((SectionAttributes & TT_DESCRIPTOR_SECTION_XN_MASK) != 0 ) {
+ *GcdAttributes |= EFI_MEMORY_XP;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+PageToGcdAttributes (
+ IN UINT32 PageAttributes,
+ OUT UINT64 *GcdAttributes
+ )
+{
+ *GcdAttributes = 0;
+
+ // determine cacheability attributes
+ switch(PageAttributes & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) {
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED:
+ *GcdAttributes |= EFI_MEMORY_UC;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE:
+ *GcdAttributes |= EFI_MEMORY_UC;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:
+ *GcdAttributes |= EFI_MEMORY_WT;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_NO_ALLOC:
+ *GcdAttributes |= EFI_MEMORY_WB;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE:
+ *GcdAttributes |= EFI_MEMORY_WC;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC:
+ *GcdAttributes |= EFI_MEMORY_WB;
+ break;
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_SHAREABLE_DEVICE:
+ *GcdAttributes |= EFI_MEMORY_UC;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ // determine protection attributes
+ switch(PageAttributes & TT_DESCRIPTOR_PAGE_AP_MASK) {
+ case TT_DESCRIPTOR_PAGE_AP_NO_NO: // no read, no write
+ //*GcdAttributes |= EFI_MEMORY_RO | EFI_MEMORY_RP;
+ break;
+
+ case TT_DESCRIPTOR_PAGE_AP_RW_NO:
+ case TT_DESCRIPTOR_PAGE_AP_RW_RW:
+ // normal read/write access, do not add additional attributes
+ break;
+
+ // read only cases map to write-protect
+ case TT_DESCRIPTOR_PAGE_AP_RO_NO:
+ case TT_DESCRIPTOR_PAGE_AP_RO_RO:
+ *GcdAttributes |= EFI_MEMORY_RO;
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ // now process eXectue Never attribute
+ if ((PageAttributes & TT_DESCRIPTOR_PAGE_XN_MASK) != 0 ) {
+ *GcdAttributes |= EFI_MEMORY_XP;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SyncCacheConfigPage (
+ IN UINT32 SectionIndex,
+ IN UINT32 FirstLevelDescriptor,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN OUT EFI_PHYSICAL_ADDRESS *NextRegionBase,
+ IN OUT UINT64 *NextRegionLength,
+ IN OUT UINT32 *NextSectionAttributes
+ )
+{
+ EFI_STATUS Status;
+ UINT32 i;
+ volatile ARM_PAGE_TABLE_ENTRY *SecondLevelTable;
+ UINT32 NextPageAttributes = 0;
+ UINT32 PageAttributes = 0;
+ UINT32 BaseAddress;
+ UINT64 GcdAttributes;
+
+ // Get the Base Address from FirstLevelDescriptor;
+ BaseAddress = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(SectionIndex << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
+
+ // Convert SectionAttributes into PageAttributes
+ NextPageAttributes =
+ TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(*NextSectionAttributes,0) |
+ TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(*NextSectionAttributes);
+
+ // obtain page table base
+ SecondLevelTable = (ARM_PAGE_TABLE_ENTRY *)(FirstLevelDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
+
+ for (i=0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) {
+ if ((SecondLevelTable[i] & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {
+ // extract attributes (cacheability and permissions)
+ PageAttributes = SecondLevelTable[i] & (TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK | TT_DESCRIPTOR_PAGE_AP_MASK);
+
+ if (NextPageAttributes == 0) {
+ // start on a new region
+ *NextRegionLength = 0;
+ *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
+ NextPageAttributes = PageAttributes;
+ } else if (PageAttributes != NextPageAttributes) {
+ // Convert Section Attributes into GCD Attributes
+ Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);
+ ASSERT_EFI_ERROR (Status);
+
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);
+
+ // start on a new region
+ *NextRegionLength = 0;
+ *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
+ NextPageAttributes = PageAttributes;
+ }
+ } else if (NextPageAttributes != 0) {
+ // Convert Page Attributes into GCD Attributes
+ Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);
+ ASSERT_EFI_ERROR (Status);
+
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);
+
+ *NextRegionLength = 0;
+ *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);
+ NextPageAttributes = 0;
+ }
+ *NextRegionLength += TT_DESCRIPTOR_PAGE_SIZE;
+ }
+
+ // Convert back PageAttributes into SectionAttributes
+ *NextSectionAttributes =
+ TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY(NextPageAttributes,0) |
+ TT_DESCRIPTOR_CONVERT_TO_SECTION_AP(NextPageAttributes);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SyncCacheConfig (
+ IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
+ )
+{
+ EFI_STATUS Status;
+ UINT32 i;
+ EFI_PHYSICAL_ADDRESS NextRegionBase;
+ UINT64 NextRegionLength;
+ UINT32 NextSectionAttributes = 0;
+ UINT32 SectionAttributes = 0;
+ UINT64 GcdAttributes;
+ volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+
+
+ DEBUG ((DEBUG_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
+ // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were
+ // a client) to update its copy of the attributes. This is bad architecture and should be replaced
+ // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.
+
+ // obtain page table base
+ FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)(ArmGetTTBR0BaseAddress ());
+
+ // Get the first region
+ NextSectionAttributes = FirstLevelTable[0] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
+
+ // iterate through each 1MB descriptor
+ NextRegionBase = NextRegionLength = 0;
+ for (i=0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) {
+ if ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {
+ // extract attributes (cacheability and permissions)
+ SectionAttributes = FirstLevelTable[i] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);
+
+ if (NextSectionAttributes == 0) {
+ // start on a new region
+ NextRegionLength = 0;
+ NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
+ NextSectionAttributes = SectionAttributes;
+ } else if (SectionAttributes != NextSectionAttributes) {
+ // Convert Section Attributes into GCD Attributes
+ Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
+ ASSERT_EFI_ERROR (Status);
+
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
+
+ // start on a new region
+ NextRegionLength = 0;
+ NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
+ NextSectionAttributes = SectionAttributes;
+ }
+ NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;
+ } else if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(FirstLevelTable[i])) {
+ // In this case any bits set in the 'NextSectionAttributes' are garbage and were set from
+ // bits that are actually part of the pagetable address. We clear it out to zero so that
+ // the SyncCacheConfigPage will use the page attributes instead of trying to convert the
+ // section attributes into page attributes
+ NextSectionAttributes = 0;
+ Status = SyncCacheConfigPage (
+ i,FirstLevelTable[i],
+ NumberOfDescriptors, MemorySpaceMap,
+ &NextRegionBase,&NextRegionLength,&NextSectionAttributes);
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ // We do not support yet 16MB sections
+ ASSERT ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) != TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION);
+
+ // start on a new region
+ if (NextSectionAttributes != 0) {
+ // Convert Section Attributes into GCD Attributes
+ Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
+ ASSERT_EFI_ERROR (Status);
+
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
+
+ NextRegionLength = 0;
+ NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);
+ NextSectionAttributes = 0;
+ }
+ NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;
+ }
+ } // section entry loop
+
+ if (NextSectionAttributes != 0) {
+ // Convert Section Attributes into GCD Attributes
+ Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);
+ ASSERT_EFI_ERROR (Status);
+
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);
+ }
+
+ FreePool (MemorySpaceMap);
+
+ return EFI_SUCCESS;
+}
+
+UINT64
+EfiAttributeToArmAttribute (
+ IN UINT64 EfiAttributes
+ )
+{
+ UINT64 ArmAttributes;
+
+ switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
+ case EFI_MEMORY_UC:
+ // Map to strongly ordered
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0
+ break;
+
+ case EFI_MEMORY_WC:
+ // Map to normal non-cachable
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0
+ break;
+
+ case EFI_MEMORY_WT:
+ // Write through with no-allocate
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0
+ break;
+
+ case EFI_MEMORY_WB:
+ // Write back (with allocate)
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1
+ break;
+
+ case EFI_MEMORY_UCE:
+ default:
+ ArmAttributes = TT_DESCRIPTOR_SECTION_TYPE_FAULT;
+ break;
+ }
+
+ // Determine protection attributes
+ if (EfiAttributes & EFI_MEMORY_RO) {
+ ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RO_RO;
+ } else {
+ ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RW_RW;
+ }
+
+ // Determine eXecute Never attribute
+ if (EfiAttributes & EFI_MEMORY_XP) {
+ ArmAttributes |= TT_DESCRIPTOR_SECTION_XN_MASK;
+ }
+
+ return ArmAttributes;
+}
+
+EFI_STATUS
+GetMemoryRegionPage (
+ IN UINT32 *PageTable,
+ IN OUT UINTN *BaseAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ )
+{
+ UINT32 PageAttributes;
+ UINT32 TableIndex;
+ UINT32 PageDescriptor;
+
+ // Convert the section attributes into page attributes
+ PageAttributes = ConvertSectionAttributesToPageAttributes (*RegionAttributes, 0);
+
+ // Calculate index into first level translation table for start of modification
+ TableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;
+ ASSERT (TableIndex < TRANSLATION_TABLE_PAGE_COUNT);
+
+ // Go through the page table to find the end of the section
+ for (; TableIndex < TRANSLATION_TABLE_PAGE_COUNT; TableIndex++) {
+ // Get the section at the given index
+ PageDescriptor = PageTable[TableIndex];
+
+ if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_FAULT) {
+ // Case: End of the boundary of the region
+ return EFI_SUCCESS;
+ } else if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_PAGE) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {
+ if ((PageDescriptor & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK) == PageAttributes) {
+ *RegionLength = *RegionLength + TT_DESCRIPTOR_PAGE_SIZE;
+ } else {
+ // Case: End of the boundary of the region
+ return EFI_SUCCESS;
+ }
+ } else {
+ // We do not support Large Page yet. We return EFI_SUCCESS that means end of the region.
+ ASSERT(0);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+GetMemoryRegion (
+ IN OUT UINTN *BaseAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TableIndex;
+ UINT32 PageAttributes;
+ UINT32 PageTableIndex;
+ UINT32 SectionDescriptor;
+ ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;
+ UINT32 *PageTable;
+
+ // Initialize the arguments
+ *RegionLength = 0;
+
+ // Obtain page table base
+ FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();
+
+ // Calculate index into first level translation table for start of modification
+ TableIndex = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (*BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;
+ ASSERT (TableIndex < TRANSLATION_TABLE_SECTION_COUNT);
+
+ // Get the section at the given index
+ SectionDescriptor = FirstLevelTable[TableIndex];
+ if (!SectionDescriptor) {
+ return EFI_NOT_FOUND;
+ }
+
+ // If 'BaseAddress' belongs to the section then round it to the section boundary
+ if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||
+ ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION))
+ {
+ *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;
+ *RegionAttributes = SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK;
+ } else {
+ // Otherwise, we round it to the page boundary
+ *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK;
+
+ // Get the attribute at the page table level (Level 2)
+ PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
+
+ // Calculate index into first level translation table for start of modification
+ PageTableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;
+ ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);
+
+ PageAttributes = PageTable[PageTableIndex] & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK;
+ *RegionAttributes = TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY (PageAttributes, 0) |
+ TT_DESCRIPTOR_CONVERT_TO_SECTION_AP (PageAttributes);
+ }
+
+ for (;TableIndex < TRANSLATION_TABLE_SECTION_COUNT; TableIndex++) {
+ // Get the section at the given index
+ SectionDescriptor = FirstLevelTable[TableIndex];
+
+ // If the entry is a level-2 page table then we scan it to find the end of the region
+ if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE (SectionDescriptor)) {
+ // Extract the page table location from the descriptor
+ PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);
+
+ // Scan the page table to find the end of the region.
+ Status = GetMemoryRegionPage (PageTable, BaseAddress, RegionLength, RegionAttributes);
+
+ // If we have found the end of the region (Status == EFI_SUCCESS) then we exit the for-loop
+ if (Status == EFI_SUCCESS) {
+ break;
+ }
+ } else if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||
+ ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION)) {
+ if ((SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK) != *RegionAttributes) {
+ // If the attributes of the section differ from the one targeted then we exit the loop
+ break;
+ } else {
+ *RegionLength = *RegionLength + TT_DESCRIPTOR_SECTION_SIZE;
+ }
+ } else {
+ // If we are on an invalid section then it means it is the end of our section.
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.c
new file mode 100644
index 000000000..082ef30fb
--- /dev/null
+++ b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.c
@@ -0,0 +1,283 @@
+/** @file
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2011, ARM Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuDxe.h"
+
+#include <Guid/IdleLoopEvent.h>
+
+BOOLEAN mIsFlushingGCD;
+
+/**
+ 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_UNSUPPORTED 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 (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ )
+{
+
+ switch (FlushType) {
+ case EfiCpuFlushTypeWriteBack:
+ WriteBackDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+ break;
+ case EfiCpuFlushTypeInvalidate:
+ InvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+ break;
+ case EfiCpuFlushTypeWriteBackInvalidate:
+ WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)Start, (UINTN)Length);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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 (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ ArmEnableInterrupts ();
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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 (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ ArmDisableInterrupts ();
+
+ 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 (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ )
+{
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *State = ArmGetInterruptState();
+ 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 (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return RegisterInterruptHandler (InterruptType, InterruptHandler);
+}
+
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Callback function for idle events.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+IdleLoopEventCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ CpuSleep ();
+}
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE mCpuHandle = NULL;
+EFI_CPU_ARCH_PROTOCOL mCpu = {
+ CpuFlushCpuDataCache,
+ CpuEnableInterrupt,
+ CpuDisableInterrupt,
+ CpuGetInterruptState,
+ CpuInit,
+ CpuRegisterInterruptHandler,
+ CpuGetTimerValue,
+ CpuSetMemoryAttributes,
+ 0, // NumberOfTimers
+ 2048, // DmaBufferAlignment
+};
+
+STATIC
+VOID
+InitializeDma (
+ IN OUT EFI_CPU_ARCH_PROTOCOL *CpuArchProtocol
+ )
+{
+ CpuArchProtocol->DmaBufferAlignment = ArmCacheWritebackGranule ();
+}
+
+EFI_STATUS
+CpuDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT IdleLoopEvent;
+
+ InitializeExceptions (&mCpu);
+
+ InitializeDma (&mCpu);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mCpuHandle,
+ &gEfiCpuArchProtocolGuid, &mCpu,
+ 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
+ //
+ mIsFlushingGCD = TRUE;
+ SyncCacheConfig (&mCpu);
+ mIsFlushingGCD = FALSE;
+
+ // If the platform is a MPCore system then install the Configuration Table describing the
+ // secondary core states
+ if (ArmIsMpCore()) {
+ PublishArmProcessorTable();
+ }
+
+ //
+ // Setup a callback for idle events
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ IdleLoopEventCallback,
+ NULL,
+ &gIdleLoopEventGuid,
+ &IdleLoopEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.h
new file mode 100644
index 000000000..3fe5c24d5
--- /dev/null
+++ b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.h
@@ -0,0 +1,146 @@
+/** @file
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __CPU_DXE_ARM_EXCEPTION_H__
+#define __CPU_DXE_ARM_EXCEPTION_H__
+
+#include <Uefi.h>
+
+#include <Library/ArmLib.h>
+#include <Library/ArmMmuLib.h>
+#include <Library/BaseMemoryLib.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 <Library/DefaultExceptionHandlerLib.h>
+#include <Library/DebugLib.h>
+
+#include <Guid/DebugImageInfoTable.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/DebugSupport.h>
+#include <Protocol/LoadedImage.h>
+
+extern BOOLEAN mIsFlushingGCD;
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+ are enabled and FALSE if interrupts are disabled.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterDebuggerInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+
+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
+ );
+
+/**
+ * Publish ARM Processor Data table in UEFI SYSTEM Table.
+ * @param HobStart Pointer to the beginning of the HOB List from PEI.
+ *
+ * Description : This function iterates through HOB list and finds ARM processor Table Entry HOB.
+ * If the ARM processor Table Entry HOB is found, the HOB data is copied to run-time memory
+ * and a pointer is assigned to it in ARM processor table. Then the ARM processor table is
+ * installed in EFI configuration table.
+**/
+VOID
+EFIAPI
+PublishArmProcessorTable(
+ VOID
+ );
+
+// The ARM Attributes might be defined on 64-bit (case of the long format description table)
+UINT64
+EfiAttributeToArmAttribute (
+ IN UINT64 EfiAttributes
+ );
+
+EFI_STATUS
+GetMemoryRegion (
+ IN OUT UINTN *BaseAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ );
+
+EFI_STATUS
+SetGcdMemorySpaceAttributes (
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+#endif // __CPU_DXE_ARM_EXCEPTION_H__
diff --git a/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
new file mode 100644
index 000000000..e5549fc71
--- /dev/null
+++ b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
@@ -0,0 +1,71 @@
+#/** @file
+#
+# DXE CPU driver
+#
+# Copyright (c) 2009, Apple Inc. All rights reserved.<BR>
+# Copyright (c) 2011-2013, ARM Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ArmCpuDxe
+ FILE_GUID = B8D9777E-D72A-451F-9BDB-BAFB52A68415
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = CpuDxeInitialize
+
+[Sources.Common]
+ CpuDxe.c
+ CpuDxe.h
+ CpuMpCore.c
+ CpuMmuCommon.c
+ Exception.c
+
+[Sources.ARM]
+ Arm/Mmu.c
+
+[Sources.AARCH64]
+ AArch64/Mmu.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ ArmLib
+ ArmMmuLib
+ BaseMemoryLib
+ CacheMaintenanceLib
+ CpuLib
+ CpuExceptionHandlerLib
+ DebugLib
+ DefaultExceptionHandlerLib
+ DxeServicesTableLib
+ HobLib
+ PeCoffGetEntryPointLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiCpuArchProtocolGuid
+
+[Guids]
+ gEfiDebugImageInfoTableGuid
+ gArmMpCoreInfoGuid
+ gIdleLoopEventGuid
+ gEfiVectorHandoffTableGuid
+
+[Pcd.common]
+ gArmTokenSpaceGuid.PcdVFPEnabled
+
+[FeaturePcd.common]
+ gArmTokenSpaceGuid.PcdDebuggerExceptionSupport
+
+[Depex]
+ gHardwareInterruptProtocolGuid OR gHardwareInterrupt2ProtocolGuid
diff --git a/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
new file mode 100644
index 000000000..cdb1d6786
--- /dev/null
+++ b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
@@ -0,0 +1,211 @@
+/** @file
+*
+* Copyright (c) 2013, ARM Limited. All rights reserved.
+* Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include "CpuDxe.h"
+
+/**
+ 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;
+
+ DEBUG ((DEBUG_GCD, "SetGcdMemorySpaceAttributes[0x%lX; 0x%lX] = 0x%lX\n",
+ BaseAddress, BaseAddress + Length, Attributes));
+
+ // We do not support a smaller granularity than 4KB on ARM Architecture
+ if ((Length & EFI_PAGE_MASK) != 0) {
+ DEBUG ((DEBUG_WARN,
+ "Warning: We do not support smaller granularity than 4KB on ARM Architecture (passed length: 0x%lX).\n",
+ Length));
+ }
+
+ //
+ // 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;
+}
+
+/**
+ This function modifies the attributes for the memory region specified by BaseAddress and
+ Length from their current attributes to the attributes specified by Attributes.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 EfiAttributes
+ )
+{
+ EFI_STATUS Status;
+ UINTN ArmAttributes;
+ UINTN RegionBaseAddress;
+ UINTN RegionLength;
+ UINTN RegionArmAttributes;
+
+ if (mIsFlushingGCD) {
+ return EFI_SUCCESS;
+ }
+
+ if ((BaseAddress & (SIZE_4KB - 1)) != 0) {
+ // Minimum granularity is SIZE_4KB (4KB on ARM)
+ DEBUG ((DEBUG_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_4KB\n", BaseAddress, Length, EfiAttributes));
+ return EFI_UNSUPPORTED;
+ }
+
+ // Convert the 'Attribute' into ARM Attribute
+ ArmAttributes = EfiAttributeToArmAttribute (EfiAttributes);
+
+ // Get the region starting from 'BaseAddress' and its 'Attribute'
+ RegionBaseAddress = BaseAddress;
+ Status = GetMemoryRegion (&RegionBaseAddress, &RegionLength, &RegionArmAttributes);
+
+ // Data & Instruction Caches are flushed when we set new memory attributes.
+ // So, we only set the attributes if the new region is different.
+ if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) ||
+ ((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
+ {
+ return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes);
+ } else {
+ return EFI_SUCCESS;
+ }
+}
diff --git a/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuMpCore.c b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuMpCore.c
new file mode 100644
index 000000000..d16ae3979
--- /dev/null
+++ b/roms/edk2/ArmPkg/Drivers/CpuDxe/CpuMpCore.c
@@ -0,0 +1,97 @@
+/** @file
+*
+* Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/ArmMpCoreInfo.h>
+
+ARM_PROCESSOR_TABLE mArmProcessorTableTemplate = {
+ {
+ EFI_ARM_PROCESSOR_TABLE_SIGNATURE,
+ 0,
+ EFI_ARM_PROCESSOR_TABLE_REVISION,
+ EFI_ARM_PROCESSOR_TABLE_OEM_ID,
+ EFI_ARM_PROCESSOR_TABLE_OEM_TABLE_ID,
+ EFI_ARM_PROCESSOR_TABLE_OEM_REVISION,
+ EFI_ARM_PROCESSOR_TABLE_CREATOR_ID,
+ EFI_ARM_PROCESSOR_TABLE_CREATOR_REVISION,
+ { 0 },
+ 0
+ }, //ARM Processor table header
+ 0, // Number of entries in ARM processor Table
+ NULL // ARM Processor Table
+};
+
+/** Publish ARM Processor Data table in UEFI SYSTEM Table.
+ * @param: HobStart Pointer to the beginning of the HOB List from PEI.
+ *
+ * Description : This function iterates through HOB list and finds ARM processor Table Entry HOB.
+ * If the ARM processor Table Entry HOB is found, the HOB data is copied to run-time memory
+ * and a pointer is assigned to it in ARM processor table. Then the ARM processor table is
+ * installed in EFI configuration table.
+**/
+VOID
+EFIAPI
+PublishArmProcessorTable (
+ VOID
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+
+ Hob.Raw = GetHobList ();
+
+ // Iterate through the HOBs and find if there is ARM PROCESSOR ENTRY HOB
+ for (; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
+ // Check for Correct HOB type
+ if ((GET_HOB_TYPE (Hob)) == EFI_HOB_TYPE_GUID_EXTENSION) {
+ // Check for correct GUID type
+ if (CompareGuid(&(Hob.Guid->Name), &gArmMpCoreInfoGuid)) {
+ ARM_PROCESSOR_TABLE *ArmProcessorTable;
+ EFI_STATUS Status;
+
+ // Allocate Runtime memory for ARM processor table
+ ArmProcessorTable = (ARM_PROCESSOR_TABLE*)AllocateRuntimePool(sizeof(ARM_PROCESSOR_TABLE));
+
+ // Check if the memory allocation is successful or not
+ ASSERT(NULL != ArmProcessorTable);
+
+ // Set ARM processor table to default values
+ CopyMem(ArmProcessorTable,&mArmProcessorTableTemplate,sizeof(ARM_PROCESSOR_TABLE));
+
+ // Fill in Length fields of ARM processor table
+ ArmProcessorTable->Header.Length = sizeof(ARM_PROCESSOR_TABLE);
+ ArmProcessorTable->Header.DataLen = GET_GUID_HOB_DATA_SIZE(Hob);
+
+ // Fill in Identifier(ARM processor table GUID)
+ ArmProcessorTable->Header.Identifier = gArmMpCoreInfoGuid;
+
+ // Set Number of ARM core entries in the Table
+ ArmProcessorTable->NumberOfEntries = GET_GUID_HOB_DATA_SIZE(Hob)/sizeof(ARM_CORE_INFO);
+
+ // Allocate runtime memory for ARM processor Table entries
+ ArmProcessorTable->ArmCpus = (ARM_CORE_INFO*)AllocateRuntimePool (
+ ArmProcessorTable->NumberOfEntries * sizeof(ARM_CORE_INFO));
+
+ // Check if the memory allocation is successful or not
+ ASSERT(NULL != ArmProcessorTable->ArmCpus);
+
+ // Copy ARM Processor Table data from HOB list to newly allocated memory
+ CopyMem(ArmProcessorTable->ArmCpus,GET_GUID_HOB_DATA(Hob), ArmProcessorTable->Header.DataLen);
+
+ // Install the ARM Processor table into EFI system configuration table
+ Status = gBS->InstallConfigurationTable (&gArmMpCoreInfoGuid, ArmProcessorTable);
+
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+}
diff --git a/roms/edk2/ArmPkg/Drivers/CpuDxe/Exception.c b/roms/edk2/ArmPkg/Drivers/CpuDxe/Exception.c
new file mode 100644
index 000000000..50ed50ebb
--- /dev/null
+++ b/roms/edk2/ArmPkg/Drivers/CpuDxe/Exception.c
@@ -0,0 +1,98 @@
+/** @file
+
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+ Portions Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuDxe.h"
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Guid/VectorHandoffTable.h>
+
+EFI_STATUS
+InitializeExceptions (
+ IN EFI_CPU_ARCH_PROTOCOL *Cpu
+ ) {
+ EFI_STATUS Status;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
+ EFI_VECTOR_HANDOFF_INFO *VectorInfo;
+ BOOLEAN IrqEnabled;
+ BOOLEAN FiqEnabled;
+
+ VectorInfo = (EFI_VECTOR_HANDOFF_INFO *)NULL;
+ Status = EfiGetSystemConfigurationTable(&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
+ if (Status == EFI_SUCCESS && VectorInfoList != NULL) {
+ VectorInfo = VectorInfoList;
+ }
+
+ // initialize the CpuExceptionHandlerLib so we take over the exception vector table from the DXE Core
+ InitializeCpuExceptionHandlers(VectorInfo);
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Disable interrupts
+ //
+ Cpu->GetInterruptState (Cpu, &IrqEnabled);
+ Cpu->DisableInterrupt (Cpu);
+
+ //
+ // EFI does not use the FIQ, but a debugger might so we must disable
+ // as we take over the exception vectors.
+ //
+ FiqEnabled = ArmGetFiqState ();
+ ArmDisableFiq ();
+
+ if (FiqEnabled) {
+ ArmEnableFiq ();
+ }
+
+ if (IrqEnabled) {
+ //
+ // Restore interrupt state
+ //
+ Status = Cpu->EnableInterrupt (Cpu);
+ }
+
+ //
+ // On a DEBUG build, unmask SErrors so they are delivered right away rather
+ // than when the OS unmasks them. This gives us a better chance of figuring
+ // out the cause.
+ //
+ DEBUG_CODE (
+ ArmEnableAsynchronousAbort ();
+ );
+
+ return Status;
+}
+
+/**
+This function registers and enables the handler specified by InterruptHandler for a processor
+interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+The installed handler is called once for each processor interrupt or exception.
+
+@param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
+are enabled and FALSE if interrupts are disabled.
+@param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+when a processor interrupt occurs. If this parameter is NULL, then the handler
+will be uninstalled.
+
+@retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+previously installed.
+@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+previously installed.
+@retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler(
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ ) {
+ // pass down to CpuExceptionHandlerLib
+ return (EFI_STATUS)RegisterCpuInterruptHandler(InterruptType, InterruptHandler);
+}