From: oliviermartin Date: Tue, 12 Mar 2013 00:49:42 +0000 (+0000) Subject: ArmPkg: Moved ARMv7 specific files to a 'Arm' subdirectory X-Git-Tag: edk2-stable201903~12665 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=2614b0c474614b97d3a0378171fa2d9b9ae2aa85;hp=6f711615bacf7ce3bc42507cba87bc0adcda0461 ArmPkg: Moved ARMv7 specific files to a 'Arm' subdirectory Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@14180 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/ArmPkg/Drivers/CpuDxe/ArmV6/Exception.c b/ArmPkg/Drivers/CpuDxe/ArmV6/Exception.c new file mode 100644 index 0000000000..55a7132193 --- /dev/null +++ b/ArmPkg/Drivers/CpuDxe/ArmV6/Exception.c @@ -0,0 +1,230 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuDxe.h" + +//FIXME: Will not compile on non-ARMv7 builds +#include + +VOID +ExceptionHandlersStart ( + VOID + ); + +VOID +ExceptionHandlersEnd ( + VOID + ); + +VOID +CommonExceptionEntry ( + VOID + ); + +VOID +AsmCommonExceptionEntry ( + VOID + ); + + +EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_ARM_EXCEPTION + 1]; +EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1]; + + + +/** + 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 + ) +{ + if (InterruptType > MAX_ARM_EXCEPTION) { + return EFI_UNSUPPORTED; + } + + if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) { + return EFI_ALREADY_STARTED; + } + + gExceptionHandlers[InterruptType] = InterruptHandler; + + return EFI_SUCCESS; +} + + + + +VOID +EFIAPI +CommonCExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + if (ExceptionType <= MAX_ARM_EXCEPTION) { + if (gExceptionHandlers[ExceptionType]) { + gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext); + return; + } + } else { + DEBUG ((EFI_D_ERROR, "Unknown exception type %d from %08x\n", ExceptionType, SystemContext.SystemContextArm->PC)); + ASSERT (FALSE); + } + + if (ExceptionType == EXCEPT_ARM_SOFTWARE_INTERRUPT) { + // + // ARM JTAG debuggers some times use this vector, so it is not an error to get one + // + return; + } + + DefaultExceptionHandler (ExceptionType, SystemContext); +} + + + +EFI_STATUS +InitializeExceptions ( + IN EFI_CPU_ARCH_PROTOCOL *Cpu + ) +{ + EFI_STATUS Status; + UINTN Offset; + UINTN Length; + UINTN Index; + BOOLEAN IrqEnabled; + BOOLEAN FiqEnabled; + EFI_PHYSICAL_ADDRESS Base; + UINT32 *VectorBase; + + Status = EFI_SUCCESS; + ZeroMem (gExceptionHandlers,sizeof(*gExceptionHandlers)); + + // + // 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 (FeaturePcdGet(PcdRelocateVectorTable) == TRUE) { + // + // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress. + // + Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart; + + // Check if the exception vector is in the low address + if (PcdGet32 (PcdCpuVectorBaseAddress) == 0x0) { + // Set SCTLR.V to 0 to enable VBAR to be used + ArmSetLowVectors (); + } else { + ArmSetHighVectors (); + } + + // + // Reserve space for the exception handlers + // + Base = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdCpuVectorBaseAddress); + VectorBase = (UINT32 *)(UINTN)Base; + Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, EFI_SIZE_TO_PAGES (Length), &Base); + // If the request was for memory that's not in the memory map (which is often the case for 0x00000000 + // on embedded systems, for example, we don't want to hang up. So we'll check here for a status of + // EFI_NOT_FOUND, and continue in that case. + if (EFI_ERROR(Status) && (Status != EFI_NOT_FOUND)) { + ASSERT_EFI_ERROR (Status); + } + + if (FeaturePcdGet(PcdDebuggerExceptionSupport) == TRUE) { + // Save existing vector table, in case debugger is already hooked in + CopyMem ((VOID *)gDebuggerExceptionHandlers, (VOID *)VectorBase, sizeof (gDebuggerExceptionHandlers)); + } + + // Copy our assembly code into the page that contains the exception vectors. + CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length); + + // + // Patch in the common Assembly exception handler + // + Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart; + *(UINTN *) ((UINT8 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress) + Offset) = (UINTN)AsmCommonExceptionEntry; + + // + // Initialize the C entry points for interrupts + // + for (Index = 0; Index <= MAX_ARM_EXCEPTION; Index++) { + if (!FeaturePcdGet(PcdDebuggerExceptionSupport) || + (gDebuggerExceptionHandlers[Index] == 0) || (gDebuggerExceptionHandlers[Index] == (VOID *)(UINTN)0xEAFFFFFE)) { + // Exception handler contains branch to vector location (jmp $) so no handler + // NOTE: This code assumes vectors are ARM and not Thumb code + Status = RegisterInterruptHandler (Index, NULL); + ASSERT_EFI_ERROR (Status); + } else { + // If the debugger has already hooked put its vector back + VectorBase[Index] = (UINT32)(UINTN)gDebuggerExceptionHandlers[Index]; + } + } + + // Flush Caches since we updated executable stuff + InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length); + + //Note: On ARM processor with the Security Extension, the Vector Table can be located anywhere in the memory. + // The Vector Base Address Register defines the location + ArmWriteVBar (PcdGet32(PcdCpuVectorBaseAddress)); + } else { + // The Vector table must be 32-byte aligned + ASSERT(((UINT32)ExceptionHandlersStart & ((1 << 5)-1)) == 0); + + // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector Base Address to point into CpuDxe code. + ArmWriteVBar ((UINT32)ExceptionHandlersStart); + } + + if (FiqEnabled) { + ArmEnableFiq (); + } + + if (IrqEnabled) { + // + // Restore interrupt state + // + Status = Cpu->EnableInterrupt (Cpu); + } + + return Status; +} diff --git a/ArmPkg/Drivers/CpuDxe/ArmV6/Mmu.c b/ArmPkg/Drivers/CpuDxe/ArmV6/Mmu.c new file mode 100644 index 0000000000..dcc7b682c0 --- /dev/null +++ b/ArmPkg/Drivers/CpuDxe/ArmV6/Mmu.c @@ -0,0 +1,944 @@ +/*++ + +Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.
+Portions copyright (c) 2010, Apple Inc. All rights reserved.
+ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +--*/ + +#include "CpuDxe.h" + +// First Level Descriptors +typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR; + +// Second Level Descriptors +typedef UINT32 ARM_PAGE_TABLE_ENTRY; + +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_WP | 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_WP; + 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_WP | 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_WP; + 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; +} + +/** + 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 +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 ((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 + // 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])) { + 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); + } + + return EFI_SUCCESS; +} + + + +EFI_STATUS +UpdatePageEntries ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes, + IN EFI_PHYSICAL_ADDRESS VirtualMask + ) +{ + EFI_STATUS Status; + UINT32 EntryValue; + UINT32 EntryMask; + UINT32 FirstLevelIdx; + UINT32 Offset; + UINT32 NumPageEntries; + UINT32 Descriptor; + UINT32 p; + UINT32 PageTableIndex; + UINT32 PageTableEntry; + UINT32 CurrentPageTableEntry; + VOID *Mva; + + volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; + volatile ARM_PAGE_TABLE_ENTRY *PageTable; + + Status = EFI_SUCCESS; + + // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone) + // EntryValue: values at bit positions specified by EntryMask + EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK; + EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE; + // 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 |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; + // map to strongly ordered + EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0 + break; + + case EFI_MEMORY_WC: + // modify cacheability attributes + EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; + // map to normal non-cachable + EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0 + break; + + case EFI_MEMORY_WT: + // modify cacheability attributes + EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; + // write through with no-allocate + EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0 + break; + + case EFI_MEMORY_WB: + // modify cacheability attributes + EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; + // write back (with allocate) + EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1 + break; + + case EFI_MEMORY_WP: + case EFI_MEMORY_XP: + case EFI_MEMORY_UCE: + // cannot be implemented UEFI definition unclear for ARM + // Cause a page fault if these ranges are accessed. + EntryValue = TT_DESCRIPTOR_PAGE_TYPE_FAULT; + DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting page %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes)); + break; + + default: + return EFI_UNSUPPORTED; + } + + // Obtain page table base + FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); + + // Calculate number of 4KB page table entries to change + NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE; + + // Iterate for the number of 4KB pages to change + Offset = 0; + for(p = 0; p < NumPageEntries; p++) { + // Calculate index into first level translation table for page table value + + FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; + ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); + + // Read the descriptor from the first level page table + Descriptor = FirstLevelTable[FirstLevelIdx]; + + // Does this descriptor need to be converted from section entry to 4K pages? + if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) { + Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT); + if (EFI_ERROR(Status)) { + // Exit for loop + break; + } + + // Re-read descriptor + Descriptor = FirstLevelTable[FirstLevelIdx]; + } + + // Obtain page table base address + PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor); + + // Calculate index into the page table + PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT; + ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT); + + // Get the entry + CurrentPageTableEntry = PageTable[PageTableIndex]; + + // Mask off appropriate fields + PageTableEntry = CurrentPageTableEntry & ~EntryMask; + + // Mask in new attributes and/or permissions + PageTableEntry |= EntryValue; + + if (VirtualMask != 0) { + // Make this virtual address point at a physical page + PageTableEntry &= ~VirtualMask; + } + + if (CurrentPageTableEntry != PageTableEntry) { + Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT)); + if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) { + // The current section mapping is cacheable so Clean/Invalidate the MVA of the page + // Note assumes switch(Attributes), not ARMv7 possibilities + WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE); + } + + // Only need to update if we are changing the entry + PageTable[PageTableIndex] = PageTableEntry; + ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva); + } + + Status = EFI_SUCCESS; + Offset += TT_DESCRIPTOR_PAGE_SIZE; + + } // End first level translation table loop + + return Status; +} + + + +EFI_STATUS +UpdateSectionEntries ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes, + IN EFI_PHYSICAL_ADDRESS VirtualMask + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 EntryMask; + UINT32 EntryValue; + UINT32 FirstLevelIdx; + UINT32 NumSections; + UINT32 i; + UINT32 CurrentDescriptor; + UINT32 Descriptor; + VOID *Mva; + volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; + + // 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 = TT_DESCRIPTOR_SECTION_TYPE_MASK; + EntryValue = TT_DESCRIPTOR_SECTION_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 |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; + // map to strongly ordered + EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0 + break; + + case EFI_MEMORY_WC: + // modify cacheability attributes + EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; + // map to normal non-cachable + EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0 + break; + + case EFI_MEMORY_WT: + // modify cacheability attributes + EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; + // write through with no-allocate + EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0 + break; + + case EFI_MEMORY_WB: + // modify cacheability attributes + EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; + // write back (with allocate) + EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1 + break; + + case EFI_MEMORY_WP: + case EFI_MEMORY_XP: + case EFI_MEMORY_RP: + case EFI_MEMORY_UCE: + // cannot be implemented UEFI definition unclear for ARM + // Cause a page fault if these ranges are accessed. + EntryValue = TT_DESCRIPTOR_SECTION_TYPE_FAULT; + DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting section %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes)); + break; + + + default: + return EFI_UNSUPPORTED; + } + + // obtain page table base + FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); + + // calculate index into first level translation table for start of modification + FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; + ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); + + // calculate number of 1MB first level entries this applies to + NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE; + + // iterate through each descriptor + for(i=0; i> TT_DESCRIPTOR_SECTION_BASE_SHIFT; + ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); + + // Get section attributes and convert to page attributes + SectionDescriptor = FirstLevelTable[FirstLevelIdx]; + PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE; + PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(SectionDescriptor,0); + PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(SectionDescriptor); + PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_XN(SectionDescriptor,0); + PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_NG(SectionDescriptor); + PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_S(SectionDescriptor); + + // Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB) + Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1, &PageTableAddr); + if (EFI_ERROR(Status)) { + return Status; + } + + PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr; + + // Write the page table entries out + for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) { + PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor; + } + + // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks + WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, TT_DESCRIPTOR_PAGE_SIZE); + + // Formulate page table entry, Domain=0, NS=0 + PageTableDescriptor = (((UINTN)PageTableAddr) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE; + + // Write the page table entry out, replacing section entry + FirstLevelTable[FirstLevelIdx] = PageTableDescriptor; + + return EFI_SUCCESS; +} + + + +EFI_STATUS +SetMemoryAttributes ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes, + IN EFI_PHYSICAL_ADDRESS VirtualMask + ) +{ + EFI_STATUS Status; + + 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)); + 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)); + Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask); + } + + // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks + // flush and invalidate pages + //TODO: Do we really need to invalidate the caches everytime we change the memory attributes ? + ArmCleanInvalidateDataCache (); + + ArmInvalidateInstructionCache (); + + // Invalidate all TLB entries so changes are synced + ArmInvalidateTlb (); + + return Status; +} + + +/** + 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 Attributes + ) +{ + DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx)\n", BaseAddress, Length, Attributes)); + if ( ((BaseAddress & ~TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK) != 0) || ((Length & ~TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK) != 0)){ + // minimum granularity is SIZE_4KB (4KB on ARM) + DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx): minimum ganularity is SIZE_4KB\n", BaseAddress, Length, Attributes)); + return EFI_UNSUPPORTED; + } + + return SetMemoryAttributes (BaseAddress, Length, Attributes, 0); +} + + + +// +// Add a new protocol to support +// + +EFI_STATUS +EFIAPI +CpuConvertPagesToUncachedVirtualAddress ( + IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Address, + IN UINTN Length, + IN EFI_PHYSICAL_ADDRESS VirtualMask, + OUT UINT64 *Attributes OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + + + if (Attributes != NULL) { + Status = gDS->GetMemorySpaceDescriptor (Address, &GcdDescriptor); + if (!EFI_ERROR (Status)) { + *Attributes = GcdDescriptor.Attributes; + } + } + + // + // 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_WP, 0); + if (!EFI_ERROR (Status)) { + Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_UC, VirtualMask); + } + + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "ConvertPagesToUncachedVirtualAddress()\n Unmapped 0x%08lx Mapped 0x%08lx 0x%x bytes\n", Address, Address | VirtualMask, Length)); + + return Status; +} + + +EFI_STATUS +EFIAPI +CpuReconvertPages ( + IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS Address, + IN UINTN Length, + IN EFI_PHYSICAL_ADDRESS VirtualMask, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "CpuReconvertPages(%lx, %x, %lx, %lx)\n", Address, Length, VirtualMask, Attributes)); + + // + // Unmap the alaised Address + // + Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_WP, 0); + if (!EFI_ERROR (Status)) { + // + // Restore atttributes + // + Status = SetMemoryAttributes (Address, Length, Attributes, 0); + } + + return Status; +} + + +VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages = { + CpuConvertPagesToUncachedVirtualAddress, + CpuReconvertPages +}; diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf index b471e4ac2f..16afd0452d 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf @@ -40,8 +40,8 @@ # [Sources.ARM] - Mmu.c - Exception.c + ArmV6/Mmu.c + ArmV6/Exception.c ArmV6/ExceptionSupport.asm | RVCT ArmV6/ExceptionSupport.S | GCC diff --git a/ArmPkg/Drivers/CpuDxe/Exception.c b/ArmPkg/Drivers/CpuDxe/Exception.c deleted file mode 100644 index 55a7132193..0000000000 --- a/ArmPkg/Drivers/CpuDxe/Exception.c +++ /dev/null @@ -1,230 +0,0 @@ -/** @file - - Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "CpuDxe.h" - -//FIXME: Will not compile on non-ARMv7 builds -#include - -VOID -ExceptionHandlersStart ( - VOID - ); - -VOID -ExceptionHandlersEnd ( - VOID - ); - -VOID -CommonExceptionEntry ( - VOID - ); - -VOID -AsmCommonExceptionEntry ( - VOID - ); - - -EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_ARM_EXCEPTION + 1]; -EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1]; - - - -/** - 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 - ) -{ - if (InterruptType > MAX_ARM_EXCEPTION) { - return EFI_UNSUPPORTED; - } - - if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) { - return EFI_ALREADY_STARTED; - } - - gExceptionHandlers[InterruptType] = InterruptHandler; - - return EFI_SUCCESS; -} - - - - -VOID -EFIAPI -CommonCExceptionHandler ( - IN EFI_EXCEPTION_TYPE ExceptionType, - IN OUT EFI_SYSTEM_CONTEXT SystemContext - ) -{ - if (ExceptionType <= MAX_ARM_EXCEPTION) { - if (gExceptionHandlers[ExceptionType]) { - gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext); - return; - } - } else { - DEBUG ((EFI_D_ERROR, "Unknown exception type %d from %08x\n", ExceptionType, SystemContext.SystemContextArm->PC)); - ASSERT (FALSE); - } - - if (ExceptionType == EXCEPT_ARM_SOFTWARE_INTERRUPT) { - // - // ARM JTAG debuggers some times use this vector, so it is not an error to get one - // - return; - } - - DefaultExceptionHandler (ExceptionType, SystemContext); -} - - - -EFI_STATUS -InitializeExceptions ( - IN EFI_CPU_ARCH_PROTOCOL *Cpu - ) -{ - EFI_STATUS Status; - UINTN Offset; - UINTN Length; - UINTN Index; - BOOLEAN IrqEnabled; - BOOLEAN FiqEnabled; - EFI_PHYSICAL_ADDRESS Base; - UINT32 *VectorBase; - - Status = EFI_SUCCESS; - ZeroMem (gExceptionHandlers,sizeof(*gExceptionHandlers)); - - // - // 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 (FeaturePcdGet(PcdRelocateVectorTable) == TRUE) { - // - // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress. - // - Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart; - - // Check if the exception vector is in the low address - if (PcdGet32 (PcdCpuVectorBaseAddress) == 0x0) { - // Set SCTLR.V to 0 to enable VBAR to be used - ArmSetLowVectors (); - } else { - ArmSetHighVectors (); - } - - // - // Reserve space for the exception handlers - // - Base = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdCpuVectorBaseAddress); - VectorBase = (UINT32 *)(UINTN)Base; - Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, EFI_SIZE_TO_PAGES (Length), &Base); - // If the request was for memory that's not in the memory map (which is often the case for 0x00000000 - // on embedded systems, for example, we don't want to hang up. So we'll check here for a status of - // EFI_NOT_FOUND, and continue in that case. - if (EFI_ERROR(Status) && (Status != EFI_NOT_FOUND)) { - ASSERT_EFI_ERROR (Status); - } - - if (FeaturePcdGet(PcdDebuggerExceptionSupport) == TRUE) { - // Save existing vector table, in case debugger is already hooked in - CopyMem ((VOID *)gDebuggerExceptionHandlers, (VOID *)VectorBase, sizeof (gDebuggerExceptionHandlers)); - } - - // Copy our assembly code into the page that contains the exception vectors. - CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length); - - // - // Patch in the common Assembly exception handler - // - Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart; - *(UINTN *) ((UINT8 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress) + Offset) = (UINTN)AsmCommonExceptionEntry; - - // - // Initialize the C entry points for interrupts - // - for (Index = 0; Index <= MAX_ARM_EXCEPTION; Index++) { - if (!FeaturePcdGet(PcdDebuggerExceptionSupport) || - (gDebuggerExceptionHandlers[Index] == 0) || (gDebuggerExceptionHandlers[Index] == (VOID *)(UINTN)0xEAFFFFFE)) { - // Exception handler contains branch to vector location (jmp $) so no handler - // NOTE: This code assumes vectors are ARM and not Thumb code - Status = RegisterInterruptHandler (Index, NULL); - ASSERT_EFI_ERROR (Status); - } else { - // If the debugger has already hooked put its vector back - VectorBase[Index] = (UINT32)(UINTN)gDebuggerExceptionHandlers[Index]; - } - } - - // Flush Caches since we updated executable stuff - InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length); - - //Note: On ARM processor with the Security Extension, the Vector Table can be located anywhere in the memory. - // The Vector Base Address Register defines the location - ArmWriteVBar (PcdGet32(PcdCpuVectorBaseAddress)); - } else { - // The Vector table must be 32-byte aligned - ASSERT(((UINT32)ExceptionHandlersStart & ((1 << 5)-1)) == 0); - - // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector Base Address to point into CpuDxe code. - ArmWriteVBar ((UINT32)ExceptionHandlersStart); - } - - if (FiqEnabled) { - ArmEnableFiq (); - } - - if (IrqEnabled) { - // - // Restore interrupt state - // - Status = Cpu->EnableInterrupt (Cpu); - } - - return Status; -} diff --git a/ArmPkg/Drivers/CpuDxe/Mmu.c b/ArmPkg/Drivers/CpuDxe/Mmu.c deleted file mode 100644 index dcc7b682c0..0000000000 --- a/ArmPkg/Drivers/CpuDxe/Mmu.c +++ /dev/null @@ -1,944 +0,0 @@ -/*++ - -Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.
-Portions copyright (c) 2010, Apple Inc. All rights reserved.
- -This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - - ---*/ - -#include "CpuDxe.h" - -// First Level Descriptors -typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR; - -// Second Level Descriptors -typedef UINT32 ARM_PAGE_TABLE_ENTRY; - -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_WP | 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_WP; - 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_WP | 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_WP; - 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; -} - -/** - 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 -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 ((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 - // 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])) { - 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); - } - - return EFI_SUCCESS; -} - - - -EFI_STATUS -UpdatePageEntries ( - IN EFI_PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN UINT64 Attributes, - IN EFI_PHYSICAL_ADDRESS VirtualMask - ) -{ - EFI_STATUS Status; - UINT32 EntryValue; - UINT32 EntryMask; - UINT32 FirstLevelIdx; - UINT32 Offset; - UINT32 NumPageEntries; - UINT32 Descriptor; - UINT32 p; - UINT32 PageTableIndex; - UINT32 PageTableEntry; - UINT32 CurrentPageTableEntry; - VOID *Mva; - - volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; - volatile ARM_PAGE_TABLE_ENTRY *PageTable; - - Status = EFI_SUCCESS; - - // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone) - // EntryValue: values at bit positions specified by EntryMask - EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK; - EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE; - // 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 |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; - // map to strongly ordered - EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0 - break; - - case EFI_MEMORY_WC: - // modify cacheability attributes - EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; - // map to normal non-cachable - EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0 - break; - - case EFI_MEMORY_WT: - // modify cacheability attributes - EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; - // write through with no-allocate - EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0 - break; - - case EFI_MEMORY_WB: - // modify cacheability attributes - EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK; - // write back (with allocate) - EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1 - break; - - case EFI_MEMORY_WP: - case EFI_MEMORY_XP: - case EFI_MEMORY_UCE: - // cannot be implemented UEFI definition unclear for ARM - // Cause a page fault if these ranges are accessed. - EntryValue = TT_DESCRIPTOR_PAGE_TYPE_FAULT; - DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting page %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes)); - break; - - default: - return EFI_UNSUPPORTED; - } - - // Obtain page table base - FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); - - // Calculate number of 4KB page table entries to change - NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE; - - // Iterate for the number of 4KB pages to change - Offset = 0; - for(p = 0; p < NumPageEntries; p++) { - // Calculate index into first level translation table for page table value - - FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; - ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); - - // Read the descriptor from the first level page table - Descriptor = FirstLevelTable[FirstLevelIdx]; - - // Does this descriptor need to be converted from section entry to 4K pages? - if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) { - Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT); - if (EFI_ERROR(Status)) { - // Exit for loop - break; - } - - // Re-read descriptor - Descriptor = FirstLevelTable[FirstLevelIdx]; - } - - // Obtain page table base address - PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor); - - // Calculate index into the page table - PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT; - ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT); - - // Get the entry - CurrentPageTableEntry = PageTable[PageTableIndex]; - - // Mask off appropriate fields - PageTableEntry = CurrentPageTableEntry & ~EntryMask; - - // Mask in new attributes and/or permissions - PageTableEntry |= EntryValue; - - if (VirtualMask != 0) { - // Make this virtual address point at a physical page - PageTableEntry &= ~VirtualMask; - } - - if (CurrentPageTableEntry != PageTableEntry) { - Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT)); - if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) { - // The current section mapping is cacheable so Clean/Invalidate the MVA of the page - // Note assumes switch(Attributes), not ARMv7 possibilities - WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE); - } - - // Only need to update if we are changing the entry - PageTable[PageTableIndex] = PageTableEntry; - ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva); - } - - Status = EFI_SUCCESS; - Offset += TT_DESCRIPTOR_PAGE_SIZE; - - } // End first level translation table loop - - return Status; -} - - - -EFI_STATUS -UpdateSectionEntries ( - IN EFI_PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN UINT64 Attributes, - IN EFI_PHYSICAL_ADDRESS VirtualMask - ) -{ - EFI_STATUS Status = EFI_SUCCESS; - UINT32 EntryMask; - UINT32 EntryValue; - UINT32 FirstLevelIdx; - UINT32 NumSections; - UINT32 i; - UINT32 CurrentDescriptor; - UINT32 Descriptor; - VOID *Mva; - volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable; - - // 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 = TT_DESCRIPTOR_SECTION_TYPE_MASK; - EntryValue = TT_DESCRIPTOR_SECTION_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 |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; - // map to strongly ordered - EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0 - break; - - case EFI_MEMORY_WC: - // modify cacheability attributes - EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; - // map to normal non-cachable - EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0 - break; - - case EFI_MEMORY_WT: - // modify cacheability attributes - EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; - // write through with no-allocate - EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0 - break; - - case EFI_MEMORY_WB: - // modify cacheability attributes - EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK; - // write back (with allocate) - EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1 - break; - - case EFI_MEMORY_WP: - case EFI_MEMORY_XP: - case EFI_MEMORY_RP: - case EFI_MEMORY_UCE: - // cannot be implemented UEFI definition unclear for ARM - // Cause a page fault if these ranges are accessed. - EntryValue = TT_DESCRIPTOR_SECTION_TYPE_FAULT; - DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting section %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes)); - break; - - - default: - return EFI_UNSUPPORTED; - } - - // obtain page table base - FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress (); - - // calculate index into first level translation table for start of modification - FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT; - ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); - - // calculate number of 1MB first level entries this applies to - NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE; - - // iterate through each descriptor - for(i=0; i> TT_DESCRIPTOR_SECTION_BASE_SHIFT; - ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT); - - // Get section attributes and convert to page attributes - SectionDescriptor = FirstLevelTable[FirstLevelIdx]; - PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE; - PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(SectionDescriptor,0); - PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(SectionDescriptor); - PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_XN(SectionDescriptor,0); - PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_NG(SectionDescriptor); - PageDescriptor |= TT_DESCRIPTOR_CONVERT_TO_PAGE_S(SectionDescriptor); - - // Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB) - Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1, &PageTableAddr); - if (EFI_ERROR(Status)) { - return Status; - } - - PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr; - - // Write the page table entries out - for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) { - PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor; - } - - // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks - WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, TT_DESCRIPTOR_PAGE_SIZE); - - // Formulate page table entry, Domain=0, NS=0 - PageTableDescriptor = (((UINTN)PageTableAddr) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE; - - // Write the page table entry out, replacing section entry - FirstLevelTable[FirstLevelIdx] = PageTableDescriptor; - - return EFI_SUCCESS; -} - - - -EFI_STATUS -SetMemoryAttributes ( - IN EFI_PHYSICAL_ADDRESS BaseAddress, - IN UINT64 Length, - IN UINT64 Attributes, - IN EFI_PHYSICAL_ADDRESS VirtualMask - ) -{ - EFI_STATUS Status; - - 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)); - 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)); - Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask); - } - - // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks - // flush and invalidate pages - //TODO: Do we really need to invalidate the caches everytime we change the memory attributes ? - ArmCleanInvalidateDataCache (); - - ArmInvalidateInstructionCache (); - - // Invalidate all TLB entries so changes are synced - ArmInvalidateTlb (); - - return Status; -} - - -/** - 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 Attributes - ) -{ - DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx)\n", BaseAddress, Length, Attributes)); - if ( ((BaseAddress & ~TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK) != 0) || ((Length & ~TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK) != 0)){ - // minimum granularity is SIZE_4KB (4KB on ARM) - DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx): minimum ganularity is SIZE_4KB\n", BaseAddress, Length, Attributes)); - return EFI_UNSUPPORTED; - } - - return SetMemoryAttributes (BaseAddress, Length, Attributes, 0); -} - - - -// -// Add a new protocol to support -// - -EFI_STATUS -EFIAPI -CpuConvertPagesToUncachedVirtualAddress ( - IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This, - IN EFI_PHYSICAL_ADDRESS Address, - IN UINTN Length, - IN EFI_PHYSICAL_ADDRESS VirtualMask, - OUT UINT64 *Attributes OPTIONAL - ) -{ - EFI_STATUS Status; - EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; - - - if (Attributes != NULL) { - Status = gDS->GetMemorySpaceDescriptor (Address, &GcdDescriptor); - if (!EFI_ERROR (Status)) { - *Attributes = GcdDescriptor.Attributes; - } - } - - // - // 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_WP, 0); - if (!EFI_ERROR (Status)) { - Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_UC, VirtualMask); - } - - DEBUG ((DEBUG_INFO | DEBUG_LOAD, "ConvertPagesToUncachedVirtualAddress()\n Unmapped 0x%08lx Mapped 0x%08lx 0x%x bytes\n", Address, Address | VirtualMask, Length)); - - return Status; -} - - -EFI_STATUS -EFIAPI -CpuReconvertPages ( - IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This, - IN EFI_PHYSICAL_ADDRESS Address, - IN UINTN Length, - IN EFI_PHYSICAL_ADDRESS VirtualMask, - IN UINT64 Attributes - ) -{ - EFI_STATUS Status; - - DEBUG ((DEBUG_INFO | DEBUG_LOAD, "CpuReconvertPages(%lx, %x, %lx, %lx)\n", Address, Length, VirtualMask, Attributes)); - - // - // Unmap the alaised Address - // - Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_WP, 0); - if (!EFI_ERROR (Status)) { - // - // Restore atttributes - // - Status = SetMemoryAttributes (Address, Length, Attributes, 0); - } - - return Status; -} - - -VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages = { - CpuConvertPagesToUncachedVirtualAddress, - CpuReconvertPages -}; diff --git a/ArmPkg/Library/ArmLib/Arm11/Arm11Lib.inf b/ArmPkg/Library/ArmLib/Arm11/Arm11Lib.inf index b28a4578b0..5f24ffaf3c 100644 --- a/ArmPkg/Library/ArmLib/Arm11/Arm11Lib.inf +++ b/ArmPkg/Library/ArmLib/Arm11/Arm11Lib.inf @@ -22,8 +22,8 @@ LIBRARY_CLASS = ArmLib [Sources.common] - ../Common/ArmLibSupport.S | GCC - ../Common/ArmLibSupport.asm | RVCT + ../Common/Arm/ArmLibSupport.S | GCC + ../Common/Arm/ArmLibSupport.asm | RVCT ../Common/ArmLib.c Arm11Support.S | GCC diff --git a/ArmPkg/Library/ArmLib/Arm11/Arm11LibPrePi.inf b/ArmPkg/Library/ArmLib/Arm11/Arm11LibPrePi.inf index cd36d8b3c7..7239aceaf9 100644 --- a/ArmPkg/Library/ArmLib/Arm11/Arm11LibPrePi.inf +++ b/ArmPkg/Library/ArmLib/Arm11/Arm11LibPrePi.inf @@ -22,8 +22,8 @@ LIBRARY_CLASS = ArmLib [Sources.common] - ../Common/ArmLibSupport.S | GCC - ../Common/ArmLibSupport.asm | RVCT + ../Common/Arm/ArmLibSupport.S | GCC + ../Common/Arm/ArmLibSupport.asm | RVCT ../Common/ArmLib.c Arm11Support.S | GCC diff --git a/ArmPkg/Library/ArmLib/Arm11/Arm11LibSec.inf b/ArmPkg/Library/ArmLib/Arm11/Arm11LibSec.inf index 4c3566e3c5..e693c46dc4 100644 --- a/ArmPkg/Library/ArmLib/Arm11/Arm11LibSec.inf +++ b/ArmPkg/Library/ArmLib/Arm11/Arm11LibSec.inf @@ -22,8 +22,8 @@ LIBRARY_CLASS = ArmLib [Sources.common] - ../Common/ArmLibSupport.S | GCC - ../Common/ArmLibSupport.asm | RVCT + ../Common/Arm/ArmLibSupport.S | GCC + ../Common/Arm/ArmLibSupport.asm | RVCT ../Common/ArmLib.c Arm11Support.S | GCC diff --git a/ArmPkg/Library/ArmLib/Arm9/Arm9ArmLib.inf b/ArmPkg/Library/ArmLib/Arm9/Arm9ArmLib.inf index 4eebf769dd..e962ca40aa 100644 --- a/ArmPkg/Library/ArmLib/Arm9/Arm9ArmLib.inf +++ b/ArmPkg/Library/ArmLib/Arm9/Arm9ArmLib.inf @@ -22,8 +22,8 @@ LIBRARY_CLASS = ArmLib [Sources.common] - ../Common/ArmLibSupport.S | GCC - ../Common/ArmLibSupport.asm | RVCT + ../Common/Arm/ArmLibSupport.S | GCC + ../Common/Arm/ArmLibSupport.asm | RVCT ../Common/ArmLib.c Arm9Support.S | GCC diff --git a/ArmPkg/Library/ArmLib/Arm9/Arm9ArmLibPrePi.inf b/ArmPkg/Library/ArmLib/Arm9/Arm9ArmLibPrePi.inf index e1900c5a11..4c57001930 100644 --- a/ArmPkg/Library/ArmLib/Arm9/Arm9ArmLibPrePi.inf +++ b/ArmPkg/Library/ArmLib/Arm9/Arm9ArmLibPrePi.inf @@ -22,8 +22,8 @@ LIBRARY_CLASS = ArmLib [Sources.common] - ../Common/ArmLibSupport.S | GCC - ../Common/ArmLibSupport.asm | RVCT + ../Common/Arm/ArmLibSupport.S | GCC + ../Common/Arm/ArmLibSupport.asm | RVCT ../Common/ArmLib.c Arm9Support.S | GCC diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf b/ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf index 2bc01a9949..ec2a0bae89 100644 --- a/ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7Lib.inf @@ -25,8 +25,8 @@ ArmLibSupportV7.S | GCC ArmLibSupportV7.asm | RVCT - ../Common/ArmLibSupport.S | GCC - ../Common/ArmLibSupport.asm | RVCT + ../Common/Arm/ArmLibSupport.S | GCC + ../Common/Arm/ArmLibSupport.asm | RVCT ../Common/ArmLib.c ArmV7Support.S | GCC diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf b/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf index 5fdb044974..be5b8e4930 100644 --- a/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibPrePi.inf @@ -25,8 +25,8 @@ ArmLibSupportV7.S | GCC ArmLibSupportV7.asm | RVCT - ../Common/ArmLibSupport.S | GCC - ../Common/ArmLibSupport.asm | RVCT + ../Common/Arm/ArmLibSupport.S | GCC + ../Common/Arm/ArmLibSupport.asm | RVCT ../Common/ArmLib.c ArmV7Support.S | GCC diff --git a/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf b/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf index 9e6f17ec3e..c1f97bb12d 100644 --- a/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf +++ b/ArmPkg/Library/ArmLib/ArmV7/ArmV7LibSec.inf @@ -23,8 +23,8 @@ ArmLibSupportV7.S | GCC ArmLibSupportV7.asm | RVCT - ../Common/ArmLibSupport.S | GCC - ../Common/ArmLibSupport.asm | RVCT + ../Common/Arm/ArmLibSupport.S | GCC + ../Common/Arm/ArmLibSupport.asm | RVCT ../Common/ArmLib.c ArmV7Support.S | GCC diff --git a/ArmPkg/Library/ArmLib/Common/Arm/ArmLibSupport.S b/ArmPkg/Library/ArmLib/Common/Arm/ArmLibSupport.S new file mode 100644 index 0000000000..b19185412c --- /dev/null +++ b/ArmPkg/Library/ArmLib/Common/Arm/ArmLibSupport.S @@ -0,0 +1,184 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+# Copyright (c) 2011-2012, ARM Limited. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#------------------------------------------------------------------------------ + +#include + +#ifdef ARM_CPU_ARMv6 +// No memory barriers for ARMv6 +#define isb +#define dsb +#endif + +.text +.align 2 +GCC_ASM_EXPORT(Cp15IdCode) +GCC_ASM_EXPORT(Cp15CacheInfo) +GCC_ASM_EXPORT(ArmGetInterruptState) +GCC_ASM_EXPORT(ArmGetFiqState) +GCC_ASM_EXPORT(ArmGetTTBR0BaseAddress) +GCC_ASM_EXPORT(ArmSetTTBR0) +GCC_ASM_EXPORT(ArmSetDomainAccessControl) +GCC_ASM_EXPORT(CPSRMaskInsert) +GCC_ASM_EXPORT(CPSRRead) +GCC_ASM_EXPORT(ArmReadCpacr) +GCC_ASM_EXPORT(ArmWriteCpacr) +GCC_ASM_EXPORT(ArmWriteAuxCr) +GCC_ASM_EXPORT(ArmReadAuxCr) +GCC_ASM_EXPORT(ArmInvalidateTlb) +GCC_ASM_EXPORT(ArmUpdateTranslationTableEntry) +GCC_ASM_EXPORT(ArmReadNsacr) +GCC_ASM_EXPORT(ArmWriteNsacr) +GCC_ASM_EXPORT(ArmReadScr) +GCC_ASM_EXPORT(ArmWriteScr) +GCC_ASM_EXPORT(ArmReadMVBar) +GCC_ASM_EXPORT(ArmWriteMVBar) +GCC_ASM_EXPORT(ArmCallWFE) +GCC_ASM_EXPORT(ArmCallSEV) +GCC_ASM_EXPORT(ArmReadSctlr) + +#------------------------------------------------------------------------------ + +ASM_PFX(Cp15IdCode): + mrc p15,0,R0,c0,c0,0 + bx LR + +ASM_PFX(Cp15CacheInfo): + mrc p15,0,R0,c0,c0,1 + bx LR + +ASM_PFX(ArmGetInterruptState): + mrs R0,CPSR + tst R0,#0x80 @Check if IRQ is enabled. + moveq R0,#1 + movne R0,#0 + bx LR + +ASM_PFX(ArmGetFiqState): + mrs R0,CPSR + tst R0,#0x40 @Check if FIQ is enabled. + moveq R0,#1 + movne R0,#0 + bx LR + +ASM_PFX(ArmSetDomainAccessControl): + mcr p15,0,r0,c3,c0,0 + bx lr + +ASM_PFX(CPSRMaskInsert): @ on entry, r0 is the mask and r1 is the field to insert + stmfd sp!, {r4-r12, lr} @ save all the banked registers + mov r3, sp @ copy the stack pointer into a non-banked register + mrs r2, cpsr @ read the cpsr + bic r2, r2, r0 @ clear mask in the cpsr + and r1, r1, r0 @ clear bits outside the mask in the input + orr r2, r2, r1 @ set field + msr cpsr_cxsf, r2 @ write back cpsr (may have caused a mode switch) + isb + mov sp, r3 @ restore stack pointer + ldmfd sp!, {r4-r12, lr} @ restore registers + bx lr @ return (hopefully thumb-safe!) @ return (hopefully thumb-safe!) + +ASM_PFX(CPSRRead): + mrs r0, cpsr + bx lr + +ASM_PFX(ArmReadCpacr): + mrc p15, 0, r0, c1, c0, 2 + bx lr + +ASM_PFX(ArmWriteCpacr): + mcr p15, 0, r0, c1, c0, 2 + isb + bx lr + +ASM_PFX(ArmWriteAuxCr): + mcr p15, 0, r0, c1, c0, 1 + bx lr + +ASM_PFX(ArmReadAuxCr): + mrc p15, 0, r0, c1, c0, 1 + bx lr + +ASM_PFX(ArmSetTTBR0): + mcr p15,0,r0,c2,c0,0 + isb + bx lr + +ASM_PFX(ArmGetTTBR0BaseAddress): + mrc p15,0,r0,c2,c0,0 + LoadConstantToReg(0xFFFFC000, r1) + and r0, r0, r1 + isb + bx lr + +// +//VOID +//ArmUpdateTranslationTableEntry ( +// IN VOID *TranslationTableEntry // R0 +// IN VOID *MVA // R1 +// ); +ASM_PFX(ArmUpdateTranslationTableEntry): + mcr p15,0,R0,c7,c14,1 @ DCCIMVAC Clean data cache by MVA + dsb + mcr p15,0,R1,c8,c7,1 @ TLBIMVA TLB Invalidate MVA + mcr p15,0,R9,c7,c5,6 @ BPIALL Invalidate Branch predictor array. R9 == NoOp + dsb + isb + bx lr + +ASM_PFX(ArmInvalidateTlb): + mov r0,#0 + mcr p15,0,r0,c8,c7,0 + mcr p15,0,R9,c7,c5,6 @ BPIALL Invalidate Branch predictor array. R9 == NoOp + dsb + isb + bx lr + +ASM_PFX(ArmReadNsacr): + mrc p15, 0, r0, c1, c1, 2 + bx lr + +ASM_PFX(ArmWriteNsacr): + mcr p15, 0, r0, c1, c1, 2 + bx lr + +ASM_PFX(ArmReadScr): + mrc p15, 0, r0, c1, c1, 0 + bx lr + +ASM_PFX(ArmWriteScr): + mcr p15, 0, r0, c1, c1, 0 + bx lr + +ASM_PFX(ArmReadMVBar): + mrc p15, 0, r0, c12, c0, 1 + bx lr + +ASM_PFX(ArmWriteMVBar): + mcr p15, 0, r0, c12, c0, 1 + bx lr + +ASM_PFX(ArmCallWFE): + wfe + bx lr + +ASM_PFX(ArmCallSEV): + sev + bx lr + +ASM_PFX(ArmReadSctlr): + mrc p15, 0, R0, c1, c0, 0 @ Read SCTLR into R0 (Read control register configuration data) + bx lr + +ASM_FUNCTION_REMOVE_IF_UNREFERENCED diff --git a/ArmPkg/Library/ArmLib/Common/Arm/ArmLibSupport.asm b/ArmPkg/Library/ArmLib/Common/Arm/ArmLibSupport.asm new file mode 100644 index 0000000000..fd0f332bd6 --- /dev/null +++ b/ArmPkg/Library/ArmLib/Common/Arm/ArmLibSupport.asm @@ -0,0 +1,184 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+// Copyright (c) 2011-2012, ARM Limited. All rights reserved. +// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +//------------------------------------------------------------------------------ + +#include + + INCLUDE AsmMacroIoLib.inc + +#ifdef ARM_CPU_ARMv6 +// No memory barriers for ARMv6 +#define isb +#define dsb +#endif + + EXPORT Cp15IdCode + EXPORT Cp15CacheInfo + EXPORT ArmGetInterruptState + EXPORT ArmGetFiqState + EXPORT ArmGetTTBR0BaseAddress + EXPORT ArmSetTTBR0 + EXPORT ArmSetDomainAccessControl + EXPORT CPSRMaskInsert + EXPORT CPSRRead + EXPORT ArmReadCpacr + EXPORT ArmWriteCpacr + EXPORT ArmWriteAuxCr + EXPORT ArmReadAuxCr + EXPORT ArmInvalidateTlb + EXPORT ArmUpdateTranslationTableEntry + EXPORT ArmReadNsacr + EXPORT ArmWriteNsacr + EXPORT ArmReadScr + EXPORT ArmWriteScr + EXPORT ArmReadMVBar + EXPORT ArmWriteMVBar + EXPORT ArmCallWFE + EXPORT ArmCallSEV + EXPORT ArmReadSctlr + + AREA ArmLibSupport, CODE, READONLY + +Cp15IdCode + mrc p15,0,R0,c0,c0,0 + bx LR + +Cp15CacheInfo + mrc p15,0,R0,c0,c0,1 + bx LR + +ArmGetInterruptState + mrs R0,CPSR + tst R0,#0x80 // Check if IRQ is enabled. + moveq R0,#1 + movne R0,#0 + bx LR + +ArmGetFiqState + mrs R0,CPSR + tst R0,#0x40 // Check if FIQ is enabled. + moveq R0,#1 + movne R0,#0 + bx LR + +ArmSetDomainAccessControl + mcr p15,0,r0,c3,c0,0 + bx lr + +CPSRMaskInsert // on entry, r0 is the mask and r1 is the field to insert + stmfd sp!, {r4-r12, lr} // save all the banked registers + mov r3, sp // copy the stack pointer into a non-banked register + mrs r2, cpsr // read the cpsr + bic r2, r2, r0 // clear mask in the cpsr + and r1, r1, r0 // clear bits outside the mask in the input + orr r2, r2, r1 // set field + msr cpsr_cxsf, r2 // write back cpsr (may have caused a mode switch) + isb + mov sp, r3 // restore stack pointer + ldmfd sp!, {r4-r12, lr} // restore registers + bx lr // return (hopefully thumb-safe!) // return (hopefully thumb-safe!) + +CPSRRead + mrs r0, cpsr + bx lr + +ArmReadCpacr + mrc p15, 0, r0, c1, c0, 2 + bx lr + +ArmWriteCpacr + mcr p15, 0, r0, c1, c0, 2 + isb + bx lr + +ArmWriteAuxCr + mcr p15, 0, r0, c1, c0, 1 + bx lr + +ArmReadAuxCr + mrc p15, 0, r0, c1, c0, 1 + bx lr + +ArmSetTTBR0 + mcr p15,0,r0,c2,c0,0 + isb + bx lr + +ArmGetTTBR0BaseAddress + mrc p15,0,r0,c2,c0,0 + LoadConstantToReg(0xFFFFC000, r1) + and r0, r0, r1 + isb + bx lr + +// +//VOID +//ArmUpdateTranslationTableEntry ( +// IN VOID *TranslationTableEntry // R0 +// IN VOID *MVA // R1 +// ); +ArmUpdateTranslationTableEntry + mcr p15,0,R0,c7,c14,1 // DCCIMVAC Clean data cache by MVA + dsb + mcr p15,0,R1,c8,c7,1 // TLBIMVA TLB Invalidate MVA + mcr p15,0,R9,c7,c5,6 // BPIALL Invalidate Branch predictor array. R9 == NoOp + dsb + isb + bx lr + +ArmInvalidateTlb + mov r0,#0 + mcr p15,0,r0,c8,c7,0 + mcr p15,0,R9,c7,c5,6 // BPIALL Invalidate Branch predictor array. R9 == NoOp + dsb + isb + bx lr + +ArmReadNsacr + mrc p15, 0, r0, c1, c1, 2 + bx lr + +ArmWriteNsacr + mcr p15, 0, r0, c1, c1, 2 + bx lr + +ArmReadScr + mrc p15, 0, r0, c1, c1, 0 + bx lr + +ArmWriteScr + mcr p15, 0, r0, c1, c1, 0 + bx lr + +ArmReadMVBar + mrc p15, 0, r0, c12, c0, 1 + bx lr + +ArmWriteMVBar + mcr p15, 0, r0, c12, c0, 1 + bx lr + +ArmCallWFE + wfe + blx lr + +ArmCallSEV + sev + blx lr + +ArmReadSctlr + mrc p15, 0, R0, c1, c0, 0 // Read SCTLR into R0 (Read control register configuration data) + bx lr + + END diff --git a/ArmPkg/Library/ArmLib/Common/ArmLibSupport.S b/ArmPkg/Library/ArmLib/Common/ArmLibSupport.S deleted file mode 100644 index b19185412c..0000000000 --- a/ArmPkg/Library/ArmLib/Common/ArmLibSupport.S +++ /dev/null @@ -1,184 +0,0 @@ -#------------------------------------------------------------------------------ -# -# Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
-# Copyright (c) 2011-2012, ARM Limited. All rights reserved. -# -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -#------------------------------------------------------------------------------ - -#include - -#ifdef ARM_CPU_ARMv6 -// No memory barriers for ARMv6 -#define isb -#define dsb -#endif - -.text -.align 2 -GCC_ASM_EXPORT(Cp15IdCode) -GCC_ASM_EXPORT(Cp15CacheInfo) -GCC_ASM_EXPORT(ArmGetInterruptState) -GCC_ASM_EXPORT(ArmGetFiqState) -GCC_ASM_EXPORT(ArmGetTTBR0BaseAddress) -GCC_ASM_EXPORT(ArmSetTTBR0) -GCC_ASM_EXPORT(ArmSetDomainAccessControl) -GCC_ASM_EXPORT(CPSRMaskInsert) -GCC_ASM_EXPORT(CPSRRead) -GCC_ASM_EXPORT(ArmReadCpacr) -GCC_ASM_EXPORT(ArmWriteCpacr) -GCC_ASM_EXPORT(ArmWriteAuxCr) -GCC_ASM_EXPORT(ArmReadAuxCr) -GCC_ASM_EXPORT(ArmInvalidateTlb) -GCC_ASM_EXPORT(ArmUpdateTranslationTableEntry) -GCC_ASM_EXPORT(ArmReadNsacr) -GCC_ASM_EXPORT(ArmWriteNsacr) -GCC_ASM_EXPORT(ArmReadScr) -GCC_ASM_EXPORT(ArmWriteScr) -GCC_ASM_EXPORT(ArmReadMVBar) -GCC_ASM_EXPORT(ArmWriteMVBar) -GCC_ASM_EXPORT(ArmCallWFE) -GCC_ASM_EXPORT(ArmCallSEV) -GCC_ASM_EXPORT(ArmReadSctlr) - -#------------------------------------------------------------------------------ - -ASM_PFX(Cp15IdCode): - mrc p15,0,R0,c0,c0,0 - bx LR - -ASM_PFX(Cp15CacheInfo): - mrc p15,0,R0,c0,c0,1 - bx LR - -ASM_PFX(ArmGetInterruptState): - mrs R0,CPSR - tst R0,#0x80 @Check if IRQ is enabled. - moveq R0,#1 - movne R0,#0 - bx LR - -ASM_PFX(ArmGetFiqState): - mrs R0,CPSR - tst R0,#0x40 @Check if FIQ is enabled. - moveq R0,#1 - movne R0,#0 - bx LR - -ASM_PFX(ArmSetDomainAccessControl): - mcr p15,0,r0,c3,c0,0 - bx lr - -ASM_PFX(CPSRMaskInsert): @ on entry, r0 is the mask and r1 is the field to insert - stmfd sp!, {r4-r12, lr} @ save all the banked registers - mov r3, sp @ copy the stack pointer into a non-banked register - mrs r2, cpsr @ read the cpsr - bic r2, r2, r0 @ clear mask in the cpsr - and r1, r1, r0 @ clear bits outside the mask in the input - orr r2, r2, r1 @ set field - msr cpsr_cxsf, r2 @ write back cpsr (may have caused a mode switch) - isb - mov sp, r3 @ restore stack pointer - ldmfd sp!, {r4-r12, lr} @ restore registers - bx lr @ return (hopefully thumb-safe!) @ return (hopefully thumb-safe!) - -ASM_PFX(CPSRRead): - mrs r0, cpsr - bx lr - -ASM_PFX(ArmReadCpacr): - mrc p15, 0, r0, c1, c0, 2 - bx lr - -ASM_PFX(ArmWriteCpacr): - mcr p15, 0, r0, c1, c0, 2 - isb - bx lr - -ASM_PFX(ArmWriteAuxCr): - mcr p15, 0, r0, c1, c0, 1 - bx lr - -ASM_PFX(ArmReadAuxCr): - mrc p15, 0, r0, c1, c0, 1 - bx lr - -ASM_PFX(ArmSetTTBR0): - mcr p15,0,r0,c2,c0,0 - isb - bx lr - -ASM_PFX(ArmGetTTBR0BaseAddress): - mrc p15,0,r0,c2,c0,0 - LoadConstantToReg(0xFFFFC000, r1) - and r0, r0, r1 - isb - bx lr - -// -//VOID -//ArmUpdateTranslationTableEntry ( -// IN VOID *TranslationTableEntry // R0 -// IN VOID *MVA // R1 -// ); -ASM_PFX(ArmUpdateTranslationTableEntry): - mcr p15,0,R0,c7,c14,1 @ DCCIMVAC Clean data cache by MVA - dsb - mcr p15,0,R1,c8,c7,1 @ TLBIMVA TLB Invalidate MVA - mcr p15,0,R9,c7,c5,6 @ BPIALL Invalidate Branch predictor array. R9 == NoOp - dsb - isb - bx lr - -ASM_PFX(ArmInvalidateTlb): - mov r0,#0 - mcr p15,0,r0,c8,c7,0 - mcr p15,0,R9,c7,c5,6 @ BPIALL Invalidate Branch predictor array. R9 == NoOp - dsb - isb - bx lr - -ASM_PFX(ArmReadNsacr): - mrc p15, 0, r0, c1, c1, 2 - bx lr - -ASM_PFX(ArmWriteNsacr): - mcr p15, 0, r0, c1, c1, 2 - bx lr - -ASM_PFX(ArmReadScr): - mrc p15, 0, r0, c1, c1, 0 - bx lr - -ASM_PFX(ArmWriteScr): - mcr p15, 0, r0, c1, c1, 0 - bx lr - -ASM_PFX(ArmReadMVBar): - mrc p15, 0, r0, c12, c0, 1 - bx lr - -ASM_PFX(ArmWriteMVBar): - mcr p15, 0, r0, c12, c0, 1 - bx lr - -ASM_PFX(ArmCallWFE): - wfe - bx lr - -ASM_PFX(ArmCallSEV): - sev - bx lr - -ASM_PFX(ArmReadSctlr): - mrc p15, 0, R0, c1, c0, 0 @ Read SCTLR into R0 (Read control register configuration data) - bx lr - -ASM_FUNCTION_REMOVE_IF_UNREFERENCED diff --git a/ArmPkg/Library/ArmLib/Common/ArmLibSupport.asm b/ArmPkg/Library/ArmLib/Common/ArmLibSupport.asm deleted file mode 100644 index fd0f332bd6..0000000000 --- a/ArmPkg/Library/ArmLib/Common/ArmLibSupport.asm +++ /dev/null @@ -1,184 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
-// Copyright (c) 2011-2012, ARM Limited. All rights reserved. -// -// This program and the accompanying materials -// are licensed and made available under the terms and conditions of the BSD License -// which accompanies this distribution. The full text of the license may be found at -// http://opensource.org/licenses/bsd-license.php -// -// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -// -//------------------------------------------------------------------------------ - -#include - - INCLUDE AsmMacroIoLib.inc - -#ifdef ARM_CPU_ARMv6 -// No memory barriers for ARMv6 -#define isb -#define dsb -#endif - - EXPORT Cp15IdCode - EXPORT Cp15CacheInfo - EXPORT ArmGetInterruptState - EXPORT ArmGetFiqState - EXPORT ArmGetTTBR0BaseAddress - EXPORT ArmSetTTBR0 - EXPORT ArmSetDomainAccessControl - EXPORT CPSRMaskInsert - EXPORT CPSRRead - EXPORT ArmReadCpacr - EXPORT ArmWriteCpacr - EXPORT ArmWriteAuxCr - EXPORT ArmReadAuxCr - EXPORT ArmInvalidateTlb - EXPORT ArmUpdateTranslationTableEntry - EXPORT ArmReadNsacr - EXPORT ArmWriteNsacr - EXPORT ArmReadScr - EXPORT ArmWriteScr - EXPORT ArmReadMVBar - EXPORT ArmWriteMVBar - EXPORT ArmCallWFE - EXPORT ArmCallSEV - EXPORT ArmReadSctlr - - AREA ArmLibSupport, CODE, READONLY - -Cp15IdCode - mrc p15,0,R0,c0,c0,0 - bx LR - -Cp15CacheInfo - mrc p15,0,R0,c0,c0,1 - bx LR - -ArmGetInterruptState - mrs R0,CPSR - tst R0,#0x80 // Check if IRQ is enabled. - moveq R0,#1 - movne R0,#0 - bx LR - -ArmGetFiqState - mrs R0,CPSR - tst R0,#0x40 // Check if FIQ is enabled. - moveq R0,#1 - movne R0,#0 - bx LR - -ArmSetDomainAccessControl - mcr p15,0,r0,c3,c0,0 - bx lr - -CPSRMaskInsert // on entry, r0 is the mask and r1 is the field to insert - stmfd sp!, {r4-r12, lr} // save all the banked registers - mov r3, sp // copy the stack pointer into a non-banked register - mrs r2, cpsr // read the cpsr - bic r2, r2, r0 // clear mask in the cpsr - and r1, r1, r0 // clear bits outside the mask in the input - orr r2, r2, r1 // set field - msr cpsr_cxsf, r2 // write back cpsr (may have caused a mode switch) - isb - mov sp, r3 // restore stack pointer - ldmfd sp!, {r4-r12, lr} // restore registers - bx lr // return (hopefully thumb-safe!) // return (hopefully thumb-safe!) - -CPSRRead - mrs r0, cpsr - bx lr - -ArmReadCpacr - mrc p15, 0, r0, c1, c0, 2 - bx lr - -ArmWriteCpacr - mcr p15, 0, r0, c1, c0, 2 - isb - bx lr - -ArmWriteAuxCr - mcr p15, 0, r0, c1, c0, 1 - bx lr - -ArmReadAuxCr - mrc p15, 0, r0, c1, c0, 1 - bx lr - -ArmSetTTBR0 - mcr p15,0,r0,c2,c0,0 - isb - bx lr - -ArmGetTTBR0BaseAddress - mrc p15,0,r0,c2,c0,0 - LoadConstantToReg(0xFFFFC000, r1) - and r0, r0, r1 - isb - bx lr - -// -//VOID -//ArmUpdateTranslationTableEntry ( -// IN VOID *TranslationTableEntry // R0 -// IN VOID *MVA // R1 -// ); -ArmUpdateTranslationTableEntry - mcr p15,0,R0,c7,c14,1 // DCCIMVAC Clean data cache by MVA - dsb - mcr p15,0,R1,c8,c7,1 // TLBIMVA TLB Invalidate MVA - mcr p15,0,R9,c7,c5,6 // BPIALL Invalidate Branch predictor array. R9 == NoOp - dsb - isb - bx lr - -ArmInvalidateTlb - mov r0,#0 - mcr p15,0,r0,c8,c7,0 - mcr p15,0,R9,c7,c5,6 // BPIALL Invalidate Branch predictor array. R9 == NoOp - dsb - isb - bx lr - -ArmReadNsacr - mrc p15, 0, r0, c1, c1, 2 - bx lr - -ArmWriteNsacr - mcr p15, 0, r0, c1, c1, 2 - bx lr - -ArmReadScr - mrc p15, 0, r0, c1, c1, 0 - bx lr - -ArmWriteScr - mcr p15, 0, r0, c1, c1, 0 - bx lr - -ArmReadMVBar - mrc p15, 0, r0, c12, c0, 1 - bx lr - -ArmWriteMVBar - mcr p15, 0, r0, c12, c0, 1 - bx lr - -ArmCallWFE - wfe - blx lr - -ArmCallSEV - sev - blx lr - -ArmReadSctlr - mrc p15, 0, R0, c1, c0, 0 // Read SCTLR into R0 (Read control register configuration data) - bx lr - - END diff --git a/ArmPkg/Library/ArmLib/Null/NullArmLib.inf b/ArmPkg/Library/ArmLib/Null/NullArmLib.inf index 33296204a8..d437198109 100644 --- a/ArmPkg/Library/ArmLib/Null/NullArmLib.inf +++ b/ArmPkg/Library/ArmLib/Null/NullArmLib.inf @@ -22,13 +22,15 @@ LIBRARY_CLASS = ArmLib [Sources.common] - ../Common/ArmLibSupport.S | GCC - ../Common/ArmLibSupport.asm | RVCT ../Common/ArmLib.c NullArmLib.c NullArmCacheInformation.c +[Sources.ARM] + ../Common/Arm/ArmLibSupport.S | GCC + ../Common/Arm/ArmLibSupport.asm | RVCT + [Packages] ArmPkg/ArmPkg.dec MdePkg/MdePkg.dec diff --git a/ArmPkg/Library/BdsLib/Arm/BdsLinuxAtag.c b/ArmPkg/Library/BdsLib/Arm/BdsLinuxAtag.c new file mode 100644 index 0000000000..8946b14236 --- /dev/null +++ b/ArmPkg/Library/BdsLib/Arm/BdsLinuxAtag.c @@ -0,0 +1,173 @@ +/** @file +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include "BdsInternal.h" +#include "BdsLinuxLoader.h" + +// Point to the current ATAG +STATIC LINUX_ATAG *mLinuxKernelCurrentAtag; + +STATIC +VOID +SetupCoreTag ( + IN UINT32 PageSize + ) +{ + mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_CORE); + mLinuxKernelCurrentAtag->header.type = ATAG_CORE; + + mLinuxKernelCurrentAtag->body.core_tag.flags = 1; /* ensure read-only */ + mLinuxKernelCurrentAtag->body.core_tag.pagesize = PageSize; /* systems PageSize (4k) */ + mLinuxKernelCurrentAtag->body.core_tag.rootdev = 0; /* zero root device (typically overridden from kernel command line )*/ + + // move pointer to next tag + mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); +} + +STATIC +VOID +SetupMemTag ( + IN UINTN StartAddress, + IN UINT32 Size + ) +{ + mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_MEM); + mLinuxKernelCurrentAtag->header.type = ATAG_MEM; + + mLinuxKernelCurrentAtag->body.mem_tag.start = StartAddress; /* Start of memory chunk for AtagMem */ + mLinuxKernelCurrentAtag->body.mem_tag.size = Size; /* Size of memory chunk for AtagMem */ + + // move pointer to next tag + mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); +} + +STATIC +VOID +SetupCmdlineTag ( + IN CONST CHAR8 *CmdLine + ) +{ + UINT32 LineLength; + + // Increment the line length by 1 to account for the null string terminator character + LineLength = AsciiStrLen(CmdLine) + 1; + + /* Check for NULL strings. + * Do not insert a tag for an empty CommandLine, don't even modify the tag address pointer. + * Remember, you have at least one null string terminator character. + */ + if(LineLength > 1) { + mLinuxKernelCurrentAtag->header.size = ((UINT32)sizeof(LINUX_ATAG_HEADER) + LineLength + (UINT32)3) >> 2; + mLinuxKernelCurrentAtag->header.type = ATAG_CMDLINE; + + /* place CommandLine into tag */ + AsciiStrCpy(mLinuxKernelCurrentAtag->body.cmdline_tag.cmdline, CmdLine); + + // move pointer to next tag + mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); + } +} + +STATIC +VOID +SetupInitrdTag ( + IN UINT32 InitrdImage, + IN UINT32 InitrdImageSize + ) +{ + mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_INITRD2); + mLinuxKernelCurrentAtag->header.type = ATAG_INITRD2; + + mLinuxKernelCurrentAtag->body.initrd2_tag.start = InitrdImage; + mLinuxKernelCurrentAtag->body.initrd2_tag.size = InitrdImageSize; + + // Move pointer to next tag + mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); +} +STATIC +VOID +SetupEndTag ( + VOID + ) +{ + // Empty tag ends list; this has zero length and no body + mLinuxKernelCurrentAtag->header.type = ATAG_NONE; + mLinuxKernelCurrentAtag->header.size = 0; + + /* We can not calculate the next address by using the standard macro: + * Params = next_tag_address(Params); + * because it relies on the header.size, which here it is 0 (zero). + * The easiest way is to add the sizeof(mLinuxKernelCurrentAtag->header). + */ + mLinuxKernelCurrentAtag = (LINUX_ATAG*)((UINT32)mLinuxKernelCurrentAtag + sizeof(mLinuxKernelCurrentAtag->header)); +} + +EFI_STATUS +PrepareAtagList ( + IN CONST CHAR8* CommandLineString, + IN EFI_PHYSICAL_ADDRESS InitrdImage, + IN UINTN InitrdImageSize, + OUT EFI_PHYSICAL_ADDRESS *AtagBase, + OUT UINT32 *AtagSize + ) +{ + EFI_STATUS Status; + LIST_ENTRY *ResourceLink; + LIST_ENTRY ResourceList; + EFI_PHYSICAL_ADDRESS AtagStartAddress; + BDS_SYSTEM_MEMORY_RESOURCE *Resource; + + AtagStartAddress = LINUX_ATAG_MAX_OFFSET; + Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_WARN, "Warning: Failed to allocate Atag at 0x%lX (%r). The Atag will be allocated somewhere else in System Memory.\n", AtagStartAddress, Status)); + Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress); + ASSERT_EFI_ERROR(Status); + } + + // Ready to setup the atag list + mLinuxKernelCurrentAtag = (LINUX_ATAG*)(UINTN)AtagStartAddress; + + // Standard core tag 4k PageSize + SetupCoreTag( (UINT32)SIZE_4KB ); + + // Physical memory setup + GetSystemMemoryResources (&ResourceList); + ResourceLink = ResourceList.ForwardLink; + while (ResourceLink != NULL && ResourceLink != &ResourceList) { + Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceLink; + DEBUG((EFI_D_INFO,"- [0x%08X,0x%08X]\n",(UINT32)Resource->PhysicalStart,(UINT32)Resource->PhysicalStart+(UINT32)Resource->ResourceLength)); + SetupMemTag( (UINT32)Resource->PhysicalStart, (UINT32)Resource->ResourceLength ); + ResourceLink = ResourceLink->ForwardLink; + } + + // CommandLine setting root device + if (CommandLineString) { + SetupCmdlineTag (CommandLineString); + } + + if (InitrdImageSize > 0 && InitrdImage != 0) { + SetupInitrdTag ((UINT32)InitrdImage, (UINT32)InitrdImageSize); + } + + // End of tags + SetupEndTag(); + + // Calculate atag list size + *AtagBase = AtagStartAddress; + *AtagSize = (UINT32)mLinuxKernelCurrentAtag - (UINT32)AtagStartAddress + 1; + + return EFI_SUCCESS; +} + diff --git a/ArmPkg/Library/BdsLib/Arm/BdsLinuxLoader.c b/ArmPkg/Library/BdsLib/Arm/BdsLinuxLoader.c new file mode 100644 index 0000000000..e3249e1307 --- /dev/null +++ b/ArmPkg/Library/BdsLib/Arm/BdsLinuxLoader.c @@ -0,0 +1,274 @@ +/** @file +* +* Copyright (c) 2011-2012, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include "BdsInternal.h" +#include "BdsLinuxLoader.h" + +#define ALIGN32_BELOW(addr) ALIGN_POINTER(addr - 32,32) + +STATIC +EFI_STATUS +PreparePlatformHardware ( + VOID + ) +{ + //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called. + + // Clean, invalidate, disable data cache + ArmDisableDataCache(); + ArmCleanInvalidateDataCache(); + + // Invalidate and disable the Instruction cache + ArmDisableInstructionCache (); + ArmInvalidateInstructionCache (); + + // Turn off MMU + ArmDisableMmu(); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +StartLinux ( + IN EFI_PHYSICAL_ADDRESS LinuxImage, + IN UINTN LinuxImageSize, + IN EFI_PHYSICAL_ADDRESS KernelParamsAddress, + IN UINTN KernelParamsSize, + IN UINT32 MachineType + ) +{ + EFI_STATUS Status; + LINUX_KERNEL LinuxKernel; + + // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on + // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event. + Status = ShutdownUefiBootServices (); + if(EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR,"ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status)); + goto Exit; + } + + // Move the kernel parameters to any address inside the first 1MB. + // This is necessary because the ARM Linux kernel requires + // the FTD / ATAG List to reside entirely inside the first 1MB of + // physical memory. + //Note: There is no requirement on the alignment + if (MachineType != ARM_FDT_MACHINE_TYPE) { + if (((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxAtagMaxOffset))) { + KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_ATAG_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize); + } + } else { + if (((UINTN)KernelParamsAddress > LINUX_FDT_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxFdtMaxOffset))) { + KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_FDT_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize); + } + } + + if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) { + //Note: There is no requirement on the alignment + LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW(LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize); + } else { + LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage; + } + + // Check if the Linux Image is a uImage + if (*(UINT32*)LinuxKernel == LINUX_UIMAGE_SIGNATURE) { + // Assume the Image Entry Point is just after the uImage header (64-byte size) + LinuxKernel = (LINUX_KERNEL)((UINTN)LinuxKernel + 64); + LinuxImageSize -= 64; + } + + //TODO: Check there is no overlapping between kernel and Atag + + // + // Switch off interrupts, caches, mmu, etc + // + Status = PreparePlatformHardware (); + ASSERT_EFI_ERROR(Status); + + // Register and print out performance information + PERF_END (NULL, "BDS", NULL, 0); + if (PerformanceMeasurementEnabled ()) { + PrintPerformance (); + } + + // + // Start the Linux Kernel + // + + // Outside BootServices, so can't use Print(); + DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n")); + + // Jump to kernel with register set + LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress); + + // Kernel should never exit + // After Life services are not provided + ASSERT(FALSE); + +Exit: + // Only be here if we fail to start Linux + Print (L"ERROR : Can not start the kernel. Status=0x%X\n", Status); + + // Free Runtimee Memory (kernel and FDT) + return Status; +} + +/** + Start a Linux kernel from a Device Path + + @param LinuxKernel Device Path to the Linux Kernel + @param Parameters Linux kernel arguments + @param Fdt Device Path to the Flat Device Tree + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. + +**/ +EFI_STATUS +BdsBootLinuxAtag ( + IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, + IN CONST CHAR8* CommandLineArguments + ) +{ + EFI_STATUS Status; + UINT32 LinuxImageSize; + UINT32 InitrdImageSize = 0; + UINT32 AtagSize; + EFI_PHYSICAL_ADDRESS AtagBase; + EFI_PHYSICAL_ADDRESS LinuxImage; + EFI_PHYSICAL_ADDRESS InitrdImage; + + PERF_START (NULL, "BDS", NULL, 0); + + // Load the Linux kernel from a device path + LinuxImage = LINUX_KERNEL_MAX_OFFSET; + Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find Linux kernel.\n"); + return Status; + } + + if (InitrdDevicePath) { + // Load the initrd near to the Linux kernel + InitrdImage = LINUX_KERNEL_MAX_OFFSET; + Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize); + if (Status == EFI_OUT_OF_RESOURCES) { + Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); + } + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find initrd image.\n"); + return Status; + } + + // Check if the initrd is a uInitrd + if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) { + // Skip the 64-byte image header + InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64); + InitrdImageSize -= 64; + } + } + + // + // Setup the Linux Kernel Parameters + // + + // By setting address=0 we leave the memory allocation to the function + Status = PrepareAtagList (CommandLineArguments, InitrdImage, InitrdImageSize, &AtagBase, &AtagSize); + if (EFI_ERROR(Status)) { + Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status); + return Status; + } + + return StartLinux (LinuxImage, LinuxImageSize, AtagBase, AtagSize, PcdGet32(PcdArmMachineType)); +} + +/** + Start a Linux kernel from a Device Path + + @param LinuxKernel Device Path to the Linux Kernel + @param Parameters Linux kernel arguments + @param Fdt Device Path to the Flat Device Tree + + @retval EFI_SUCCESS All drivers have been connected + @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found + @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. + +**/ +EFI_STATUS +BdsBootLinuxFdt ( + IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, + IN CONST CHAR8* CommandLineArguments, + IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath + ) +{ + EFI_STATUS Status; + UINT32 LinuxImageSize; + UINT32 InitrdImageSize = 0; + UINT32 FdtBlobSize; + EFI_PHYSICAL_ADDRESS FdtBlobBase; + EFI_PHYSICAL_ADDRESS LinuxImage; + EFI_PHYSICAL_ADDRESS InitrdImage; + + PERF_START (NULL, "BDS", NULL, 0); + + // Load the Linux kernel from a device path + LinuxImage = LINUX_KERNEL_MAX_OFFSET; + Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find Linux kernel.\n"); + return Status; + } + + if (InitrdDevicePath) { + InitrdImage = LINUX_KERNEL_MAX_OFFSET; + Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize); + if (Status == EFI_OUT_OF_RESOURCES) { + Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); + } + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find initrd image.\n"); + return Status; + } + + // Check if the initrd is a uInitrd + if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) { + // Skip the 64-byte image header + InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64); + InitrdImageSize -= 64; + } + } + + // Load the FDT binary from a device path. The FDT will be reloaded later to a more appropriate location for the Linux kernel. + FdtBlobBase = 0; + Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize); + if (EFI_ERROR(Status)) { + Print (L"ERROR: Did not find Device Tree blob.\n"); + return Status; + } + + // Update the Fdt with the Initrd information. The FDT will increase in size. + // By setting address=0 we leave the memory allocation to the function + Status = PrepareFdt (CommandLineArguments, InitrdImage, InitrdImageSize, &FdtBlobBase, &FdtBlobSize); + if (EFI_ERROR(Status)) { + Print(L"ERROR: Can not load kernel with FDT. Status=%r\n", Status); + return Status; + } + + return StartLinux (LinuxImage, LinuxImageSize, FdtBlobBase, FdtBlobSize, ARM_FDT_MACHINE_TYPE); +} + diff --git a/ArmPkg/Library/BdsLib/BdsLib.inf b/ArmPkg/Library/BdsLib/BdsLib.inf index d9439d983a..7f8b03eb59 100644 --- a/ArmPkg/Library/BdsLib/BdsLib.inf +++ b/ArmPkg/Library/BdsLib/BdsLib.inf @@ -25,11 +25,12 @@ BdsAppLoader.c BdsHelper.c BdsLoadOption.c - - BdsLinuxLoader.c - BdsLinuxAtag.c BdsLinuxFdt.c +[Sources.ARM] + Arm/BdsLinuxLoader.c + Arm/BdsLinuxAtag.c + [Packages] MdePkg/MdePkg.dec EmbeddedPkg/EmbeddedPkg.dec diff --git a/ArmPkg/Library/BdsLib/BdsLinuxAtag.c b/ArmPkg/Library/BdsLib/BdsLinuxAtag.c deleted file mode 100644 index 8946b14236..0000000000 --- a/ArmPkg/Library/BdsLib/BdsLinuxAtag.c +++ /dev/null @@ -1,173 +0,0 @@ -/** @file -* -* Copyright (c) 2011-2012, ARM Limited. All rights reserved. -* -* This program and the accompanying materials -* are licensed and made available under the terms and conditions of the BSD License -* which accompanies this distribution. The full text of the license may be found at -* http://opensource.org/licenses/bsd-license.php -* -* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -* -**/ - -#include "BdsInternal.h" -#include "BdsLinuxLoader.h" - -// Point to the current ATAG -STATIC LINUX_ATAG *mLinuxKernelCurrentAtag; - -STATIC -VOID -SetupCoreTag ( - IN UINT32 PageSize - ) -{ - mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_CORE); - mLinuxKernelCurrentAtag->header.type = ATAG_CORE; - - mLinuxKernelCurrentAtag->body.core_tag.flags = 1; /* ensure read-only */ - mLinuxKernelCurrentAtag->body.core_tag.pagesize = PageSize; /* systems PageSize (4k) */ - mLinuxKernelCurrentAtag->body.core_tag.rootdev = 0; /* zero root device (typically overridden from kernel command line )*/ - - // move pointer to next tag - mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); -} - -STATIC -VOID -SetupMemTag ( - IN UINTN StartAddress, - IN UINT32 Size - ) -{ - mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_MEM); - mLinuxKernelCurrentAtag->header.type = ATAG_MEM; - - mLinuxKernelCurrentAtag->body.mem_tag.start = StartAddress; /* Start of memory chunk for AtagMem */ - mLinuxKernelCurrentAtag->body.mem_tag.size = Size; /* Size of memory chunk for AtagMem */ - - // move pointer to next tag - mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); -} - -STATIC -VOID -SetupCmdlineTag ( - IN CONST CHAR8 *CmdLine - ) -{ - UINT32 LineLength; - - // Increment the line length by 1 to account for the null string terminator character - LineLength = AsciiStrLen(CmdLine) + 1; - - /* Check for NULL strings. - * Do not insert a tag for an empty CommandLine, don't even modify the tag address pointer. - * Remember, you have at least one null string terminator character. - */ - if(LineLength > 1) { - mLinuxKernelCurrentAtag->header.size = ((UINT32)sizeof(LINUX_ATAG_HEADER) + LineLength + (UINT32)3) >> 2; - mLinuxKernelCurrentAtag->header.type = ATAG_CMDLINE; - - /* place CommandLine into tag */ - AsciiStrCpy(mLinuxKernelCurrentAtag->body.cmdline_tag.cmdline, CmdLine); - - // move pointer to next tag - mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); - } -} - -STATIC -VOID -SetupInitrdTag ( - IN UINT32 InitrdImage, - IN UINT32 InitrdImageSize - ) -{ - mLinuxKernelCurrentAtag->header.size = tag_size(LINUX_ATAG_INITRD2); - mLinuxKernelCurrentAtag->header.type = ATAG_INITRD2; - - mLinuxKernelCurrentAtag->body.initrd2_tag.start = InitrdImage; - mLinuxKernelCurrentAtag->body.initrd2_tag.size = InitrdImageSize; - - // Move pointer to next tag - mLinuxKernelCurrentAtag = next_tag_address(mLinuxKernelCurrentAtag); -} -STATIC -VOID -SetupEndTag ( - VOID - ) -{ - // Empty tag ends list; this has zero length and no body - mLinuxKernelCurrentAtag->header.type = ATAG_NONE; - mLinuxKernelCurrentAtag->header.size = 0; - - /* We can not calculate the next address by using the standard macro: - * Params = next_tag_address(Params); - * because it relies on the header.size, which here it is 0 (zero). - * The easiest way is to add the sizeof(mLinuxKernelCurrentAtag->header). - */ - mLinuxKernelCurrentAtag = (LINUX_ATAG*)((UINT32)mLinuxKernelCurrentAtag + sizeof(mLinuxKernelCurrentAtag->header)); -} - -EFI_STATUS -PrepareAtagList ( - IN CONST CHAR8* CommandLineString, - IN EFI_PHYSICAL_ADDRESS InitrdImage, - IN UINTN InitrdImageSize, - OUT EFI_PHYSICAL_ADDRESS *AtagBase, - OUT UINT32 *AtagSize - ) -{ - EFI_STATUS Status; - LIST_ENTRY *ResourceLink; - LIST_ENTRY ResourceList; - EFI_PHYSICAL_ADDRESS AtagStartAddress; - BDS_SYSTEM_MEMORY_RESOURCE *Resource; - - AtagStartAddress = LINUX_ATAG_MAX_OFFSET; - Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress); - if (EFI_ERROR(Status)) { - DEBUG ((EFI_D_WARN, "Warning: Failed to allocate Atag at 0x%lX (%r). The Atag will be allocated somewhere else in System Memory.\n", AtagStartAddress, Status)); - Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(ATAG_MAX_SIZE), &AtagStartAddress); - ASSERT_EFI_ERROR(Status); - } - - // Ready to setup the atag list - mLinuxKernelCurrentAtag = (LINUX_ATAG*)(UINTN)AtagStartAddress; - - // Standard core tag 4k PageSize - SetupCoreTag( (UINT32)SIZE_4KB ); - - // Physical memory setup - GetSystemMemoryResources (&ResourceList); - ResourceLink = ResourceList.ForwardLink; - while (ResourceLink != NULL && ResourceLink != &ResourceList) { - Resource = (BDS_SYSTEM_MEMORY_RESOURCE*)ResourceLink; - DEBUG((EFI_D_INFO,"- [0x%08X,0x%08X]\n",(UINT32)Resource->PhysicalStart,(UINT32)Resource->PhysicalStart+(UINT32)Resource->ResourceLength)); - SetupMemTag( (UINT32)Resource->PhysicalStart, (UINT32)Resource->ResourceLength ); - ResourceLink = ResourceLink->ForwardLink; - } - - // CommandLine setting root device - if (CommandLineString) { - SetupCmdlineTag (CommandLineString); - } - - if (InitrdImageSize > 0 && InitrdImage != 0) { - SetupInitrdTag ((UINT32)InitrdImage, (UINT32)InitrdImageSize); - } - - // End of tags - SetupEndTag(); - - // Calculate atag list size - *AtagBase = AtagStartAddress; - *AtagSize = (UINT32)mLinuxKernelCurrentAtag - (UINT32)AtagStartAddress + 1; - - return EFI_SUCCESS; -} - diff --git a/ArmPkg/Library/BdsLib/BdsLinuxLoader.c b/ArmPkg/Library/BdsLib/BdsLinuxLoader.c deleted file mode 100644 index e3249e1307..0000000000 --- a/ArmPkg/Library/BdsLib/BdsLinuxLoader.c +++ /dev/null @@ -1,274 +0,0 @@ -/** @file -* -* Copyright (c) 2011-2012, ARM Limited. All rights reserved. -* -* This program and the accompanying materials -* are licensed and made available under the terms and conditions of the BSD License -* which accompanies this distribution. The full text of the license may be found at -* http://opensource.org/licenses/bsd-license.php -* -* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -* -**/ - -#include "BdsInternal.h" -#include "BdsLinuxLoader.h" - -#define ALIGN32_BELOW(addr) ALIGN_POINTER(addr - 32,32) - -STATIC -EFI_STATUS -PreparePlatformHardware ( - VOID - ) -{ - //Note: Interrupts will be disabled by the GIC driver when ExitBootServices() will be called. - - // Clean, invalidate, disable data cache - ArmDisableDataCache(); - ArmCleanInvalidateDataCache(); - - // Invalidate and disable the Instruction cache - ArmDisableInstructionCache (); - ArmInvalidateInstructionCache (); - - // Turn off MMU - ArmDisableMmu(); - - return EFI_SUCCESS; -} - -STATIC -EFI_STATUS -StartLinux ( - IN EFI_PHYSICAL_ADDRESS LinuxImage, - IN UINTN LinuxImageSize, - IN EFI_PHYSICAL_ADDRESS KernelParamsAddress, - IN UINTN KernelParamsSize, - IN UINT32 MachineType - ) -{ - EFI_STATUS Status; - LINUX_KERNEL LinuxKernel; - - // Shut down UEFI boot services. ExitBootServices() will notify every driver that created an event on - // ExitBootServices event. Example the Interrupt DXE driver will disable the interrupts on this event. - Status = ShutdownUefiBootServices (); - if(EFI_ERROR(Status)) { - DEBUG((EFI_D_ERROR,"ERROR: Can not shutdown UEFI boot services. Status=0x%X\n", Status)); - goto Exit; - } - - // Move the kernel parameters to any address inside the first 1MB. - // This is necessary because the ARM Linux kernel requires - // the FTD / ATAG List to reside entirely inside the first 1MB of - // physical memory. - //Note: There is no requirement on the alignment - if (MachineType != ARM_FDT_MACHINE_TYPE) { - if (((UINTN)KernelParamsAddress > LINUX_ATAG_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxAtagMaxOffset))) { - KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_ATAG_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize); - } - } else { - if (((UINTN)KernelParamsAddress > LINUX_FDT_MAX_OFFSET) && (KernelParamsSize < PcdGet32(PcdArmLinuxFdtMaxOffset))) { - KernelParamsAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CopyMem (ALIGN32_BELOW(LINUX_FDT_MAX_OFFSET - KernelParamsSize), (VOID*)(UINTN)KernelParamsAddress, KernelParamsSize); - } - } - - if ((UINTN)LinuxImage > LINUX_KERNEL_MAX_OFFSET) { - //Note: There is no requirement on the alignment - LinuxKernel = (LINUX_KERNEL)CopyMem (ALIGN32_BELOW(LINUX_KERNEL_MAX_OFFSET - LinuxImageSize), (VOID*)(UINTN)LinuxImage, LinuxImageSize); - } else { - LinuxKernel = (LINUX_KERNEL)(UINTN)LinuxImage; - } - - // Check if the Linux Image is a uImage - if (*(UINT32*)LinuxKernel == LINUX_UIMAGE_SIGNATURE) { - // Assume the Image Entry Point is just after the uImage header (64-byte size) - LinuxKernel = (LINUX_KERNEL)((UINTN)LinuxKernel + 64); - LinuxImageSize -= 64; - } - - //TODO: Check there is no overlapping between kernel and Atag - - // - // Switch off interrupts, caches, mmu, etc - // - Status = PreparePlatformHardware (); - ASSERT_EFI_ERROR(Status); - - // Register and print out performance information - PERF_END (NULL, "BDS", NULL, 0); - if (PerformanceMeasurementEnabled ()) { - PrintPerformance (); - } - - // - // Start the Linux Kernel - // - - // Outside BootServices, so can't use Print(); - DEBUG((EFI_D_ERROR, "\nStarting the kernel:\n\n")); - - // Jump to kernel with register set - LinuxKernel ((UINTN)0, MachineType, (UINTN)KernelParamsAddress); - - // Kernel should never exit - // After Life services are not provided - ASSERT(FALSE); - -Exit: - // Only be here if we fail to start Linux - Print (L"ERROR : Can not start the kernel. Status=0x%X\n", Status); - - // Free Runtimee Memory (kernel and FDT) - return Status; -} - -/** - Start a Linux kernel from a Device Path - - @param LinuxKernel Device Path to the Linux Kernel - @param Parameters Linux kernel arguments - @param Fdt Device Path to the Flat Device Tree - - @retval EFI_SUCCESS All drivers have been connected - @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found - @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. - -**/ -EFI_STATUS -BdsBootLinuxAtag ( - IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, - IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, - IN CONST CHAR8* CommandLineArguments - ) -{ - EFI_STATUS Status; - UINT32 LinuxImageSize; - UINT32 InitrdImageSize = 0; - UINT32 AtagSize; - EFI_PHYSICAL_ADDRESS AtagBase; - EFI_PHYSICAL_ADDRESS LinuxImage; - EFI_PHYSICAL_ADDRESS InitrdImage; - - PERF_START (NULL, "BDS", NULL, 0); - - // Load the Linux kernel from a device path - LinuxImage = LINUX_KERNEL_MAX_OFFSET; - Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); - if (EFI_ERROR(Status)) { - Print (L"ERROR: Did not find Linux kernel.\n"); - return Status; - } - - if (InitrdDevicePath) { - // Load the initrd near to the Linux kernel - InitrdImage = LINUX_KERNEL_MAX_OFFSET; - Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize); - if (Status == EFI_OUT_OF_RESOURCES) { - Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); - } - if (EFI_ERROR(Status)) { - Print (L"ERROR: Did not find initrd image.\n"); - return Status; - } - - // Check if the initrd is a uInitrd - if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) { - // Skip the 64-byte image header - InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64); - InitrdImageSize -= 64; - } - } - - // - // Setup the Linux Kernel Parameters - // - - // By setting address=0 we leave the memory allocation to the function - Status = PrepareAtagList (CommandLineArguments, InitrdImage, InitrdImageSize, &AtagBase, &AtagSize); - if (EFI_ERROR(Status)) { - Print(L"ERROR: Can not prepare ATAG list. Status=0x%X\n", Status); - return Status; - } - - return StartLinux (LinuxImage, LinuxImageSize, AtagBase, AtagSize, PcdGet32(PcdArmMachineType)); -} - -/** - Start a Linux kernel from a Device Path - - @param LinuxKernel Device Path to the Linux Kernel - @param Parameters Linux kernel arguments - @param Fdt Device Path to the Flat Device Tree - - @retval EFI_SUCCESS All drivers have been connected - @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found - @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. - -**/ -EFI_STATUS -BdsBootLinuxFdt ( - IN EFI_DEVICE_PATH_PROTOCOL* LinuxKernelDevicePath, - IN EFI_DEVICE_PATH_PROTOCOL* InitrdDevicePath, - IN CONST CHAR8* CommandLineArguments, - IN EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath - ) -{ - EFI_STATUS Status; - UINT32 LinuxImageSize; - UINT32 InitrdImageSize = 0; - UINT32 FdtBlobSize; - EFI_PHYSICAL_ADDRESS FdtBlobBase; - EFI_PHYSICAL_ADDRESS LinuxImage; - EFI_PHYSICAL_ADDRESS InitrdImage; - - PERF_START (NULL, "BDS", NULL, 0); - - // Load the Linux kernel from a device path - LinuxImage = LINUX_KERNEL_MAX_OFFSET; - Status = BdsLoadImage (LinuxKernelDevicePath, AllocateMaxAddress, &LinuxImage, &LinuxImageSize); - if (EFI_ERROR(Status)) { - Print (L"ERROR: Did not find Linux kernel.\n"); - return Status; - } - - if (InitrdDevicePath) { - InitrdImage = LINUX_KERNEL_MAX_OFFSET; - Status = BdsLoadImage (InitrdDevicePath, AllocateMaxAddress, &InitrdImage, &InitrdImageSize); - if (Status == EFI_OUT_OF_RESOURCES) { - Status = BdsLoadImage (InitrdDevicePath, AllocateAnyPages, &InitrdImage, &InitrdImageSize); - } - if (EFI_ERROR(Status)) { - Print (L"ERROR: Did not find initrd image.\n"); - return Status; - } - - // Check if the initrd is a uInitrd - if (*(UINT32*)((UINTN)InitrdImage) == LINUX_UIMAGE_SIGNATURE) { - // Skip the 64-byte image header - InitrdImage = (EFI_PHYSICAL_ADDRESS)((UINTN)InitrdImage + 64); - InitrdImageSize -= 64; - } - } - - // Load the FDT binary from a device path. The FDT will be reloaded later to a more appropriate location for the Linux kernel. - FdtBlobBase = 0; - Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize); - if (EFI_ERROR(Status)) { - Print (L"ERROR: Did not find Device Tree blob.\n"); - return Status; - } - - // Update the Fdt with the Initrd information. The FDT will increase in size. - // By setting address=0 we leave the memory allocation to the function - Status = PrepareFdt (CommandLineArguments, InitrdImage, InitrdImageSize, &FdtBlobBase, &FdtBlobSize); - if (EFI_ERROR(Status)) { - Print(L"ERROR: Can not load kernel with FDT. Status=%r\n", Status); - return Status; - } - - return StartLinux (LinuxImage, LinuxImageSize, FdtBlobBase, FdtBlobSize, ARM_FDT_MACHINE_TYPE); -} - diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/Arm/DebugAgentException.S b/ArmPkg/Library/DebugAgentSymbolsBaseLib/Arm/DebugAgentException.S new file mode 100644 index 0000000000..d92acfeacb --- /dev/null +++ b/ArmPkg/Library/DebugAgentSymbolsBaseLib/Arm/DebugAgentException.S @@ -0,0 +1,276 @@ +#------------------------------------------------------------------------------ +# +# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+# Copyright (c) 2011 - 2012, ARM Ltd. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#------------------------------------------------------------------------------ + +#include + +/* + +This is the stack constructed by the exception handler (low address to high address) + # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM + Reg Offset + === ====== + R0 0x00 # stmfd SP!,{R0-R12} + R1 0x04 + R2 0x08 + R3 0x0c + R4 0x10 + R5 0x14 + R6 0x18 + R7 0x1c + R8 0x20 + R9 0x24 + R10 0x28 + R11 0x2c + R12 0x30 + SP 0x34 # reserved via adding 0x20 (32) to the SP + LR 0x38 + PC 0x3c + CPSR 0x40 + DFSR 0x44 + DFAR 0x48 + IFSR 0x4c + IFAR 0x50 + + LR 0x54 # SVC Link register (we need to restore it) + + LR 0x58 # pushed by srsfd + CPSR 0x5c + + */ + +GCC_ASM_EXPORT(DebugAgentVectorTable) +GCC_ASM_IMPORT(DefaultExceptionHandler) + +.text +#if !defined(__APPLE__) +.fpu neon @ makes vpush/vpop assemble +#endif +.align 5 + + +// +// This code gets copied to the ARM vector table +// ExceptionHandlersStart - ExceptionHandlersEnd gets copied +// +ASM_PFX(DebugAgentVectorTable): + b ASM_PFX(ResetEntry) + b ASM_PFX(UndefinedInstructionEntry) + b ASM_PFX(SoftwareInterruptEntry) + b ASM_PFX(PrefetchAbortEntry) + b ASM_PFX(DataAbortEntry) + b ASM_PFX(ReservedExceptionEntry) + b ASM_PFX(IrqEntry) + b ASM_PFX(FiqEntry) + +ASM_PFX(ResetEntry): + srsdb #0x13! @ Store return state on SVC stack + @ We are already in SVC mode + + stmfd SP!,{LR} @ Store the link register for the current mode + sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} @ Store the register state + + mov R0,#0 @ ExceptionType + ldr R1,ASM_PFX(CommonExceptionEntry) + bx R1 + +ASM_PFX(UndefinedInstructionEntry): + sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry + srsdb #0x13! @ Store return state on SVC stack + cps #0x13 @ Switch to SVC for common stack + stmfd SP!,{LR} @ Store the link register for the current mode + sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} @ Store the register state + + mov R0,#1 @ ExceptionType + ldr R1,ASM_PFX(CommonExceptionEntry) + bx R1 + +ASM_PFX(SoftwareInterruptEntry): + sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry + srsdb #0x13! @ Store return state on SVC stack + @ We are already in SVC mode + stmfd SP!,{LR} @ Store the link register for the current mode + sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} @ Store the register state + + mov R0,#2 @ ExceptionType + ldr R1,ASM_PFX(CommonExceptionEntry) + bx R1 + +ASM_PFX(PrefetchAbortEntry): + sub LR,LR,#4 + srsdb #0x13! @ Store return state on SVC stack + cps #0x13 @ Switch to SVC for common stack + stmfd SP!,{LR} @ Store the link register for the current mode + sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} @ Store the register state + + mov R0,#3 @ ExceptionType + ldr R1,ASM_PFX(CommonExceptionEntry) + bx R1 + +ASM_PFX(DataAbortEntry): + sub LR,LR,#8 + srsdb #0x13! @ Store return state on SVC stack + cps #0x13 @ Switch to SVC for common stack + stmfd SP!,{LR} @ Store the link register for the current mode + sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} @ Store the register state + + mov R0,#4 + ldr R1,ASM_PFX(CommonExceptionEntry) + bx R1 + +ASM_PFX(ReservedExceptionEntry): + srsdb #0x13! @ Store return state on SVC stack + cps #0x13 @ Switch to SVC for common stack + stmfd SP!,{LR} @ Store the link register for the current mode + sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} @ Store the register state + + mov R0,#5 + ldr R1,ASM_PFX(CommonExceptionEntry) + bx R1 + +ASM_PFX(IrqEntry): + sub LR,LR,#4 + srsdb #0x13! @ Store return state on SVC stack + cps #0x13 @ Switch to SVC for common stack + stmfd SP!,{LR} @ Store the link register for the current mode + sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} @ Store the register state + + mov R0,#6 @ ExceptionType + ldr R1,ASM_PFX(CommonExceptionEntry) + bx R1 + +ASM_PFX(FiqEntry): + sub LR,LR,#4 + srsdb #0x13! @ Store return state on SVC stack + cps #0x13 @ Switch to SVC for common stack + stmfd SP!,{LR} @ Store the link register for the current mode + sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} @ Store the register state + @ Since we have already switch to SVC R8_fiq - R12_fiq + @ never get used or saved + mov R0,#7 @ ExceptionType + ldr R1,ASM_PFX(CommonExceptionEntry) + bx R1 + +// +// This gets patched by the C code that patches in the vector table +// +ASM_PFX(CommonExceptionEntry): + .word ASM_PFX(AsmCommonExceptionEntry) + +ASM_PFX(ExceptionHandlersEnd): + +// +// This code runs from CpuDxe driver loaded address. It is patched into +// CommonExceptionEntry. +// +ASM_PFX(AsmCommonExceptionEntry): + mrc p15, 0, R1, c6, c0, 2 @ Read IFAR + str R1, [SP, #0x50] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR + + mrc p15, 0, R1, c5, c0, 1 @ Read IFSR + str R1, [SP, #0x4c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR + + mrc p15, 0, R1, c6, c0, 0 @ Read DFAR + str R1, [SP, #0x48] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR + + mrc p15, 0, R1, c5, c0, 0 @ Read DFSR + str R1, [SP, #0x44] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR + + ldr R1, [SP, #0x5c] @ srsdb saved pre-exception CPSR on the stack + str R1, [SP, #0x40] @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR + + add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR + and R3, R1, #0x1f @ Check CPSR to see if User or System Mode + cmp R3, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1df)) + cmpne R3, #0x10 @ + stmeqed R2, {lr}^ @ save unbanked lr + @ else + stmneed R2, {lr} @ save SVC lr + + + ldr R5, [SP, #0x58] @ PC is the LR pushed by srsfd + @ Check to see if we have to adjust for Thumb entry + sub r4, r0, #1 @ if (ExceptionType == 1 || ExceptionType ==2)) { + cmp r4, #1 @ // UND & SVC have differnt LR adjust for Thumb + bhi NoAdjustNeeded + + tst r1, #0x20 @ if ((CPSR & T)) == T) { // Thumb Mode on entry + addne R5, R5, #2 @ PC += 2@ + str R5,[SP,#0x58] @ Update LR value pused by srsfd + +NoAdjustNeeded: + + str R5, [SP, #0x3c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC + + sub R1, SP, #0x60 @ We pused 0x60 bytes on the stack + str R1, [SP, #0x34] @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP + + @ R0 is ExceptionType + mov R1,SP @ R1 is SystemContext + +#if (FixedPcdGet32(PcdVFPEnabled)) + vpush {d0-d15} @ save vstm registers in case they are used in optimizations +#endif + +/* +VOID +EFIAPI +DefaultExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, R0 + IN OUT EFI_SYSTEM_CONTEXT SystemContext R1 + ) + +*/ + blx ASM_PFX(DefaultExceptionHandler) @ Call exception handler + +#if (FixedPcdGet32(PcdVFPEnabled)) + vpop {d0-d15} +#endif + + ldr R1, [SP, #0x4c] @ Restore EFI_SYSTEM_CONTEXT_ARM.IFSR + mcr p15, 0, R1, c5, c0, 1 @ Write IFSR + + ldr R1, [SP, #0x44] @ sRestore EFI_SYSTEM_CONTEXT_ARM.DFSR + mcr p15, 0, R1, c5, c0, 0 @ Write DFSR + + ldr R1,[SP,#0x3c] @ EFI_SYSTEM_CONTEXT_ARM.PC + str R1,[SP,#0x58] @ Store it back to srsfd stack slot so it can be restored + + ldr R1,[SP,#0x40] @ EFI_SYSTEM_CONTEXT_ARM.CPSR + str R1,[SP,#0x5c] @ Store it back to srsfd stack slot so it can be restored + + add R3, SP, #0x54 @ Make R3 point to SVC LR saved on entry + add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR + and R1, R1, #0x1f @ Check to see if User or System Mode + cmp R1, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f)) + cmpne R1, #0x10 @ + ldmeqed R2, {lr}^ @ restore unbanked lr + @ else + ldmneed R3, {lr} @ restore SVC lr, via ldmfd SP!, {LR} + + ldmfd SP!,{R0-R12} @ Restore general purpose registers + @ Exception handler can not change SP + + add SP,SP,#0x20 @ Clear out the remaining stack space + ldmfd SP!,{LR} @ restore the link register for this context + rfefd SP! @ return from exception via srsfd stack slot + diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/Arm/DebugAgentException.asm b/ArmPkg/Library/DebugAgentSymbolsBaseLib/Arm/DebugAgentException.asm new file mode 100644 index 0000000000..f281c0603f --- /dev/null +++ b/ArmPkg/Library/DebugAgentSymbolsBaseLib/Arm/DebugAgentException.asm @@ -0,0 +1,273 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+// Copyright (c) 2011 - 2012, ARM Ltd. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +//------------------------------------------------------------------------------ + +#include + +/* + +This is the stack constructed by the exception handler (low address to high address) + # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM + Reg Offset + === ====== + R0 0x00 # stmfd SP!,{R0-R12} + R1 0x04 + R2 0x08 + R3 0x0c + R4 0x10 + R5 0x14 + R6 0x18 + R7 0x1c + R8 0x20 + R9 0x24 + R10 0x28 + R11 0x2c + R12 0x30 + SP 0x34 # reserved via adding 0x20 (32) to the SP + LR 0x38 + PC 0x3c + CPSR 0x40 + DFSR 0x44 + DFAR 0x48 + IFSR 0x4c + IFAR 0x50 + + LR 0x54 # SVC Link register (we need to restore it) + + LR 0x58 # pushed by srsfd + CPSR 0x5c + + */ + + EXPORT DebugAgentVectorTable + IMPORT DefaultExceptionHandler + + PRESERVE8 + AREA DebugAgentException, CODE, READONLY, CODEALIGN, ALIGN=5 + +// +// This code gets copied to the ARM vector table +// ExceptionHandlersStart - ExceptionHandlersEnd gets copied +// +DebugAgentVectorTable FUNCTION + b ResetEntry + b UndefinedInstructionEntry + b SoftwareInterruptEntry + b PrefetchAbortEntry + b DataAbortEntry + b ReservedExceptionEntry + b IrqEntry + b FiqEntry + ENDFUNC + +ResetEntry + srsfd #0x13! ; Store return state on SVC stack + ; We are already in SVC mode + stmfd SP!,{LR} ; Store the link register for the current mode + sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} ; Store the register state + + mov R0,#0 ; ExceptionType + ldr R1,CommonExceptionEntry + bx R1 + +UndefinedInstructionEntry + sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry + srsfd #0x13! ; Store return state on SVC stack + cps #0x13 ; Switch to SVC for common stack + stmfd SP!,{LR} ; Store the link register for the current mode + sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} ; Store the register state + + mov R0,#1 ; ExceptionType + ldr R1,CommonExceptionEntry; + bx R1 + +SoftwareInterruptEntry + sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry + srsfd #0x13! ; Store return state on SVC stack + ; We are already in SVC mode + stmfd SP!,{LR} ; Store the link register for the current mode + sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} ; Store the register state + + mov R0,#2 ; ExceptionType + ldr R1,CommonExceptionEntry + bx R1 + +PrefetchAbortEntry + sub LR,LR,#4 + srsfd #0x13! ; Store return state on SVC stack + cps #0x13 ; Switch to SVC for common stack + stmfd SP!,{LR} ; Store the link register for the current mode + sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} ; Store the register state + + mov R0,#3 ; ExceptionType + ldr R1,CommonExceptionEntry + bx R1 + +DataAbortEntry + sub LR,LR,#8 + srsfd #0x13! ; Store return state on SVC stack + cps #0x13 ; Switch to SVC for common stack + stmfd SP!,{LR} ; Store the link register for the current mode + sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} ; Store the register state + + mov R0,#4 ; ExceptionType + ldr R1,CommonExceptionEntry + bx R1 + +ReservedExceptionEntry + srsfd #0x13! ; Store return state on SVC stack + cps #0x13 ; Switch to SVC for common stack + stmfd SP!,{LR} ; Store the link register for the current mode + sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} ; Store the register state + + mov R0,#5 ; ExceptionType + ldr R1,CommonExceptionEntry + bx R1 + +IrqEntry + sub LR,LR,#4 + srsfd #0x13! ; Store return state on SVC stack + cps #0x13 ; Switch to SVC for common stack + stmfd SP!,{LR} ; Store the link register for the current mode + sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} ; Store the register state + + mov R0,#6 ; ExceptionType + ldr R1,CommonExceptionEntry + bx R1 + +FiqEntry + sub LR,LR,#4 + srsfd #0x13! ; Store return state on SVC stack + cps #0x13 ; Switch to SVC for common stack + stmfd SP!,{LR} ; Store the link register for the current mode + sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR + stmfd SP!,{R0-R12} ; Store the register state + ; Since we have already switch to SVC R8_fiq - R12_fiq + ; never get used or saved + mov R0,#7 ; ExceptionType + ldr R1,CommonExceptionEntry + bx R1 + +// +// This gets patched by the C code that patches in the vector table +// +CommonExceptionEntry + dcd AsmCommonExceptionEntry + +ExceptionHandlersEnd + +// +// This code runs from CpuDxe driver loaded address. It is patched into +// CommonExceptionEntry. +// +AsmCommonExceptionEntry + mrc p15, 0, R1, c6, c0, 2 ; Read IFAR + str R1, [SP, #0x50] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR + + mrc p15, 0, R1, c5, c0, 1 ; Read IFSR + str R1, [SP, #0x4c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR + + mrc p15, 0, R1, c6, c0, 0 ; Read DFAR + str R1, [SP, #0x48] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR + + mrc p15, 0, R1, c5, c0, 0 ; Read DFSR + str R1, [SP, #0x44] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR + + ldr R1, [SP, #0x5c] ; srsfd saved pre-exception CPSR on the stack + str R1, [SP, #0x40] ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR + + add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR + and R3, R1, #0x1f ; Check CPSR to see if User or System Mode + cmp R3, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1df)) + cmpne R3, #0x10 ; + stmeqed R2, {lr}^ ; save unbanked lr + ; else + stmneed R2, {lr} ; save SVC lr + + + ldr R5, [SP, #0x58] ; PC is the LR pushed by srsfd + ; Check to see if we have to adjust for Thumb entry + sub r4, r0, #1 ; if (ExceptionType == 1 || ExceptionType ==2)) { + cmp r4, #1 ; // UND & SVC have differnt LR adjust for Thumb + bhi NoAdjustNeeded + + tst r1, #0x20 ; if ((CPSR & T)) == T) { // Thumb Mode on entry + addne R5, R5, #2 ; PC += 2; + str R5,[SP,#0x58] ; Update LR value pused by srsfd + +NoAdjustNeeded + + str R5, [SP, #0x3c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC + + sub R1, SP, #0x60 ; We pused 0x60 bytes on the stack + str R1, [SP, #0x34] ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP + + ; R0 is ExceptionType + mov R1,SP ; R1 is SystemContext + +#if (FixedPcdGet32(PcdVFPEnabled)) + vpush {d0-d15} ; save vstm registers in case they are used in optimizations +#endif + +/* +VOID +EFIAPI +DefaultExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, R0 + IN OUT EFI_SYSTEM_CONTEXT SystemContext R1 + ) + +*/ + blx DefaultExceptionHandler ; Call exception handler + +#if (FixedPcdGet32(PcdVFPEnabled)) + vpop {d0-d15} +#endif + + ldr R1, [SP, #0x4c] ; Restore EFI_SYSTEM_CONTEXT_ARM.IFSR + mcr p15, 0, R1, c5, c0, 1 ; Write IFSR + + ldr R1, [SP, #0x44] ; sRestore EFI_SYSTEM_CONTEXT_ARM.DFSR + mcr p15, 0, R1, c5, c0, 0 ; Write DFSR + + ldr R1,[SP,#0x3c] ; EFI_SYSTEM_CONTEXT_ARM.PC + str R1,[SP,#0x58] ; Store it back to srsfd stack slot so it can be restored + + ldr R1,[SP,#0x40] ; EFI_SYSTEM_CONTEXT_ARM.CPSR + str R1,[SP,#0x5c] ; Store it back to srsfd stack slot so it can be restored + + add R3, SP, #0x54 ; Make R3 point to SVC LR saved on entry + add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR + and R1, R1, #0x1f ; Check to see if User or System Mode + cmp R1, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f)) + cmpne R1, #0x10 ; + ldmeqed R2, {lr}^ ; restore unbanked lr + ; else + ldmneed R3, {lr} ; restore SVC lr, via ldmfd SP!, {LR} + + ldmfd SP!,{R0-R12} ; Restore general purpose registers + ; Exception handler can not change SP + + add SP,SP,#0x20 ; Clear out the remaining stack space + ldmfd SP!,{LR} ; restore the link register for this context + rfefd SP! ; return from exception via srsfd stack slot + + END diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentException.S b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentException.S deleted file mode 100644 index d92acfeacb..0000000000 --- a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentException.S +++ /dev/null @@ -1,276 +0,0 @@ -#------------------------------------------------------------------------------ -# -# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
-# Copyright (c) 2011 - 2012, ARM Ltd. All rights reserved.
-# -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -#------------------------------------------------------------------------------ - -#include - -/* - -This is the stack constructed by the exception handler (low address to high address) - # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM - Reg Offset - === ====== - R0 0x00 # stmfd SP!,{R0-R12} - R1 0x04 - R2 0x08 - R3 0x0c - R4 0x10 - R5 0x14 - R6 0x18 - R7 0x1c - R8 0x20 - R9 0x24 - R10 0x28 - R11 0x2c - R12 0x30 - SP 0x34 # reserved via adding 0x20 (32) to the SP - LR 0x38 - PC 0x3c - CPSR 0x40 - DFSR 0x44 - DFAR 0x48 - IFSR 0x4c - IFAR 0x50 - - LR 0x54 # SVC Link register (we need to restore it) - - LR 0x58 # pushed by srsfd - CPSR 0x5c - - */ - -GCC_ASM_EXPORT(DebugAgentVectorTable) -GCC_ASM_IMPORT(DefaultExceptionHandler) - -.text -#if !defined(__APPLE__) -.fpu neon @ makes vpush/vpop assemble -#endif -.align 5 - - -// -// This code gets copied to the ARM vector table -// ExceptionHandlersStart - ExceptionHandlersEnd gets copied -// -ASM_PFX(DebugAgentVectorTable): - b ASM_PFX(ResetEntry) - b ASM_PFX(UndefinedInstructionEntry) - b ASM_PFX(SoftwareInterruptEntry) - b ASM_PFX(PrefetchAbortEntry) - b ASM_PFX(DataAbortEntry) - b ASM_PFX(ReservedExceptionEntry) - b ASM_PFX(IrqEntry) - b ASM_PFX(FiqEntry) - -ASM_PFX(ResetEntry): - srsdb #0x13! @ Store return state on SVC stack - @ We are already in SVC mode - - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#0 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(UndefinedInstructionEntry): - sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#1 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(SoftwareInterruptEntry): - sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry - srsdb #0x13! @ Store return state on SVC stack - @ We are already in SVC mode - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#2 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(PrefetchAbortEntry): - sub LR,LR,#4 - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#3 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(DataAbortEntry): - sub LR,LR,#8 - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#4 - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(ReservedExceptionEntry): - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#5 - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(IrqEntry): - sub LR,LR,#4 - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#6 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(FiqEntry): - sub LR,LR,#4 - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - @ Since we have already switch to SVC R8_fiq - R12_fiq - @ never get used or saved - mov R0,#7 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -// -// This gets patched by the C code that patches in the vector table -// -ASM_PFX(CommonExceptionEntry): - .word ASM_PFX(AsmCommonExceptionEntry) - -ASM_PFX(ExceptionHandlersEnd): - -// -// This code runs from CpuDxe driver loaded address. It is patched into -// CommonExceptionEntry. -// -ASM_PFX(AsmCommonExceptionEntry): - mrc p15, 0, R1, c6, c0, 2 @ Read IFAR - str R1, [SP, #0x50] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR - - mrc p15, 0, R1, c5, c0, 1 @ Read IFSR - str R1, [SP, #0x4c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR - - mrc p15, 0, R1, c6, c0, 0 @ Read DFAR - str R1, [SP, #0x48] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR - - mrc p15, 0, R1, c5, c0, 0 @ Read DFSR - str R1, [SP, #0x44] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR - - ldr R1, [SP, #0x5c] @ srsdb saved pre-exception CPSR on the stack - str R1, [SP, #0x40] @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR - - add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR - and R3, R1, #0x1f @ Check CPSR to see if User or System Mode - cmp R3, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1df)) - cmpne R3, #0x10 @ - stmeqed R2, {lr}^ @ save unbanked lr - @ else - stmneed R2, {lr} @ save SVC lr - - - ldr R5, [SP, #0x58] @ PC is the LR pushed by srsfd - @ Check to see if we have to adjust for Thumb entry - sub r4, r0, #1 @ if (ExceptionType == 1 || ExceptionType ==2)) { - cmp r4, #1 @ // UND & SVC have differnt LR adjust for Thumb - bhi NoAdjustNeeded - - tst r1, #0x20 @ if ((CPSR & T)) == T) { // Thumb Mode on entry - addne R5, R5, #2 @ PC += 2@ - str R5,[SP,#0x58] @ Update LR value pused by srsfd - -NoAdjustNeeded: - - str R5, [SP, #0x3c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC - - sub R1, SP, #0x60 @ We pused 0x60 bytes on the stack - str R1, [SP, #0x34] @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP - - @ R0 is ExceptionType - mov R1,SP @ R1 is SystemContext - -#if (FixedPcdGet32(PcdVFPEnabled)) - vpush {d0-d15} @ save vstm registers in case they are used in optimizations -#endif - -/* -VOID -EFIAPI -DefaultExceptionHandler ( - IN EFI_EXCEPTION_TYPE ExceptionType, R0 - IN OUT EFI_SYSTEM_CONTEXT SystemContext R1 - ) - -*/ - blx ASM_PFX(DefaultExceptionHandler) @ Call exception handler - -#if (FixedPcdGet32(PcdVFPEnabled)) - vpop {d0-d15} -#endif - - ldr R1, [SP, #0x4c] @ Restore EFI_SYSTEM_CONTEXT_ARM.IFSR - mcr p15, 0, R1, c5, c0, 1 @ Write IFSR - - ldr R1, [SP, #0x44] @ sRestore EFI_SYSTEM_CONTEXT_ARM.DFSR - mcr p15, 0, R1, c5, c0, 0 @ Write DFSR - - ldr R1,[SP,#0x3c] @ EFI_SYSTEM_CONTEXT_ARM.PC - str R1,[SP,#0x58] @ Store it back to srsfd stack slot so it can be restored - - ldr R1,[SP,#0x40] @ EFI_SYSTEM_CONTEXT_ARM.CPSR - str R1,[SP,#0x5c] @ Store it back to srsfd stack slot so it can be restored - - add R3, SP, #0x54 @ Make R3 point to SVC LR saved on entry - add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR - and R1, R1, #0x1f @ Check to see if User or System Mode - cmp R1, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f)) - cmpne R1, #0x10 @ - ldmeqed R2, {lr}^ @ restore unbanked lr - @ else - ldmneed R3, {lr} @ restore SVC lr, via ldmfd SP!, {LR} - - ldmfd SP!,{R0-R12} @ Restore general purpose registers - @ Exception handler can not change SP - - add SP,SP,#0x20 @ Clear out the remaining stack space - ldmfd SP!,{LR} @ restore the link register for this context - rfefd SP! @ return from exception via srsfd stack slot - diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentException.asm b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentException.asm deleted file mode 100644 index f281c0603f..0000000000 --- a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentException.asm +++ /dev/null @@ -1,273 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
-// Copyright (c) 2011 - 2012, ARM Ltd. All rights reserved.
-// -// This program and the accompanying materials -// are licensed and made available under the terms and conditions of the BSD License -// which accompanies this distribution. The full text of the license may be found at -// http://opensource.org/licenses/bsd-license.php -// -// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -// -//------------------------------------------------------------------------------ - -#include - -/* - -This is the stack constructed by the exception handler (low address to high address) - # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM - Reg Offset - === ====== - R0 0x00 # stmfd SP!,{R0-R12} - R1 0x04 - R2 0x08 - R3 0x0c - R4 0x10 - R5 0x14 - R6 0x18 - R7 0x1c - R8 0x20 - R9 0x24 - R10 0x28 - R11 0x2c - R12 0x30 - SP 0x34 # reserved via adding 0x20 (32) to the SP - LR 0x38 - PC 0x3c - CPSR 0x40 - DFSR 0x44 - DFAR 0x48 - IFSR 0x4c - IFAR 0x50 - - LR 0x54 # SVC Link register (we need to restore it) - - LR 0x58 # pushed by srsfd - CPSR 0x5c - - */ - - EXPORT DebugAgentVectorTable - IMPORT DefaultExceptionHandler - - PRESERVE8 - AREA DebugAgentException, CODE, READONLY, CODEALIGN, ALIGN=5 - -// -// This code gets copied to the ARM vector table -// ExceptionHandlersStart - ExceptionHandlersEnd gets copied -// -DebugAgentVectorTable FUNCTION - b ResetEntry - b UndefinedInstructionEntry - b SoftwareInterruptEntry - b PrefetchAbortEntry - b DataAbortEntry - b ReservedExceptionEntry - b IrqEntry - b FiqEntry - ENDFUNC - -ResetEntry - srsfd #0x13! ; Store return state on SVC stack - ; We are already in SVC mode - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#0 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -UndefinedInstructionEntry - sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#1 ; ExceptionType - ldr R1,CommonExceptionEntry; - bx R1 - -SoftwareInterruptEntry - sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry - srsfd #0x13! ; Store return state on SVC stack - ; We are already in SVC mode - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#2 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -PrefetchAbortEntry - sub LR,LR,#4 - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#3 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -DataAbortEntry - sub LR,LR,#8 - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#4 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -ReservedExceptionEntry - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#5 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -IrqEntry - sub LR,LR,#4 - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#6 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -FiqEntry - sub LR,LR,#4 - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - ; Since we have already switch to SVC R8_fiq - R12_fiq - ; never get used or saved - mov R0,#7 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -// -// This gets patched by the C code that patches in the vector table -// -CommonExceptionEntry - dcd AsmCommonExceptionEntry - -ExceptionHandlersEnd - -// -// This code runs from CpuDxe driver loaded address. It is patched into -// CommonExceptionEntry. -// -AsmCommonExceptionEntry - mrc p15, 0, R1, c6, c0, 2 ; Read IFAR - str R1, [SP, #0x50] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR - - mrc p15, 0, R1, c5, c0, 1 ; Read IFSR - str R1, [SP, #0x4c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR - - mrc p15, 0, R1, c6, c0, 0 ; Read DFAR - str R1, [SP, #0x48] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR - - mrc p15, 0, R1, c5, c0, 0 ; Read DFSR - str R1, [SP, #0x44] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR - - ldr R1, [SP, #0x5c] ; srsfd saved pre-exception CPSR on the stack - str R1, [SP, #0x40] ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR - - add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR - and R3, R1, #0x1f ; Check CPSR to see if User or System Mode - cmp R3, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1df)) - cmpne R3, #0x10 ; - stmeqed R2, {lr}^ ; save unbanked lr - ; else - stmneed R2, {lr} ; save SVC lr - - - ldr R5, [SP, #0x58] ; PC is the LR pushed by srsfd - ; Check to see if we have to adjust for Thumb entry - sub r4, r0, #1 ; if (ExceptionType == 1 || ExceptionType ==2)) { - cmp r4, #1 ; // UND & SVC have differnt LR adjust for Thumb - bhi NoAdjustNeeded - - tst r1, #0x20 ; if ((CPSR & T)) == T) { // Thumb Mode on entry - addne R5, R5, #2 ; PC += 2; - str R5,[SP,#0x58] ; Update LR value pused by srsfd - -NoAdjustNeeded - - str R5, [SP, #0x3c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC - - sub R1, SP, #0x60 ; We pused 0x60 bytes on the stack - str R1, [SP, #0x34] ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP - - ; R0 is ExceptionType - mov R1,SP ; R1 is SystemContext - -#if (FixedPcdGet32(PcdVFPEnabled)) - vpush {d0-d15} ; save vstm registers in case they are used in optimizations -#endif - -/* -VOID -EFIAPI -DefaultExceptionHandler ( - IN EFI_EXCEPTION_TYPE ExceptionType, R0 - IN OUT EFI_SYSTEM_CONTEXT SystemContext R1 - ) - -*/ - blx DefaultExceptionHandler ; Call exception handler - -#if (FixedPcdGet32(PcdVFPEnabled)) - vpop {d0-d15} -#endif - - ldr R1, [SP, #0x4c] ; Restore EFI_SYSTEM_CONTEXT_ARM.IFSR - mcr p15, 0, R1, c5, c0, 1 ; Write IFSR - - ldr R1, [SP, #0x44] ; sRestore EFI_SYSTEM_CONTEXT_ARM.DFSR - mcr p15, 0, R1, c5, c0, 0 ; Write DFSR - - ldr R1,[SP,#0x3c] ; EFI_SYSTEM_CONTEXT_ARM.PC - str R1,[SP,#0x58] ; Store it back to srsfd stack slot so it can be restored - - ldr R1,[SP,#0x40] ; EFI_SYSTEM_CONTEXT_ARM.CPSR - str R1,[SP,#0x5c] ; Store it back to srsfd stack slot so it can be restored - - add R3, SP, #0x54 ; Make R3 point to SVC LR saved on entry - add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR - and R1, R1, #0x1f ; Check to see if User or System Mode - cmp R1, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f)) - cmpne R1, #0x10 ; - ldmeqed R2, {lr}^ ; restore unbanked lr - ; else - ldmneed R3, {lr} ; restore SVC lr, via ldmfd SP!, {LR} - - ldmfd SP!,{R0-R12} ; Restore general purpose registers - ; Exception handler can not change SP - - add SP,SP,#0x20 ; Clear out the remaining stack space - ldmfd SP!,{LR} ; restore the link register for this context - rfefd SP! ; return from exception via srsfd stack slot - - END diff --git a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf index 1cf0b33524..f6a0ec2938 100644 --- a/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf +++ b/ArmPkg/Library/DebugAgentSymbolsBaseLib/DebugAgentSymbolsBaseLib.inf @@ -21,9 +21,11 @@ [Sources.common] DebugAgentSymbolsBaseLib.c - DebugAgentException.asm | RVCT - DebugAgentException.S | GCC - + +[Sources.ARM] + Arm/DebugAgentException.asm | RVCT + Arm/DebugAgentException.S | GCC + [Packages] MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c b/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c new file mode 100644 index 0000000000..bb29b95da2 --- /dev/null +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/Arm/DefaultExceptionHandler.c @@ -0,0 +1,268 @@ +/** @file + Default exception handler + + Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
+ Copyright (c) 2012, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL; + +typedef struct { + UINT32 BIT; + CHAR8 Char; +} CPSR_CHAR; + +CHAR8 * +GetImageName ( + IN UINT32 FaultAddress, + OUT UINT32 *ImageBase, + OUT UINT32 *PeCoffSizeOfHeaders + ); + +/** + Convert the Current Program Status Register (CPSR) to a string. The string is + a defacto standard in the ARM world. + + It is possible to add extra bits by adding them to CpsrChar array. + + @param Cpsr ARM CPSR register value + @param ReturnStr 32 byte string that contains string version of CPSR + +**/ +VOID +CpsrString ( + IN UINT32 Cpsr, + OUT CHAR8 *ReturnStr + ) +{ + UINTN Index; + CHAR8* Str; + CHAR8* ModeStr; + CPSR_CHAR CpsrChar[] = { + { 31, 'n' }, + { 30, 'z' }, + { 29, 'c' }, + { 28, 'v' }, + + { 9, 'e' }, + { 8, 'a' }, + { 7, 'i' }, + { 6, 'f' }, + { 5, 't' }, + { 0, '?' } + }; + + Str = ReturnStr; + + for (Index = 0; CpsrChar[Index].BIT != 0; Index++, Str++) { + *Str = CpsrChar[Index].Char; + if ((Cpsr & (1 << CpsrChar[Index].BIT)) != 0) { + // Concert to upper case if bit is set + *Str &= ~0x20; + } + } + + *Str++ = '_'; + *Str = '\0'; + + switch (Cpsr & 0x1f) { + case 0x10: + ModeStr = "usr"; + break; + case 0x011: + ModeStr = "fiq"; + break; + case 0x12: + ModeStr = "irq"; + break; + case 0x13: + ModeStr = "svc"; + break; + case 0x16: + ModeStr = "mon"; + break; + case 0x17: + ModeStr = "abt"; + break; + case 0x1b: + ModeStr = "und"; + break; + case 0x1f: + ModeStr = "sys"; + break; + + default: + ModeStr = "???"; + break; + } + + AsciiStrCat (Str, ModeStr); + return; +} + +CHAR8 * +FaultStatusToString ( + IN UINT32 Status + ) +{ + CHAR8 *FaultSource; + + switch (Status) { + case 0x01: FaultSource = "Alignment fault"; break; + case 0x02: FaultSource = "Debug event fault"; break; + case 0x03: FaultSource = "Access Flag fault on Section"; break; + case 0x04: FaultSource = "Cache maintenance operation fault[2]"; break; + case 0x05: FaultSource = "Translation fault on Section"; break; + case 0x06: FaultSource = "Access Flag fault on Page"; break; + case 0x07: FaultSource = "Translation fault on Page"; break; + case 0x08: FaultSource = "Precise External Abort"; break; + case 0x09: FaultSource = "Domain fault on Section"; break; + case 0x0b: FaultSource = "Domain fault on Page"; break; + case 0x0c: FaultSource = "External abort on translation, first level"; break; + case 0x0d: FaultSource = "Permission fault on Section"; break; + case 0x0e: FaultSource = "External abort on translation, second level"; break; + case 0x0f: FaultSource = "Permission fault on Page"; break; + case 0x16: FaultSource = "Imprecise External Abort"; break; + default: FaultSource = "No function"; break; + } + + return FaultSource; +} + +STATIC CHAR8 *gExceptionTypeString[] = { + "Reset", + "Undefined OpCode", + "SVC", + "Prefetch Abort", + "Data Abort", + "Undefined", + "IRQ", + "FIQ" +}; + +/** + This is the default action to take on an unexpected exception + + Since this is exception context don't do anything crazy like try to allcoate memory. + + @param ExceptionType Type of the exception + @param SystemContext Register state at the time of the Exception + + +**/ +VOID +DefaultExceptionHandler ( + IN EFI_EXCEPTION_TYPE ExceptionType, + IN OUT EFI_SYSTEM_CONTEXT SystemContext + ) +{ + CHAR8 Buffer[100]; + UINTN CharCount; + UINT32 DfsrStatus; + UINT32 IfsrStatus; + BOOLEAN DfsrWrite; + UINT32 PcAdjust = 0; + + CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"\n%a Exception PC at 0x%08x CPSR 0x%08x ", + gExceptionTypeString[ExceptionType], SystemContext.SystemContextArm->PC, SystemContext.SystemContextArm->CPSR); + SerialPortWrite ((UINT8 *) Buffer, CharCount); + + DEBUG_CODE_BEGIN (); + CHAR8 *Pdb; + UINT32 ImageBase; + UINT32 PeCoffSizeOfHeader; + UINT32 Offset; + CHAR8 CpsrStr[32]; // char per bit. Lower 5-bits are mode that is a 3 char string + CHAR8 Buffer[80]; + UINT8 *DisAsm; + UINT32 ItBlock; + + CpsrString (SystemContext.SystemContextArm->CPSR, CpsrStr); + DEBUG ((EFI_D_ERROR, "%a\n", CpsrStr)); + + 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 addresses. 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 subtract out the size of the PE/COFF header to get + // get the offset that matches the link map. + // + DEBUG ((EFI_D_ERROR, "loaded at 0x%08x (PE/COFF offset) 0x%x (ELF or Mach-O offset) 0x%x", ImageBase, Offset, Offset - PeCoffSizeOfHeader)); + + // If we come from an image it is safe to show the instruction. We know it should not fault + DisAsm = (UINT8 *)(UINTN)SystemContext.SystemContextArm->PC; + ItBlock = 0; + DisassembleInstruction (&DisAsm, (SystemContext.SystemContextArm->CPSR & BIT5) == BIT5, TRUE, &ItBlock, Buffer, sizeof (Buffer)); + DEBUG ((EFI_D_ERROR, "\n%a", Buffer)); + + switch (ExceptionType) { + case EXCEPT_ARM_UNDEFINED_INSTRUCTION: + case EXCEPT_ARM_SOFTWARE_INTERRUPT: + case EXCEPT_ARM_PREFETCH_ABORT: + case EXCEPT_ARM_DATA_ABORT: + // advance PC past the faulting instruction + PcAdjust = (UINTN)DisAsm - SystemContext.SystemContextArm->PC; + break; + + default: + break; + } + + } + DEBUG_CODE_END (); + DEBUG ((EFI_D_ERROR, "\n 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", SystemContext.SystemContextArm->DFSR, SystemContext.SystemContextArm->DFAR, SystemContext.SystemContextArm->IFSR, SystemContext.SystemContextArm->IFAR)); + + // Bit10 is Status[4] Bit3:0 is Status[3:0] + DfsrStatus = (SystemContext.SystemContextArm->DFSR & 0xf) | ((SystemContext.SystemContextArm->DFSR >> 6) & 0x10); + DfsrWrite = (SystemContext.SystemContextArm->DFSR & BIT11) != 0; + if (DfsrStatus != 0x00) { + DEBUG ((EFI_D_ERROR, " %a: %a 0x%08x\n", FaultStatusToString (DfsrStatus), DfsrWrite ? "write to" : "read from", SystemContext.SystemContextArm->DFAR)); + } + + IfsrStatus = (SystemContext.SystemContextArm->IFSR & 0xf) | ((SystemContext.SystemContextArm->IFSR >> 6) & 0x10); + if (IfsrStatus != 0) { + DEBUG ((EFI_D_ERROR, " Instruction %a at 0x%08x\n", FaultStatusToString (SystemContext.SystemContextArm->IFSR & 0xf), SystemContext.SystemContextArm->IFAR)); + } + + DEBUG ((EFI_D_ERROR, "\n")); + ASSERT (FALSE); + + // Clear the error registers that we have already displayed incase some one wants to keep going + SystemContext.SystemContextArm->DFSR = 0; + SystemContext.SystemContextArm->IFSR = 0; + + // If some one is stepping past the exception handler adjust the PC to point to the next instruction + SystemContext.SystemContextArm->PC += PcAdjust; +} diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandler.c b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandler.c deleted file mode 100644 index bb29b95da2..0000000000 --- a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandler.c +++ /dev/null @@ -1,268 +0,0 @@ -/** @file - Default exception handler - - Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
- Copyright (c) 2012, ARM Ltd. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL; - -typedef struct { - UINT32 BIT; - CHAR8 Char; -} CPSR_CHAR; - -CHAR8 * -GetImageName ( - IN UINT32 FaultAddress, - OUT UINT32 *ImageBase, - OUT UINT32 *PeCoffSizeOfHeaders - ); - -/** - Convert the Current Program Status Register (CPSR) to a string. The string is - a defacto standard in the ARM world. - - It is possible to add extra bits by adding them to CpsrChar array. - - @param Cpsr ARM CPSR register value - @param ReturnStr 32 byte string that contains string version of CPSR - -**/ -VOID -CpsrString ( - IN UINT32 Cpsr, - OUT CHAR8 *ReturnStr - ) -{ - UINTN Index; - CHAR8* Str; - CHAR8* ModeStr; - CPSR_CHAR CpsrChar[] = { - { 31, 'n' }, - { 30, 'z' }, - { 29, 'c' }, - { 28, 'v' }, - - { 9, 'e' }, - { 8, 'a' }, - { 7, 'i' }, - { 6, 'f' }, - { 5, 't' }, - { 0, '?' } - }; - - Str = ReturnStr; - - for (Index = 0; CpsrChar[Index].BIT != 0; Index++, Str++) { - *Str = CpsrChar[Index].Char; - if ((Cpsr & (1 << CpsrChar[Index].BIT)) != 0) { - // Concert to upper case if bit is set - *Str &= ~0x20; - } - } - - *Str++ = '_'; - *Str = '\0'; - - switch (Cpsr & 0x1f) { - case 0x10: - ModeStr = "usr"; - break; - case 0x011: - ModeStr = "fiq"; - break; - case 0x12: - ModeStr = "irq"; - break; - case 0x13: - ModeStr = "svc"; - break; - case 0x16: - ModeStr = "mon"; - break; - case 0x17: - ModeStr = "abt"; - break; - case 0x1b: - ModeStr = "und"; - break; - case 0x1f: - ModeStr = "sys"; - break; - - default: - ModeStr = "???"; - break; - } - - AsciiStrCat (Str, ModeStr); - return; -} - -CHAR8 * -FaultStatusToString ( - IN UINT32 Status - ) -{ - CHAR8 *FaultSource; - - switch (Status) { - case 0x01: FaultSource = "Alignment fault"; break; - case 0x02: FaultSource = "Debug event fault"; break; - case 0x03: FaultSource = "Access Flag fault on Section"; break; - case 0x04: FaultSource = "Cache maintenance operation fault[2]"; break; - case 0x05: FaultSource = "Translation fault on Section"; break; - case 0x06: FaultSource = "Access Flag fault on Page"; break; - case 0x07: FaultSource = "Translation fault on Page"; break; - case 0x08: FaultSource = "Precise External Abort"; break; - case 0x09: FaultSource = "Domain fault on Section"; break; - case 0x0b: FaultSource = "Domain fault on Page"; break; - case 0x0c: FaultSource = "External abort on translation, first level"; break; - case 0x0d: FaultSource = "Permission fault on Section"; break; - case 0x0e: FaultSource = "External abort on translation, second level"; break; - case 0x0f: FaultSource = "Permission fault on Page"; break; - case 0x16: FaultSource = "Imprecise External Abort"; break; - default: FaultSource = "No function"; break; - } - - return FaultSource; -} - -STATIC CHAR8 *gExceptionTypeString[] = { - "Reset", - "Undefined OpCode", - "SVC", - "Prefetch Abort", - "Data Abort", - "Undefined", - "IRQ", - "FIQ" -}; - -/** - This is the default action to take on an unexpected exception - - Since this is exception context don't do anything crazy like try to allcoate memory. - - @param ExceptionType Type of the exception - @param SystemContext Register state at the time of the Exception - - -**/ -VOID -DefaultExceptionHandler ( - IN EFI_EXCEPTION_TYPE ExceptionType, - IN OUT EFI_SYSTEM_CONTEXT SystemContext - ) -{ - CHAR8 Buffer[100]; - UINTN CharCount; - UINT32 DfsrStatus; - UINT32 IfsrStatus; - BOOLEAN DfsrWrite; - UINT32 PcAdjust = 0; - - CharCount = AsciiSPrint (Buffer,sizeof (Buffer),"\n%a Exception PC at 0x%08x CPSR 0x%08x ", - gExceptionTypeString[ExceptionType], SystemContext.SystemContextArm->PC, SystemContext.SystemContextArm->CPSR); - SerialPortWrite ((UINT8 *) Buffer, CharCount); - - DEBUG_CODE_BEGIN (); - CHAR8 *Pdb; - UINT32 ImageBase; - UINT32 PeCoffSizeOfHeader; - UINT32 Offset; - CHAR8 CpsrStr[32]; // char per bit. Lower 5-bits are mode that is a 3 char string - CHAR8 Buffer[80]; - UINT8 *DisAsm; - UINT32 ItBlock; - - CpsrString (SystemContext.SystemContextArm->CPSR, CpsrStr); - DEBUG ((EFI_D_ERROR, "%a\n", CpsrStr)); - - 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 addresses. 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 subtract out the size of the PE/COFF header to get - // get the offset that matches the link map. - // - DEBUG ((EFI_D_ERROR, "loaded at 0x%08x (PE/COFF offset) 0x%x (ELF or Mach-O offset) 0x%x", ImageBase, Offset, Offset - PeCoffSizeOfHeader)); - - // If we come from an image it is safe to show the instruction. We know it should not fault - DisAsm = (UINT8 *)(UINTN)SystemContext.SystemContextArm->PC; - ItBlock = 0; - DisassembleInstruction (&DisAsm, (SystemContext.SystemContextArm->CPSR & BIT5) == BIT5, TRUE, &ItBlock, Buffer, sizeof (Buffer)); - DEBUG ((EFI_D_ERROR, "\n%a", Buffer)); - - switch (ExceptionType) { - case EXCEPT_ARM_UNDEFINED_INSTRUCTION: - case EXCEPT_ARM_SOFTWARE_INTERRUPT: - case EXCEPT_ARM_PREFETCH_ABORT: - case EXCEPT_ARM_DATA_ABORT: - // advance PC past the faulting instruction - PcAdjust = (UINTN)DisAsm - SystemContext.SystemContextArm->PC; - break; - - default: - break; - } - - } - DEBUG_CODE_END (); - DEBUG ((EFI_D_ERROR, "\n 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", SystemContext.SystemContextArm->DFSR, SystemContext.SystemContextArm->DFAR, SystemContext.SystemContextArm->IFSR, SystemContext.SystemContextArm->IFAR)); - - // Bit10 is Status[4] Bit3:0 is Status[3:0] - DfsrStatus = (SystemContext.SystemContextArm->DFSR & 0xf) | ((SystemContext.SystemContextArm->DFSR >> 6) & 0x10); - DfsrWrite = (SystemContext.SystemContextArm->DFSR & BIT11) != 0; - if (DfsrStatus != 0x00) { - DEBUG ((EFI_D_ERROR, " %a: %a 0x%08x\n", FaultStatusToString (DfsrStatus), DfsrWrite ? "write to" : "read from", SystemContext.SystemContextArm->DFAR)); - } - - IfsrStatus = (SystemContext.SystemContextArm->IFSR & 0xf) | ((SystemContext.SystemContextArm->IFSR >> 6) & 0x10); - if (IfsrStatus != 0) { - DEBUG ((EFI_D_ERROR, " Instruction %a at 0x%08x\n", FaultStatusToString (SystemContext.SystemContextArm->IFSR & 0xf), SystemContext.SystemContextArm->IFAR)); - } - - DEBUG ((EFI_D_ERROR, "\n")); - ASSERT (FALSE); - - // Clear the error registers that we have already displayed incase some one wants to keep going - SystemContext.SystemContextArm->DFSR = 0; - SystemContext.SystemContextArm->IFSR = 0; - - // If some one is stepping past the exception handler adjust the PC to point to the next instruction - SystemContext.SystemContextArm->PC += PcAdjust; -} diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf index 120e2de217..61dabf484e 100644 --- a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLib.inf @@ -21,11 +21,12 @@ LIBRARY_CLASS = DefaultExceptionHandlerLib CONSTRUCTOR = DefaultExceptionHandlerConstructor - [Sources.common] - DefaultExceptionHandler.c DefaultExceptionHandlerUefi.c +[Sources.ARM] + Arm/DefaultExceptionHandler.c + [Packages] MdePkg/MdePkg.dec ArmPkg/ArmPkg.dec diff --git a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf index f51d3a0ef5..39b2775fce 100644 --- a/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf +++ b/ArmPkg/Library/DefaultExceptionHandlerLib/DefaultExceptionHandlerLibBase.inf @@ -21,9 +21,11 @@ LIBRARY_CLASS = DefaultExceptionHandlerLib [Sources.common] - DefaultExceptionHandler.c DefaultExceptionHandlerBase.c +[Sources.ARM] + Arm/DefaultExceptionHandler.c + [Packages] MdePkg/MdePkg.dec ArmPkg/ArmPkg.dec diff --git a/ArmPkg/Library/SemihostLib/Arm/SemihostLib.c b/ArmPkg/Library/SemihostLib/Arm/SemihostLib.c deleted file mode 100644 index 01b6dc334d..0000000000 --- a/ArmPkg/Library/SemihostLib/Arm/SemihostLib.c +++ /dev/null @@ -1,219 +0,0 @@ -/** @file - - Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ -#include - -#include -#include - -#include "SemihostPrivate.h" - -BOOLEAN -SemihostConnectionSupported ( - VOID - ) -{ - return SEMIHOST_SUPPORTED; -} - -RETURN_STATUS -SemihostFileOpen ( - IN CHAR8 *FileName, - IN UINT32 Mode, - OUT UINT32 *FileHandle - ) -{ - SEMIHOST_FILE_OPEN_BLOCK OpenBlock; - INT32 Result; - - if (FileHandle == NULL) { - return RETURN_INVALID_PARAMETER; - } - - OpenBlock.FileName = FileName; - OpenBlock.Mode = Mode; - OpenBlock.NameLength = AsciiStrLen(FileName); - - Result = Semihost_SYS_OPEN(&OpenBlock); - - if (Result == -1) { - return RETURN_NOT_FOUND; - } else { - *FileHandle = Result; - return RETURN_SUCCESS; - } -} - -RETURN_STATUS -SemihostFileSeek ( - IN UINT32 FileHandle, - IN UINT32 Offset - ) -{ - SEMIHOST_FILE_SEEK_BLOCK SeekBlock; - INT32 Result; - - SeekBlock.Handle = FileHandle; - SeekBlock.Location = Offset; - - Result = Semihost_SYS_SEEK(&SeekBlock); - - if (Result == 0) { - return RETURN_SUCCESS; - } else { - return RETURN_ABORTED; - } -} - -RETURN_STATUS -SemihostFileRead ( - IN UINT32 FileHandle, - IN OUT UINT32 *Length, - OUT VOID *Buffer - ) -{ - SEMIHOST_FILE_READ_WRITE_BLOCK ReadBlock; - UINT32 Result; - - if ((Length == NULL) || (Buffer == NULL)) { - return RETURN_INVALID_PARAMETER; - } - - ReadBlock.Handle = FileHandle; - ReadBlock.Buffer = Buffer; - ReadBlock.Length = *Length; - - Result = Semihost_SYS_READ(&ReadBlock); - - if (Result == *Length) { - return RETURN_ABORTED; - } else { - *Length -= Result; - return RETURN_SUCCESS; - } -} - -RETURN_STATUS -SemihostFileWrite ( - IN UINT32 FileHandle, - IN OUT UINT32 *Length, - IN VOID *Buffer - ) -{ - SEMIHOST_FILE_READ_WRITE_BLOCK WriteBlock; - - if ((Length == NULL) || (Buffer == NULL)) { - return RETURN_INVALID_PARAMETER; - } - - WriteBlock.Handle = FileHandle; - WriteBlock.Buffer = Buffer; - WriteBlock.Length = *Length; - - *Length = Semihost_SYS_WRITE(&WriteBlock); - - return RETURN_SUCCESS; -} - -RETURN_STATUS -SemihostFileClose ( - IN UINT32 FileHandle - ) -{ - INT32 Result = Semihost_SYS_CLOSE(&FileHandle); - - if (Result == -1) { - return RETURN_INVALID_PARAMETER; - } else { - return RETURN_SUCCESS; - } -} - -RETURN_STATUS -SemihostFileLength ( - IN UINT32 FileHandle, - OUT UINT32 *Length - ) -{ - INT32 Result; - - if (Length == NULL) { - return RETURN_INVALID_PARAMETER; - } - - Result = Semihost_SYS_FLEN(&FileHandle); - - if (Result == -1) { - return RETURN_ABORTED; - } else { - *Length = Result; - return RETURN_SUCCESS; - } -} - -RETURN_STATUS -SemihostFileRemove ( - IN CHAR8 *FileName - ) -{ - SEMIHOST_FILE_REMOVE_BLOCK RemoveBlock; - UINT32 Result; - - RemoveBlock.FileName = FileName; - RemoveBlock.NameLength = AsciiStrLen(FileName); - - Result = Semihost_SYS_REMOVE(&RemoveBlock); - - if (Result == 0) { - return RETURN_SUCCESS; - } else { - return RETURN_ABORTED; - } -} - -CHAR8 -SemihostReadCharacter ( - VOID - ) -{ - return Semihost_SYS_READC(); -} - -VOID -SemihostWriteCharacter ( - IN CHAR8 Character - ) -{ - Semihost_SYS_WRITEC(&Character); -} - -VOID -SemihostWriteString ( - IN CHAR8 *String - ) -{ - Semihost_SYS_WRITE0(String); -} - -UINT32 -SemihostSystem ( - IN CHAR8 *CommandLine - ) -{ - SEMIHOST_SYSTEM_BLOCK SystemBlock; - - SystemBlock.CommandLine = CommandLine; - SystemBlock.CommandLength = AsciiStrLen(CommandLine); - - return Semihost_SYS_SYSTEM(&SystemBlock); -} diff --git a/ArmPkg/Library/SemihostLib/Arm/SemihostPrivate.h b/ArmPkg/Library/SemihostLib/Arm/SemihostPrivate.h deleted file mode 100644 index 02836ca281..0000000000 --- a/ArmPkg/Library/SemihostLib/Arm/SemihostPrivate.h +++ /dev/null @@ -1,184 +0,0 @@ -/** @file - - Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef __SEMIHOST_PRIVATE_H__ -#define __SEMIHOST_PRIVATE_H__ - -typedef struct { - CHAR8 *FileName; - UINT32 Mode; - UINT32 NameLength; -} SEMIHOST_FILE_OPEN_BLOCK; - -typedef struct { - UINT32 Handle; - VOID *Buffer; - UINT32 Length; -} SEMIHOST_FILE_READ_WRITE_BLOCK; - -typedef struct { - UINT32 Handle; - UINT32 Location; -} SEMIHOST_FILE_SEEK_BLOCK; - -typedef struct { - CHAR8 *FileName; - UINT32 NameLength; -} SEMIHOST_FILE_REMOVE_BLOCK; - -typedef struct { - CHAR8 *CommandLine; - UINT32 CommandLength; -} SEMIHOST_SYSTEM_BLOCK; - -#if defined(__CC_ARM) - -#if defined(__thumb__) -#define SWI 0xAB -#else -#define SWI 0x123456 -#endif - -#define SEMIHOST_SUPPORTED TRUE - -__swi(SWI) -INT32 -_Semihost_SYS_OPEN( - IN UINTN SWI_0x01, - IN SEMIHOST_FILE_OPEN_BLOCK *OpenBlock - ); - -__swi(SWI) -INT32 -_Semihost_SYS_CLOSE( - IN UINTN SWI_0x02, - IN UINT32 *Handle - ); - -__swi(SWI) -VOID -_Semihost_SYS_WRITEC( - IN UINTN SWI_0x03, - IN CHAR8 *Character - ); - -__swi(SWI) -VOID -_Semihost_SYS_WRITE0( - IN UINTN SWI_0x04, - IN CHAR8 *String - ); - -__swi(SWI) -UINT32 -_Semihost_SYS_WRITE( - IN UINTN SWI_0x05, - IN OUT SEMIHOST_FILE_READ_WRITE_BLOCK *WriteBlock - ); - -__swi(SWI) -UINT32 -_Semihost_SYS_READ( - IN UINTN SWI_0x06, - IN OUT SEMIHOST_FILE_READ_WRITE_BLOCK *ReadBlock - ); - -__swi(SWI) -CHAR8 -_Semihost_SYS_READC( - IN UINTN SWI_0x07, - IN UINTN Zero - ); - -__swi(SWI) -INT32 -_Semihost_SYS_SEEK( - IN UINTN SWI_0x0A, - IN SEMIHOST_FILE_SEEK_BLOCK *SeekBlock - ); - -__swi(SWI) -INT32 -_Semihost_SYS_FLEN( - IN UINTN SWI_0x0C, - IN UINT32 *Handle - ); - -__swi(SWI) -UINT32 -_Semihost_SYS_REMOVE( - IN UINTN SWI_0x0E, - IN SEMIHOST_FILE_REMOVE_BLOCK *RemoveBlock - ); - -__swi(SWI) -UINT32 -_Semihost_SYS_SYSTEM( - IN UINTN SWI_0x12, - IN SEMIHOST_SYSTEM_BLOCK *SystemBlock - ); - -#define Semihost_SYS_OPEN(OpenBlock) _Semihost_SYS_OPEN(0x01, OpenBlock) -#define Semihost_SYS_CLOSE(Handle) _Semihost_SYS_CLOSE(0x02, Handle) -#define Semihost_SYS_WRITE0(String) _Semihost_SYS_WRITE0(0x04, String) -#define Semihost_SYS_WRITEC(Character) _Semihost_SYS_WRITEC(0x03, Character) -#define Semihost_SYS_WRITE(WriteBlock) _Semihost_SYS_WRITE(0x05, WriteBlock) -#define Semihost_SYS_READ(ReadBlock) _Semihost_SYS_READ(0x06, ReadBlock) -#define Semihost_SYS_READC() _Semihost_SYS_READC(0x07, 0) -#define Semihost_SYS_SEEK(SeekBlock) _Semihost_SYS_SEEK(0x0A, SeekBlock) -#define Semihost_SYS_FLEN(Handle) _Semihost_SYS_FLEN(0x0C, Handle) -#define Semihost_SYS_REMOVE(RemoveBlock) _Semihost_SYS_REMOVE(0x0E, RemoveBlock) -#define Semihost_SYS_SYSTEM(SystemBlock) _Semihost_SYS_SYSTEM(0x12, SystemBlock) - -#elif defined(__GNUC__) // __CC_ARM - -#define SEMIHOST_SUPPORTED TRUE - -UINT32 -GccSemihostCall ( - IN UINT32 Operation, - IN UINTN SystemBlockAddress - ); // __attribute__ ((interrupt ("SVC"))); - -#define Semihost_SYS_OPEN(OpenBlock) GccSemihostCall(0x01, (UINTN)(OpenBlock)) -#define Semihost_SYS_CLOSE(Handle) GccSemihostCall(0x02, (UINTN)(Handle)) -#define Semihost_SYS_WRITE0(String) GccSemihostCall(0x04, (UINTN)(String)) -#define Semihost_SYS_WRITEC(Character) GccSemihostCall(0x03, (UINTN)(Character)) -#define Semihost_SYS_WRITE(WriteBlock) GccSemihostCall(0x05, (UINTN)(WriteBlock)) -#define Semihost_SYS_READ(ReadBlock) GccSemihostCall(0x06, (UINTN)(ReadBlock)) -#define Semihost_SYS_READC() GccSemihostCall(0x07, (UINTN)(0)) -#define Semihost_SYS_SEEK(SeekBlock) GccSemihostCall(0x0A, (UINTN)(SeekBlock)) -#define Semihost_SYS_FLEN(Handle) GccSemihostCall(0x0C, (UINTN)(Handle)) -#define Semihost_SYS_REMOVE(RemoveBlock) GccSemihostCall(0x0E, (UINTN)(RemoveBlock)) -#define Semihost_SYS_SYSTEM(SystemBlock) GccSemihostCall(0x12, (UINTN)(SystemBlock)) - -#else // __CC_ARM - -#define SEMIHOST_SUPPORTED FALSE - -#define Semihost_SYS_OPEN(OpenBlock) (-1) -#define Semihost_SYS_CLOSE(Handle) (-1) -#define Semihost_SYS_WRITE0(String) -#define Semihost_SYS_WRITEC(Character) -#define Semihost_SYS_WRITE(WriteBlock) (0) -#define Semihost_SYS_READ(ReadBlock) ((ReadBlock)->Length) -#define Semihost_SYS_READC() ('x') -#define Semihost_SYS_SEEK(SeekBlock) (-1) -#define Semihost_SYS_FLEN(Handle) (-1) -#define Semihost_SYS_REMOVE(RemoveBlock) (-1) -#define Semihost_SYS_SYSTEM(SystemBlock) (-1) - -#endif // __CC_ARM - -#endif //__SEMIHOST_PRIVATE_H__ diff --git a/ArmPkg/Library/SemihostLib/SemihostLib.c b/ArmPkg/Library/SemihostLib/SemihostLib.c new file mode 100644 index 0000000000..01b6dc334d --- /dev/null +++ b/ArmPkg/Library/SemihostLib/SemihostLib.c @@ -0,0 +1,219 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include + +#include +#include + +#include "SemihostPrivate.h" + +BOOLEAN +SemihostConnectionSupported ( + VOID + ) +{ + return SEMIHOST_SUPPORTED; +} + +RETURN_STATUS +SemihostFileOpen ( + IN CHAR8 *FileName, + IN UINT32 Mode, + OUT UINT32 *FileHandle + ) +{ + SEMIHOST_FILE_OPEN_BLOCK OpenBlock; + INT32 Result; + + if (FileHandle == NULL) { + return RETURN_INVALID_PARAMETER; + } + + OpenBlock.FileName = FileName; + OpenBlock.Mode = Mode; + OpenBlock.NameLength = AsciiStrLen(FileName); + + Result = Semihost_SYS_OPEN(&OpenBlock); + + if (Result == -1) { + return RETURN_NOT_FOUND; + } else { + *FileHandle = Result; + return RETURN_SUCCESS; + } +} + +RETURN_STATUS +SemihostFileSeek ( + IN UINT32 FileHandle, + IN UINT32 Offset + ) +{ + SEMIHOST_FILE_SEEK_BLOCK SeekBlock; + INT32 Result; + + SeekBlock.Handle = FileHandle; + SeekBlock.Location = Offset; + + Result = Semihost_SYS_SEEK(&SeekBlock); + + if (Result == 0) { + return RETURN_SUCCESS; + } else { + return RETURN_ABORTED; + } +} + +RETURN_STATUS +SemihostFileRead ( + IN UINT32 FileHandle, + IN OUT UINT32 *Length, + OUT VOID *Buffer + ) +{ + SEMIHOST_FILE_READ_WRITE_BLOCK ReadBlock; + UINT32 Result; + + if ((Length == NULL) || (Buffer == NULL)) { + return RETURN_INVALID_PARAMETER; + } + + ReadBlock.Handle = FileHandle; + ReadBlock.Buffer = Buffer; + ReadBlock.Length = *Length; + + Result = Semihost_SYS_READ(&ReadBlock); + + if (Result == *Length) { + return RETURN_ABORTED; + } else { + *Length -= Result; + return RETURN_SUCCESS; + } +} + +RETURN_STATUS +SemihostFileWrite ( + IN UINT32 FileHandle, + IN OUT UINT32 *Length, + IN VOID *Buffer + ) +{ + SEMIHOST_FILE_READ_WRITE_BLOCK WriteBlock; + + if ((Length == NULL) || (Buffer == NULL)) { + return RETURN_INVALID_PARAMETER; + } + + WriteBlock.Handle = FileHandle; + WriteBlock.Buffer = Buffer; + WriteBlock.Length = *Length; + + *Length = Semihost_SYS_WRITE(&WriteBlock); + + return RETURN_SUCCESS; +} + +RETURN_STATUS +SemihostFileClose ( + IN UINT32 FileHandle + ) +{ + INT32 Result = Semihost_SYS_CLOSE(&FileHandle); + + if (Result == -1) { + return RETURN_INVALID_PARAMETER; + } else { + return RETURN_SUCCESS; + } +} + +RETURN_STATUS +SemihostFileLength ( + IN UINT32 FileHandle, + OUT UINT32 *Length + ) +{ + INT32 Result; + + if (Length == NULL) { + return RETURN_INVALID_PARAMETER; + } + + Result = Semihost_SYS_FLEN(&FileHandle); + + if (Result == -1) { + return RETURN_ABORTED; + } else { + *Length = Result; + return RETURN_SUCCESS; + } +} + +RETURN_STATUS +SemihostFileRemove ( + IN CHAR8 *FileName + ) +{ + SEMIHOST_FILE_REMOVE_BLOCK RemoveBlock; + UINT32 Result; + + RemoveBlock.FileName = FileName; + RemoveBlock.NameLength = AsciiStrLen(FileName); + + Result = Semihost_SYS_REMOVE(&RemoveBlock); + + if (Result == 0) { + return RETURN_SUCCESS; + } else { + return RETURN_ABORTED; + } +} + +CHAR8 +SemihostReadCharacter ( + VOID + ) +{ + return Semihost_SYS_READC(); +} + +VOID +SemihostWriteCharacter ( + IN CHAR8 Character + ) +{ + Semihost_SYS_WRITEC(&Character); +} + +VOID +SemihostWriteString ( + IN CHAR8 *String + ) +{ + Semihost_SYS_WRITE0(String); +} + +UINT32 +SemihostSystem ( + IN CHAR8 *CommandLine + ) +{ + SEMIHOST_SYSTEM_BLOCK SystemBlock; + + SystemBlock.CommandLine = CommandLine; + SystemBlock.CommandLength = AsciiStrLen(CommandLine); + + return Semihost_SYS_SYSTEM(&SystemBlock); +} diff --git a/ArmPkg/Library/SemihostLib/SemihostLib.inf b/ArmPkg/Library/SemihostLib/SemihostLib.inf index 5ec7fef3a6..a0a6871780 100644 --- a/ArmPkg/Library/SemihostLib/SemihostLib.inf +++ b/ArmPkg/Library/SemihostLib/SemihostLib.inf @@ -27,10 +27,11 @@ # # VALID_ARCHITECTURES = ARM # +[Sources.common] + SemihostLib.c + [Sources.ARM] Arm/GccSemihost.S | GCC - Arm/SemihostLib.c - [Packages] MdePkg/MdePkg.dec @@ -38,10 +39,4 @@ [LibraryClasses] BaseLib - -[Protocols] - -[Guids] - -[Pcd] - \ No newline at end of file + diff --git a/ArmPkg/Library/SemihostLib/SemihostPrivate.h b/ArmPkg/Library/SemihostLib/SemihostPrivate.h new file mode 100644 index 0000000000..02836ca281 --- /dev/null +++ b/ArmPkg/Library/SemihostLib/SemihostPrivate.h @@ -0,0 +1,184 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SEMIHOST_PRIVATE_H__ +#define __SEMIHOST_PRIVATE_H__ + +typedef struct { + CHAR8 *FileName; + UINT32 Mode; + UINT32 NameLength; +} SEMIHOST_FILE_OPEN_BLOCK; + +typedef struct { + UINT32 Handle; + VOID *Buffer; + UINT32 Length; +} SEMIHOST_FILE_READ_WRITE_BLOCK; + +typedef struct { + UINT32 Handle; + UINT32 Location; +} SEMIHOST_FILE_SEEK_BLOCK; + +typedef struct { + CHAR8 *FileName; + UINT32 NameLength; +} SEMIHOST_FILE_REMOVE_BLOCK; + +typedef struct { + CHAR8 *CommandLine; + UINT32 CommandLength; +} SEMIHOST_SYSTEM_BLOCK; + +#if defined(__CC_ARM) + +#if defined(__thumb__) +#define SWI 0xAB +#else +#define SWI 0x123456 +#endif + +#define SEMIHOST_SUPPORTED TRUE + +__swi(SWI) +INT32 +_Semihost_SYS_OPEN( + IN UINTN SWI_0x01, + IN SEMIHOST_FILE_OPEN_BLOCK *OpenBlock + ); + +__swi(SWI) +INT32 +_Semihost_SYS_CLOSE( + IN UINTN SWI_0x02, + IN UINT32 *Handle + ); + +__swi(SWI) +VOID +_Semihost_SYS_WRITEC( + IN UINTN SWI_0x03, + IN CHAR8 *Character + ); + +__swi(SWI) +VOID +_Semihost_SYS_WRITE0( + IN UINTN SWI_0x04, + IN CHAR8 *String + ); + +__swi(SWI) +UINT32 +_Semihost_SYS_WRITE( + IN UINTN SWI_0x05, + IN OUT SEMIHOST_FILE_READ_WRITE_BLOCK *WriteBlock + ); + +__swi(SWI) +UINT32 +_Semihost_SYS_READ( + IN UINTN SWI_0x06, + IN OUT SEMIHOST_FILE_READ_WRITE_BLOCK *ReadBlock + ); + +__swi(SWI) +CHAR8 +_Semihost_SYS_READC( + IN UINTN SWI_0x07, + IN UINTN Zero + ); + +__swi(SWI) +INT32 +_Semihost_SYS_SEEK( + IN UINTN SWI_0x0A, + IN SEMIHOST_FILE_SEEK_BLOCK *SeekBlock + ); + +__swi(SWI) +INT32 +_Semihost_SYS_FLEN( + IN UINTN SWI_0x0C, + IN UINT32 *Handle + ); + +__swi(SWI) +UINT32 +_Semihost_SYS_REMOVE( + IN UINTN SWI_0x0E, + IN SEMIHOST_FILE_REMOVE_BLOCK *RemoveBlock + ); + +__swi(SWI) +UINT32 +_Semihost_SYS_SYSTEM( + IN UINTN SWI_0x12, + IN SEMIHOST_SYSTEM_BLOCK *SystemBlock + ); + +#define Semihost_SYS_OPEN(OpenBlock) _Semihost_SYS_OPEN(0x01, OpenBlock) +#define Semihost_SYS_CLOSE(Handle) _Semihost_SYS_CLOSE(0x02, Handle) +#define Semihost_SYS_WRITE0(String) _Semihost_SYS_WRITE0(0x04, String) +#define Semihost_SYS_WRITEC(Character) _Semihost_SYS_WRITEC(0x03, Character) +#define Semihost_SYS_WRITE(WriteBlock) _Semihost_SYS_WRITE(0x05, WriteBlock) +#define Semihost_SYS_READ(ReadBlock) _Semihost_SYS_READ(0x06, ReadBlock) +#define Semihost_SYS_READC() _Semihost_SYS_READC(0x07, 0) +#define Semihost_SYS_SEEK(SeekBlock) _Semihost_SYS_SEEK(0x0A, SeekBlock) +#define Semihost_SYS_FLEN(Handle) _Semihost_SYS_FLEN(0x0C, Handle) +#define Semihost_SYS_REMOVE(RemoveBlock) _Semihost_SYS_REMOVE(0x0E, RemoveBlock) +#define Semihost_SYS_SYSTEM(SystemBlock) _Semihost_SYS_SYSTEM(0x12, SystemBlock) + +#elif defined(__GNUC__) // __CC_ARM + +#define SEMIHOST_SUPPORTED TRUE + +UINT32 +GccSemihostCall ( + IN UINT32 Operation, + IN UINTN SystemBlockAddress + ); // __attribute__ ((interrupt ("SVC"))); + +#define Semihost_SYS_OPEN(OpenBlock) GccSemihostCall(0x01, (UINTN)(OpenBlock)) +#define Semihost_SYS_CLOSE(Handle) GccSemihostCall(0x02, (UINTN)(Handle)) +#define Semihost_SYS_WRITE0(String) GccSemihostCall(0x04, (UINTN)(String)) +#define Semihost_SYS_WRITEC(Character) GccSemihostCall(0x03, (UINTN)(Character)) +#define Semihost_SYS_WRITE(WriteBlock) GccSemihostCall(0x05, (UINTN)(WriteBlock)) +#define Semihost_SYS_READ(ReadBlock) GccSemihostCall(0x06, (UINTN)(ReadBlock)) +#define Semihost_SYS_READC() GccSemihostCall(0x07, (UINTN)(0)) +#define Semihost_SYS_SEEK(SeekBlock) GccSemihostCall(0x0A, (UINTN)(SeekBlock)) +#define Semihost_SYS_FLEN(Handle) GccSemihostCall(0x0C, (UINTN)(Handle)) +#define Semihost_SYS_REMOVE(RemoveBlock) GccSemihostCall(0x0E, (UINTN)(RemoveBlock)) +#define Semihost_SYS_SYSTEM(SystemBlock) GccSemihostCall(0x12, (UINTN)(SystemBlock)) + +#else // __CC_ARM + +#define SEMIHOST_SUPPORTED FALSE + +#define Semihost_SYS_OPEN(OpenBlock) (-1) +#define Semihost_SYS_CLOSE(Handle) (-1) +#define Semihost_SYS_WRITE0(String) +#define Semihost_SYS_WRITEC(Character) +#define Semihost_SYS_WRITE(WriteBlock) (0) +#define Semihost_SYS_READ(ReadBlock) ((ReadBlock)->Length) +#define Semihost_SYS_READC() ('x') +#define Semihost_SYS_SEEK(SeekBlock) (-1) +#define Semihost_SYS_FLEN(Handle) (-1) +#define Semihost_SYS_REMOVE(RemoveBlock) (-1) +#define Semihost_SYS_SYSTEM(SystemBlock) (-1) + +#endif // __CC_ARM + +#endif //__SEMIHOST_PRIVATE_H__