--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+ Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CpuDxe.h"\r
+\r
+//FIXME: Will not compile on non-ARMv7 builds\r
+#include <Chipset/ArmV7.h>\r
+\r
+VOID\r
+ExceptionHandlersStart (\r
+ VOID\r
+ );\r
+\r
+VOID\r
+ExceptionHandlersEnd (\r
+ VOID\r
+ );\r
+\r
+VOID\r
+CommonExceptionEntry (\r
+ VOID\r
+ );\r
+\r
+VOID\r
+AsmCommonExceptionEntry (\r
+ VOID\r
+ );\r
+\r
+\r
+EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_ARM_EXCEPTION + 1];\r
+EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1];\r
+\r
+\r
+\r
+/**\r
+ This function registers and enables the handler specified by InterruptHandler for a processor\r
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the\r
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.\r
+ The installed handler is called once for each processor interrupt or exception.\r
+\r
+ @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts\r
+ are enabled and FALSE if interrupts are disabled.\r
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
+ when a processor interrupt occurs. If this parameter is NULL, then the handler\r
+ will be uninstalled.\r
+\r
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was\r
+ previously installed.\r
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
+ previously installed.\r
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+RegisterInterruptHandler (\r
+ IN EFI_EXCEPTION_TYPE InterruptType,\r
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
+ )\r
+{\r
+ if (InterruptType > MAX_ARM_EXCEPTION) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ gExceptionHandlers[InterruptType] = InterruptHandler;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+\r
+VOID\r
+EFIAPI\r
+CommonCExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE ExceptionType,\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
+ )\r
+{\r
+ if (ExceptionType <= MAX_ARM_EXCEPTION) {\r
+ if (gExceptionHandlers[ExceptionType]) {\r
+ gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext);\r
+ return;\r
+ }\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "Unknown exception type %d from %08x\n", ExceptionType, SystemContext.SystemContextArm->PC));\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ if (ExceptionType == EXCEPT_ARM_SOFTWARE_INTERRUPT) {\r
+ //\r
+ // ARM JTAG debuggers some times use this vector, so it is not an error to get one\r
+ //\r
+ return;\r
+ }\r
+\r
+ DefaultExceptionHandler (ExceptionType, SystemContext);\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+InitializeExceptions (\r
+ IN EFI_CPU_ARCH_PROTOCOL *Cpu\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Offset;\r
+ UINTN Length;\r
+ UINTN Index;\r
+ BOOLEAN IrqEnabled;\r
+ BOOLEAN FiqEnabled;\r
+ EFI_PHYSICAL_ADDRESS Base;\r
+ UINT32 *VectorBase;\r
+\r
+ Status = EFI_SUCCESS;\r
+ ZeroMem (gExceptionHandlers,sizeof(*gExceptionHandlers));\r
+\r
+ //\r
+ // Disable interrupts\r
+ //\r
+ Cpu->GetInterruptState (Cpu, &IrqEnabled);\r
+ Cpu->DisableInterrupt (Cpu);\r
+\r
+ //\r
+ // EFI does not use the FIQ, but a debugger might so we must disable\r
+ // as we take over the exception vectors.\r
+ //\r
+ FiqEnabled = ArmGetFiqState ();\r
+ ArmDisableFiq ();\r
+\r
+ if (FeaturePcdGet(PcdRelocateVectorTable) == TRUE) {\r
+ //\r
+ // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.\r
+ //\r
+ Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;\r
+\r
+ // Check if the exception vector is in the low address\r
+ if (PcdGet32 (PcdCpuVectorBaseAddress) == 0x0) {\r
+ // Set SCTLR.V to 0 to enable VBAR to be used\r
+ ArmSetLowVectors ();\r
+ } else {\r
+ ArmSetHighVectors ();\r
+ }\r
+\r
+ //\r
+ // Reserve space for the exception handlers\r
+ //\r
+ Base = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdCpuVectorBaseAddress);\r
+ VectorBase = (UINT32 *)(UINTN)Base;\r
+ Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, EFI_SIZE_TO_PAGES (Length), &Base);\r
+ // If the request was for memory that's not in the memory map (which is often the case for 0x00000000\r
+ // on embedded systems, for example, we don't want to hang up. So we'll check here for a status of\r
+ // EFI_NOT_FOUND, and continue in that case.\r
+ if (EFI_ERROR(Status) && (Status != EFI_NOT_FOUND)) {\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ if (FeaturePcdGet(PcdDebuggerExceptionSupport) == TRUE) {\r
+ // Save existing vector table, in case debugger is already hooked in\r
+ CopyMem ((VOID *)gDebuggerExceptionHandlers, (VOID *)VectorBase, sizeof (gDebuggerExceptionHandlers));\r
+ }\r
+\r
+ // Copy our assembly code into the page that contains the exception vectors.\r
+ CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);\r
+\r
+ //\r
+ // Patch in the common Assembly exception handler\r
+ //\r
+ Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;\r
+ *(UINTN *) ((UINT8 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress) + Offset) = (UINTN)AsmCommonExceptionEntry;\r
+\r
+ //\r
+ // Initialize the C entry points for interrupts\r
+ //\r
+ for (Index = 0; Index <= MAX_ARM_EXCEPTION; Index++) {\r
+ if (!FeaturePcdGet(PcdDebuggerExceptionSupport) ||\r
+ (gDebuggerExceptionHandlers[Index] == 0) || (gDebuggerExceptionHandlers[Index] == (VOID *)(UINTN)0xEAFFFFFE)) {\r
+ // Exception handler contains branch to vector location (jmp $) so no handler\r
+ // NOTE: This code assumes vectors are ARM and not Thumb code\r
+ Status = RegisterInterruptHandler (Index, NULL);\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ // If the debugger has already hooked put its vector back\r
+ VectorBase[Index] = (UINT32)(UINTN)gDebuggerExceptionHandlers[Index];\r
+ }\r
+ }\r
+\r
+ // Flush Caches since we updated executable stuff\r
+ InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length);\r
+\r
+ //Note: On ARM processor with the Security Extension, the Vector Table can be located anywhere in the memory.\r
+ // The Vector Base Address Register defines the location\r
+ ArmWriteVBar (PcdGet32(PcdCpuVectorBaseAddress));\r
+ } else {\r
+ // The Vector table must be 32-byte aligned\r
+ if (((UINT32)ExceptionHandlersStart & ARM_VECTOR_TABLE_ALIGNMENT) != 0) {\r
+ ASSERT (0);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector Base Address to point into CpuDxe code.\r
+ ArmWriteVBar ((UINT32)ExceptionHandlersStart);\r
+ }\r
+\r
+ if (FiqEnabled) {\r
+ ArmEnableFiq ();\r
+ }\r
+\r
+ if (IrqEnabled) {\r
+ //\r
+ // Restore interrupt state\r
+ //\r
+ Status = Cpu->EnableInterrupt (Cpu);\r
+ }\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+#------------------------------------------------------------------------------\r
+#\r
+# Use ARMv6 instruction to operate on a single stack\r
+#\r
+# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+# Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#------------------------------------------------------------------------------\r
+\r
+#include <Library/PcdLib.h>\r
+\r
+/*\r
+\r
+This is the stack constructed by the exception handler (low address to high address)\r
+ # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM\r
+ Reg Offset\r
+ === ======\r
+ R0 0x00 # stmfd SP!,{R0-R12}\r
+ R1 0x04\r
+ R2 0x08\r
+ R3 0x0c\r
+ R4 0x10\r
+ R5 0x14\r
+ R6 0x18\r
+ R7 0x1c\r
+ R8 0x20\r
+ R9 0x24\r
+ R10 0x28\r
+ R11 0x2c\r
+ R12 0x30\r
+ SP 0x34 # reserved via subtraction 0x20 (32) from SP\r
+ LR 0x38\r
+ PC 0x3c\r
+ CPSR 0x40\r
+ DFSR 0x44\r
+ DFAR 0x48\r
+ IFSR 0x4c\r
+ IFAR 0x50\r
+\r
+ LR 0x54 # SVC Link register (we need to restore it)\r
+\r
+ LR 0x58 # pushed by srsfd\r
+ CPSR 0x5c\r
+\r
+ */\r
+\r
+\r
+GCC_ASM_EXPORT(ExceptionHandlersStart)\r
+GCC_ASM_EXPORT(ExceptionHandlersEnd)\r
+GCC_ASM_EXPORT(CommonExceptionEntry)\r
+GCC_ASM_EXPORT(AsmCommonExceptionEntry)\r
+GCC_ASM_EXPORT(CommonCExceptionHandler)\r
+\r
+.text\r
+#if !defined(__APPLE__)\r
+.fpu neon @ makes vpush/vpop assemble\r
+#endif\r
+.align 5\r
+\r
+\r
+//\r
+// This code gets copied to the ARM vector table\r
+// ExceptionHandlersStart - ExceptionHandlersEnd gets copied\r
+//\r
+ASM_PFX(ExceptionHandlersStart):\r
+\r
+ASM_PFX(Reset):\r
+ b ASM_PFX(ResetEntry)\r
+\r
+ASM_PFX(UndefinedInstruction):\r
+ b ASM_PFX(UndefinedInstructionEntry)\r
+\r
+ASM_PFX(SoftwareInterrupt):\r
+ b ASM_PFX(SoftwareInterruptEntry)\r
+\r
+ASM_PFX(PrefetchAbort):\r
+ b ASM_PFX(PrefetchAbortEntry)\r
+\r
+ASM_PFX(DataAbort):\r
+ b ASM_PFX(DataAbortEntry)\r
+\r
+ASM_PFX(ReservedException):\r
+ b ASM_PFX(ReservedExceptionEntry)\r
+\r
+ASM_PFX(Irq):\r
+ b ASM_PFX(IrqEntry)\r
+\r
+ASM_PFX(Fiq):\r
+ b ASM_PFX(FiqEntry)\r
+\r
+ASM_PFX(ResetEntry):\r
+ srsdb #0x13! @ Store return state on SVC stack\r
+ @ We are already in SVC mode\r
+\r
+ stmfd SP!,{LR} @ Store the link register for the current mode\r
+ sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} @ Store the register state\r
+\r
+ mov R0,#0 @ ExceptionType\r
+ ldr R1,ASM_PFX(CommonExceptionEntry)\r
+ bx R1\r
+\r
+ASM_PFX(UndefinedInstructionEntry):\r
+ sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry\r
+ srsdb #0x13! @ Store return state on SVC stack\r
+ cps #0x13 @ Switch to SVC for common stack\r
+ stmfd SP!,{LR} @ Store the link register for the current mode\r
+ sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} @ Store the register state\r
+\r
+ mov R0,#1 @ ExceptionType\r
+ ldr R1,ASM_PFX(CommonExceptionEntry)\r
+ bx R1\r
+\r
+ASM_PFX(SoftwareInterruptEntry):\r
+ srsdb #0x13! @ Store return state on SVC stack\r
+ @ We are already in SVC mode\r
+ stmfd SP!,{LR} @ Store the link register for the current mode\r
+ sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} @ Store the register state\r
+\r
+ mov R0,#2 @ ExceptionType\r
+ ldr R1,ASM_PFX(CommonExceptionEntry)\r
+ bx R1\r
+\r
+ASM_PFX(PrefetchAbortEntry):\r
+ sub LR,LR,#4\r
+ srsdb #0x13! @ Store return state on SVC stack\r
+ cps #0x13 @ Switch to SVC for common stack\r
+ stmfd SP!,{LR} @ Store the link register for the current mode\r
+ sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} @ Store the register state\r
+\r
+ mov R0,#3 @ ExceptionType\r
+ ldr R1,ASM_PFX(CommonExceptionEntry)\r
+ bx R1\r
+\r
+ASM_PFX(DataAbortEntry):\r
+ sub LR,LR,#8\r
+ srsdb #0x13! @ Store return state on SVC stack\r
+ cps #0x13 @ Switch to SVC for common stack\r
+ stmfd SP!,{LR} @ Store the link register for the current mode\r
+ sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} @ Store the register state\r
+\r
+ mov R0,#4\r
+ ldr R1,ASM_PFX(CommonExceptionEntry)\r
+ bx R1\r
+\r
+ASM_PFX(ReservedExceptionEntry):\r
+ srsdb #0x13! @ Store return state on SVC stack\r
+ cps #0x13 @ Switch to SVC for common stack\r
+ stmfd SP!,{LR} @ Store the link register for the current mode\r
+ sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} @ Store the register state\r
+\r
+ mov R0,#5\r
+ ldr R1,ASM_PFX(CommonExceptionEntry)\r
+ bx R1\r
+\r
+ASM_PFX(IrqEntry):\r
+ sub LR,LR,#4\r
+ srsdb #0x13! @ Store return state on SVC stack\r
+ cps #0x13 @ Switch to SVC for common stack\r
+ stmfd SP!,{LR} @ Store the link register for the current mode\r
+ sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} @ Store the register state\r
+\r
+ mov R0,#6 @ ExceptionType\r
+ ldr R1,ASM_PFX(CommonExceptionEntry)\r
+ bx R1\r
+\r
+ASM_PFX(FiqEntry):\r
+ sub LR,LR,#4\r
+ srsdb #0x13! @ Store return state on SVC stack\r
+ cps #0x13 @ Switch to SVC for common stack\r
+ stmfd SP!,{LR} @ Store the link register for the current mode\r
+ sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} @ Store the register state\r
+ @ Since we have already switch to SVC R8_fiq - R12_fiq\r
+ @ never get used or saved\r
+ mov R0,#7 @ ExceptionType\r
+ ldr R1,ASM_PFX(CommonExceptionEntry)\r
+ bx R1\r
+\r
+//\r
+// This gets patched by the C code that patches in the vector table\r
+//\r
+ASM_PFX(CommonExceptionEntry):\r
+ .word ASM_PFX(AsmCommonExceptionEntry)\r
+\r
+ASM_PFX(ExceptionHandlersEnd):\r
+\r
+//\r
+// This code runs from CpuDxe driver loaded address. It is patched into\r
+// CommonExceptionEntry.\r
+//\r
+ASM_PFX(AsmCommonExceptionEntry):\r
+ mrc p15, 0, R1, c6, c0, 2 @ Read IFAR\r
+ str R1, [SP, #0x50] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR\r
+\r
+ mrc p15, 0, R1, c5, c0, 1 @ Read IFSR\r
+ str R1, [SP, #0x4c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR\r
+\r
+ mrc p15, 0, R1, c6, c0, 0 @ Read DFAR\r
+ str R1, [SP, #0x48] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR\r
+\r
+ mrc p15, 0, R1, c5, c0, 0 @ Read DFSR\r
+ str R1, [SP, #0x44] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR\r
+\r
+ ldr R1, [SP, #0x5c] @ srsdb saved pre-exception CPSR on the stack\r
+ str R1, [SP, #0x40] @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR\r
+\r
+ add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
+ and R3, R1, #0x1f @ Check CPSR to see if User or System Mode\r
+ cmp R3, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f))\r
+ cmpne R3, #0x10 @\r
+ stmeqed R2, {lr}^ @ save unbanked lr\r
+ @ else\r
+ stmneed R2, {lr} @ save SVC lr\r
+\r
+\r
+ ldr R5, [SP, #0x58] @ PC is the LR pushed by srsfd\r
+ @ Check to see if we have to adjust for Thumb entry\r
+ sub r4, r0, #1 @ if (ExceptionType == 1 || ExceptionType == 2)) {\r
+ cmp r4, #1 @ // UND & SVC have differnt LR adjust for Thumb\r
+ bhi NoAdjustNeeded\r
+\r
+ tst r1, #0x20 @ if ((CPSR & T)) == T) { // Thumb Mode on entry\r
+ addne R5, R5, #2 @ PC += 2;\r
+ strne R5,[SP,#0x58] @ Update LR value pushed by srsfd\r
+\r
+NoAdjustNeeded:\r
+\r
+ str R5, [SP, #0x3c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC\r
+\r
+ add R1, SP, #0x60 @ We pushed 0x60 bytes on the stack\r
+ str R1, [SP, #0x34] @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP\r
+\r
+ @ R0 is ExceptionType\r
+ mov R1,SP @ R1 is SystemContext\r
+\r
+#if (FixedPcdGet32(PcdVFPEnabled))\r
+ vpush {d0-d15} @ save vstm registers in case they are used in optimizations\r
+#endif\r
+\r
+ mov R4, SP @ Save current SP\r
+ tst R4, #4\r
+ subne SP, SP, #4 @ Adjust SP if not 8-byte aligned\r
+\r
+/*\r
+VOID\r
+EFIAPI\r
+CommonCExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE ExceptionType, R0\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext R1\r
+ )\r
+\r
+*/\r
+ blx ASM_PFX(CommonCExceptionHandler) @ Call exception handler\r
+\r
+ mov SP, R4 @ Restore SP\r
+\r
+#if (FixedPcdGet32(PcdVFPEnabled))\r
+ vpop {d0-d15}\r
+#endif\r
+\r
+ ldr R1, [SP, #0x4c] @ Restore EFI_SYSTEM_CONTEXT_ARM.IFSR\r
+ mcr p15, 0, R1, c5, c0, 1 @ Write IFSR\r
+\r
+ ldr R1, [SP, #0x44] @ Restore EFI_SYSTEM_CONTEXT_ARM.DFSR\r
+ mcr p15, 0, R1, c5, c0, 0 @ Write DFSR\r
+\r
+ ldr R1,[SP,#0x3c] @ EFI_SYSTEM_CONTEXT_ARM.PC\r
+ str R1,[SP,#0x58] @ Store it back to srsfd stack slot so it can be restored\r
+\r
+ ldr R1,[SP,#0x40] @ EFI_SYSTEM_CONTEXT_ARM.CPSR\r
+ str R1,[SP,#0x5c] @ Store it back to srsfd stack slot so it can be restored\r
+\r
+ add R3, SP, #0x54 @ Make R3 point to SVC LR saved on entry\r
+ add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
+ and R1, R1, #0x1f @ Check to see if User or System Mode\r
+ cmp R1, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f))\r
+ cmpne R1, #0x10 @\r
+ ldmeqed R2, {lr}^ @ restore unbanked lr\r
+ @ else\r
+ ldmneed R3, {lr} @ restore SVC lr, via ldmfd SP!, {LR}\r
+\r
+ ldmfd SP!,{R0-R12} @ Restore general purpose registers\r
+ @ Exception handler can not change SP\r
+\r
+ add SP,SP,#0x20 @ Clear out the remaining stack space\r
+ ldmfd SP!,{LR} @ restore the link register for this context\r
+ rfefd SP! @ return from exception via srsfd stack slot\r
+\r
--- /dev/null
+//------------------------------------------------------------------------------\r
+//\r
+// Use ARMv6 instruction to operate on a single stack\r
+//\r
+// Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
+// Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+//------------------------------------------------------------------------------\r
+\r
+#include <Library/PcdLib.h>\r
+\r
+/*\r
+\r
+This is the stack constructed by the exception handler (low address to high address)\r
+ # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM\r
+ Reg Offset\r
+ === ======\r
+ R0 0x00 # stmfd SP!,{R0-R12}\r
+ R1 0x04\r
+ R2 0x08\r
+ R3 0x0c\r
+ R4 0x10\r
+ R5 0x14\r
+ R6 0x18\r
+ R7 0x1c\r
+ R8 0x20\r
+ R9 0x24\r
+ R10 0x28\r
+ R11 0x2c\r
+ R12 0x30\r
+ SP 0x34 # reserved via subtraction 0x20 (32) from SP\r
+ LR 0x38\r
+ PC 0x3c\r
+ CPSR 0x40\r
+ DFSR 0x44\r
+ DFAR 0x48\r
+ IFSR 0x4c\r
+ IFAR 0x50\r
+\r
+ LR 0x54 # SVC Link register (we need to restore it)\r
+\r
+ LR 0x58 # pushed by srsfd\r
+ CPSR 0x5c\r
+\r
+ */\r
+\r
+\r
+ EXPORT ExceptionHandlersStart\r
+ EXPORT ExceptionHandlersEnd\r
+ EXPORT CommonExceptionEntry\r
+ EXPORT AsmCommonExceptionEntry\r
+ IMPORT CommonCExceptionHandler\r
+\r
+ PRESERVE8\r
+ AREA DxeExceptionHandlers, CODE, READONLY, CODEALIGN, ALIGN=5\r
+\r
+//\r
+// This code gets copied to the ARM vector table\r
+// ExceptionHandlersStart - ExceptionHandlersEnd gets copied\r
+//\r
+ExceptionHandlersStart\r
+\r
+Reset\r
+ b ResetEntry\r
+\r
+UndefinedInstruction\r
+ b UndefinedInstructionEntry\r
+\r
+SoftwareInterrupt\r
+ b SoftwareInterruptEntry\r
+\r
+PrefetchAbort\r
+ b PrefetchAbortEntry\r
+\r
+DataAbort\r
+ b DataAbortEntry\r
+\r
+ReservedException\r
+ b ReservedExceptionEntry\r
+\r
+Irq\r
+ b IrqEntry\r
+\r
+Fiq\r
+ b FiqEntry\r
+\r
+ResetEntry\r
+ srsfd #0x13! ; Store return state on SVC stack\r
+ ; We are already in SVC mode\r
+ stmfd SP!,{LR} ; Store the link register for the current mode\r
+ sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} ; Store the register state\r
+\r
+ mov R0,#0 ; ExceptionType\r
+ ldr R1,CommonExceptionEntry\r
+ bx R1\r
+\r
+UndefinedInstructionEntry\r
+ sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry\r
+ srsfd #0x13! ; Store return state on SVC stack\r
+ cps #0x13 ; Switch to SVC for common stack\r
+ stmfd SP!,{LR} ; Store the link register for the current mode\r
+ sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} ; Store the register state\r
+\r
+ mov R0,#1 ; ExceptionType\r
+ ldr R1,CommonExceptionEntry;\r
+ bx R1\r
+\r
+SoftwareInterruptEntry\r
+ srsfd #0x13! ; Store return state on SVC stack\r
+ ; We are already in SVC mode\r
+ stmfd SP!,{LR} ; Store the link register for the current mode\r
+ sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} ; Store the register state\r
+\r
+ mov R0,#2 ; ExceptionType\r
+ ldr R1,CommonExceptionEntry\r
+ bx R1\r
+\r
+PrefetchAbortEntry\r
+ sub LR,LR,#4\r
+ srsfd #0x13! ; Store return state on SVC stack\r
+ cps #0x13 ; Switch to SVC for common stack\r
+ stmfd SP!,{LR} ; Store the link register for the current mode\r
+ sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} ; Store the register state\r
+\r
+ mov R0,#3 ; ExceptionType\r
+ ldr R1,CommonExceptionEntry\r
+ bx R1\r
+\r
+DataAbortEntry\r
+ sub LR,LR,#8\r
+ srsfd #0x13! ; Store return state on SVC stack\r
+ cps #0x13 ; Switch to SVC for common stack\r
+ stmfd SP!,{LR} ; Store the link register for the current mode\r
+ sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} ; Store the register state\r
+\r
+ mov R0,#4 ; ExceptionType\r
+ ldr R1,CommonExceptionEntry\r
+ bx R1\r
+\r
+ReservedExceptionEntry\r
+ srsfd #0x13! ; Store return state on SVC stack\r
+ cps #0x13 ; Switch to SVC for common stack\r
+ stmfd SP!,{LR} ; Store the link register for the current mode\r
+ sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} ; Store the register state\r
+\r
+ mov R0,#5 ; ExceptionType\r
+ ldr R1,CommonExceptionEntry\r
+ bx R1\r
+\r
+IrqEntry\r
+ sub LR,LR,#4\r
+ srsfd #0x13! ; Store return state on SVC stack\r
+ cps #0x13 ; Switch to SVC for common stack\r
+ stmfd SP!,{LR} ; Store the link register for the current mode\r
+ sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} ; Store the register state\r
+\r
+ mov R0,#6 ; ExceptionType\r
+ ldr R1,CommonExceptionEntry\r
+ bx R1\r
+\r
+FiqEntry\r
+ sub LR,LR,#4\r
+ srsfd #0x13! ; Store return state on SVC stack\r
+ cps #0x13 ; Switch to SVC for common stack\r
+ stmfd SP!,{LR} ; Store the link register for the current mode\r
+ sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
+ stmfd SP!,{R0-R12} ; Store the register state\r
+ ; Since we have already switch to SVC R8_fiq - R12_fiq\r
+ ; never get used or saved\r
+ mov R0,#7 ; ExceptionType\r
+ ldr R1,CommonExceptionEntry\r
+ bx R1\r
+\r
+//\r
+// This gets patched by the C code that patches in the vector table\r
+//\r
+CommonExceptionEntry\r
+ dcd AsmCommonExceptionEntry\r
+\r
+ExceptionHandlersEnd\r
+\r
+//\r
+// This code runs from CpuDxe driver loaded address. It is patched into\r
+// CommonExceptionEntry.\r
+//\r
+AsmCommonExceptionEntry\r
+ mrc p15, 0, R1, c6, c0, 2 ; Read IFAR\r
+ str R1, [SP, #0x50] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR\r
+\r
+ mrc p15, 0, R1, c5, c0, 1 ; Read IFSR\r
+ str R1, [SP, #0x4c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR\r
+\r
+ mrc p15, 0, R1, c6, c0, 0 ; Read DFAR\r
+ str R1, [SP, #0x48] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR\r
+\r
+ mrc p15, 0, R1, c5, c0, 0 ; Read DFSR\r
+ str R1, [SP, #0x44] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR\r
+\r
+ ldr R1, [SP, #0x5c] ; srsfd saved pre-exception CPSR on the stack\r
+ str R1, [SP, #0x40] ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR\r
+\r
+ add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
+ and R3, R1, #0x1f ; Check CPSR to see if User or System Mode\r
+ cmp R3, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f))\r
+ cmpne R3, #0x10 ;\r
+ stmeqed R2, {lr}^ ; save unbanked lr\r
+ ; else\r
+ stmneed R2, {lr} ; save SVC lr\r
+\r
+\r
+ ldr R5, [SP, #0x58] ; PC is the LR pushed by srsfd\r
+ ; Check to see if we have to adjust for Thumb entry\r
+ sub r4, r0, #1 ; if (ExceptionType == 1 || ExceptionType == 2)) {\r
+ cmp r4, #1 ; // UND & SVC have differnt LR adjust for Thumb\r
+ bhi NoAdjustNeeded\r
+\r
+ tst r1, #0x20 ; if ((CPSR & T)) == T) { // Thumb Mode on entry\r
+ addne R5, R5, #2 ; PC += 2;\r
+ strne R5,[SP,#0x58] ; Update LR value pushed by srsfd\r
+\r
+NoAdjustNeeded\r
+\r
+ str R5, [SP, #0x3c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC\r
+\r
+ add R1, SP, #0x60 ; We pushed 0x60 bytes on the stack\r
+ str R1, [SP, #0x34] ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP\r
+\r
+ ; R0 is ExceptionType\r
+ mov R1,SP ; R1 is SystemContext\r
+\r
+#if (FixedPcdGet32(PcdVFPEnabled))\r
+ vpush {d0-d15} ; save vstm registers in case they are used in optimizations\r
+#endif\r
+\r
+ mov R4, SP ; Save current SP\r
+ tst R4, #4\r
+ subne SP, SP, #4 ; Adjust SP if not 8-byte aligned\r
+\r
+/*\r
+VOID\r
+EFIAPI\r
+CommonCExceptionHandler (\r
+ IN EFI_EXCEPTION_TYPE ExceptionType, R0\r
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext R1\r
+ )\r
+\r
+*/\r
+ blx CommonCExceptionHandler ; Call exception handler\r
+\r
+ mov SP, R4 ; Restore SP\r
+\r
+#if (FixedPcdGet32(PcdVFPEnabled))\r
+ vpop {d0-d15}\r
+#endif\r
+\r
+ ldr R1, [SP, #0x4c] ; Restore EFI_SYSTEM_CONTEXT_ARM.IFSR\r
+ mcr p15, 0, R1, c5, c0, 1 ; Write IFSR\r
+\r
+ ldr R1, [SP, #0x44] ; Restore EFI_SYSTEM_CONTEXT_ARM.DFSR\r
+ mcr p15, 0, R1, c5, c0, 0 ; Write DFSR\r
+\r
+ ldr R1,[SP,#0x3c] ; EFI_SYSTEM_CONTEXT_ARM.PC\r
+ str R1,[SP,#0x58] ; Store it back to srsfd stack slot so it can be restored\r
+\r
+ ldr R1,[SP,#0x40] ; EFI_SYSTEM_CONTEXT_ARM.CPSR\r
+ str R1,[SP,#0x5c] ; Store it back to srsfd stack slot so it can be restored\r
+\r
+ add R3, SP, #0x54 ; Make R3 point to SVC LR saved on entry\r
+ add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
+ and R1, R1, #0x1f ; Check to see if User or System Mode\r
+ cmp R1, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f))\r
+ cmpne R1, #0x10 ;\r
+ ldmeqed R2, {lr}^ ; restore unbanked lr\r
+ ; else\r
+ ldmneed R3, {lr} ; restore SVC lr, via ldmfd SP!, {LR}\r
+\r
+ ldmfd SP!,{R0-R12} ; Restore general purpose registers\r
+ ; Exception handler can not change SP\r
+\r
+ add SP,SP,#0x20 ; Clear out the remaining stack space\r
+ ldmfd SP!,{LR} ; restore the link register for this context\r
+ rfefd SP! ; return from exception via srsfd stack slot\r
+\r
+ END\r
+\r
+\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>\r
+Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>\r
+Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+--*/\r
+\r
+#include <Library/MemoryAllocationLib.h>\r
+#include "CpuDxe.h"\r
+\r
+// First Level Descriptors\r
+typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR;\r
+\r
+// Second Level Descriptors\r
+typedef UINT32 ARM_PAGE_TABLE_ENTRY;\r
+\r
+EFI_STATUS\r
+SectionToGcdAttributes (\r
+ IN UINT32 SectionAttributes,\r
+ OUT UINT64 *GcdAttributes\r
+ )\r
+{\r
+ *GcdAttributes = 0;\r
+\r
+ // determine cacheability attributes\r
+ switch(SectionAttributes & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) {\r
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED:\r
+ *GcdAttributes |= EFI_MEMORY_UC;\r
+ break;\r
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE:\r
+ *GcdAttributes |= EFI_MEMORY_UC;\r
+ break;\r
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:\r
+ *GcdAttributes |= EFI_MEMORY_WT;\r
+ break;\r
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_NO_ALLOC:\r
+ *GcdAttributes |= EFI_MEMORY_WB;\r
+ break;\r
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE:\r
+ *GcdAttributes |= EFI_MEMORY_WC;\r
+ break;\r
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC:\r
+ *GcdAttributes |= EFI_MEMORY_WB;\r
+ break;\r
+ case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_SHAREABLE_DEVICE:\r
+ *GcdAttributes |= EFI_MEMORY_UC;\r
+ break;\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ // determine protection attributes\r
+ switch(SectionAttributes & TT_DESCRIPTOR_SECTION_AP_MASK) {\r
+ case TT_DESCRIPTOR_SECTION_AP_NO_NO: // no read, no write\r
+ //*GcdAttributes |= EFI_MEMORY_WP | EFI_MEMORY_RP;\r
+ break;\r
+\r
+ case TT_DESCRIPTOR_SECTION_AP_RW_NO:\r
+ case TT_DESCRIPTOR_SECTION_AP_RW_RW:\r
+ // normal read/write access, do not add additional attributes\r
+ break;\r
+\r
+ // read only cases map to write-protect\r
+ case TT_DESCRIPTOR_SECTION_AP_RO_NO:\r
+ case TT_DESCRIPTOR_SECTION_AP_RO_RO:\r
+ *GcdAttributes |= EFI_MEMORY_WP;\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ // now process eXectue Never attribute\r
+ if ((SectionAttributes & TT_DESCRIPTOR_SECTION_XN_MASK) != 0 ) {\r
+ *GcdAttributes |= EFI_MEMORY_XP;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+PageToGcdAttributes (\r
+ IN UINT32 PageAttributes,\r
+ OUT UINT64 *GcdAttributes\r
+ )\r
+{\r
+ *GcdAttributes = 0;\r
+\r
+ // determine cacheability attributes\r
+ switch(PageAttributes & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) {\r
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED:\r
+ *GcdAttributes |= EFI_MEMORY_UC;\r
+ break;\r
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE:\r
+ *GcdAttributes |= EFI_MEMORY_UC;\r
+ break;\r
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:\r
+ *GcdAttributes |= EFI_MEMORY_WT;\r
+ break;\r
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_NO_ALLOC:\r
+ *GcdAttributes |= EFI_MEMORY_WB;\r
+ break;\r
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE:\r
+ *GcdAttributes |= EFI_MEMORY_WC;\r
+ break;\r
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC:\r
+ *GcdAttributes |= EFI_MEMORY_WB;\r
+ break;\r
+ case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_SHAREABLE_DEVICE:\r
+ *GcdAttributes |= EFI_MEMORY_UC;\r
+ break;\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ // determine protection attributes\r
+ switch(PageAttributes & TT_DESCRIPTOR_PAGE_AP_MASK) {\r
+ case TT_DESCRIPTOR_PAGE_AP_NO_NO: // no read, no write\r
+ //*GcdAttributes |= EFI_MEMORY_WP | EFI_MEMORY_RP;\r
+ break;\r
+\r
+ case TT_DESCRIPTOR_PAGE_AP_RW_NO:\r
+ case TT_DESCRIPTOR_PAGE_AP_RW_RW:\r
+ // normal read/write access, do not add additional attributes\r
+ break;\r
+\r
+ // read only cases map to write-protect\r
+ case TT_DESCRIPTOR_PAGE_AP_RO_NO:\r
+ case TT_DESCRIPTOR_PAGE_AP_RO_RO:\r
+ *GcdAttributes |= EFI_MEMORY_WP;\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ // now process eXectue Never attribute\r
+ if ((PageAttributes & TT_DESCRIPTOR_PAGE_XN_MASK) != 0 ) {\r
+ *GcdAttributes |= EFI_MEMORY_XP;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+SyncCacheConfigPage (\r
+ IN UINT32 SectionIndex,\r
+ IN UINT32 FirstLevelDescriptor,\r
+ IN UINTN NumberOfDescriptors,\r
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
+ IN OUT EFI_PHYSICAL_ADDRESS *NextRegionBase,\r
+ IN OUT UINT64 *NextRegionLength,\r
+ IN OUT UINT32 *NextSectionAttributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 i;\r
+ volatile ARM_PAGE_TABLE_ENTRY *SecondLevelTable;\r
+ UINT32 NextPageAttributes = 0;\r
+ UINT32 PageAttributes = 0;\r
+ UINT32 BaseAddress;\r
+ UINT64 GcdAttributes;\r
+\r
+ // Get the Base Address from FirstLevelDescriptor;\r
+ BaseAddress = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(SectionIndex << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
+\r
+ // Convert SectionAttributes into PageAttributes\r
+ NextPageAttributes =\r
+ TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(*NextSectionAttributes,0) |\r
+ TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(*NextSectionAttributes);\r
+\r
+ // obtain page table base\r
+ SecondLevelTable = (ARM_PAGE_TABLE_ENTRY *)(FirstLevelDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
+\r
+ for (i=0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) {\r
+ if ((SecondLevelTable[i] & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {\r
+ // extract attributes (cacheability and permissions)\r
+ PageAttributes = SecondLevelTable[i] & (TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK | TT_DESCRIPTOR_PAGE_AP_MASK);\r
+\r
+ if (NextPageAttributes == 0) {\r
+ // start on a new region\r
+ *NextRegionLength = 0;\r
+ *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
+ NextPageAttributes = PageAttributes;\r
+ } else if (PageAttributes != NextPageAttributes) {\r
+ // Convert Section Attributes into GCD Attributes\r
+ Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);\r
+\r
+ // start on a new region\r
+ *NextRegionLength = 0;\r
+ *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
+ NextPageAttributes = PageAttributes;\r
+ }\r
+ } else if (NextPageAttributes != 0) {\r
+ // Convert Page Attributes into GCD Attributes\r
+ Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);\r
+\r
+ *NextRegionLength = 0;\r
+ *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
+ NextPageAttributes = 0;\r
+ }\r
+ *NextRegionLength += TT_DESCRIPTOR_PAGE_SIZE;\r
+ }\r
+\r
+ // Convert back PageAttributes into SectionAttributes\r
+ *NextSectionAttributes =\r
+ TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY(NextPageAttributes,0) |\r
+ TT_DESCRIPTOR_CONVERT_TO_SECTION_AP(NextPageAttributes);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+SyncCacheConfig (\r
+ IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 i;\r
+ EFI_PHYSICAL_ADDRESS NextRegionBase;\r
+ UINT64 NextRegionLength;\r
+ UINT32 NextSectionAttributes = 0;\r
+ UINT32 SectionAttributes = 0;\r
+ UINT64 GcdAttributes;\r
+ volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
+ UINTN NumberOfDescriptors;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
+\r
+\r
+ DEBUG ((EFI_D_PAGE, "SyncCacheConfig()\n"));\r
+\r
+ // This code assumes MMU is enabled and filed with section translations\r
+ ASSERT (ArmMmuEnabled ());\r
+\r
+ //\r
+ // Get the memory space map from GCD\r
+ //\r
+ MemorySpaceMap = NULL;\r
+ Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+\r
+ // The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs\r
+ // to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a\r
+ // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were\r
+ // a client) to update its copy of the attributes. This is bad architecture and should be replaced\r
+ // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.\r
+\r
+ // obtain page table base\r
+ FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)(ArmGetTTBR0BaseAddress ());\r
+\r
+ // Get the first region\r
+ NextSectionAttributes = FirstLevelTable[0] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);\r
+\r
+ // iterate through each 1MB descriptor\r
+ NextRegionBase = NextRegionLength = 0;\r
+ for (i=0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) {\r
+ if ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {\r
+ // extract attributes (cacheability and permissions)\r
+ SectionAttributes = FirstLevelTable[i] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);\r
+\r
+ if (NextSectionAttributes == 0) {\r
+ // start on a new region\r
+ NextRegionLength = 0;\r
+ NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
+ NextSectionAttributes = SectionAttributes;\r
+ } else if (SectionAttributes != NextSectionAttributes) {\r
+ // Convert Section Attributes into GCD Attributes\r
+ Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
+\r
+ // start on a new region\r
+ NextRegionLength = 0;\r
+ NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
+ NextSectionAttributes = SectionAttributes;\r
+ }\r
+ NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;\r
+ } else if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(FirstLevelTable[i])) {\r
+ Status = SyncCacheConfigPage (\r
+ i,FirstLevelTable[i],\r
+ NumberOfDescriptors, MemorySpaceMap,\r
+ &NextRegionBase,&NextRegionLength,&NextSectionAttributes);\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ // We do not support yet 16MB sections\r
+ ASSERT ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) != TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION);\r
+\r
+ // start on a new region\r
+ if (NextSectionAttributes != 0) {\r
+ // Convert Section Attributes into GCD Attributes\r
+ Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
+\r
+ NextRegionLength = 0;\r
+ NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
+ NextSectionAttributes = 0;\r
+ }\r
+ NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;\r
+ }\r
+ } // section entry loop\r
+\r
+ if (NextSectionAttributes != 0) {\r
+ // Convert Section Attributes into GCD Attributes\r
+ Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
+ SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
+ }\r
+\r
+ FreePool (MemorySpaceMap);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+UpdatePageEntries (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 Attributes,\r
+ IN EFI_PHYSICAL_ADDRESS VirtualMask\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 EntryValue;\r
+ UINT32 EntryMask;\r
+ UINT32 FirstLevelIdx;\r
+ UINT32 Offset;\r
+ UINT32 NumPageEntries;\r
+ UINT32 Descriptor;\r
+ UINT32 p;\r
+ UINT32 PageTableIndex;\r
+ UINT32 PageTableEntry;\r
+ UINT32 CurrentPageTableEntry;\r
+ VOID *Mva;\r
+\r
+ volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
+ volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
+ // EntryValue: values at bit positions specified by EntryMask\r
+ EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK;\r
+ EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE;\r
+ // Although the PI spec is unclear on this the GCD guarantees that only\r
+ // one Attribute bit is set at a time, so we can safely use a switch statement\r
+ switch (Attributes) {\r
+ case EFI_MEMORY_UC:\r
+ // modify cacheability attributes\r
+ EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
+ // map to strongly ordered\r
+ EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WC:\r
+ // modify cacheability attributes\r
+ EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
+ // map to normal non-cachable\r
+ EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WT:\r
+ // modify cacheability attributes\r
+ EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
+ // write through with no-allocate\r
+ EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WB:\r
+ // modify cacheability attributes\r
+ EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
+ // write back (with allocate)\r
+ EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
+ break;\r
+\r
+ case EFI_MEMORY_WP:\r
+ case EFI_MEMORY_XP:\r
+ case EFI_MEMORY_UCE:\r
+ // cannot be implemented UEFI definition unclear for ARM\r
+ // Cause a page fault if these ranges are accessed.\r
+ EntryValue = TT_DESCRIPTOR_PAGE_TYPE_FAULT;\r
+ DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting page %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ // Obtain page table base\r
+ FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
+\r
+ // Calculate number of 4KB page table entries to change\r
+ NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE;\r
+\r
+ // Iterate for the number of 4KB pages to change\r
+ Offset = 0;\r
+ for(p = 0; p < NumPageEntries; p++) {\r
+ // Calculate index into first level translation table for page table value\r
+\r
+ FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
+ ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
+\r
+ // Read the descriptor from the first level page table\r
+ Descriptor = FirstLevelTable[FirstLevelIdx];\r
+\r
+ // Does this descriptor need to be converted from section entry to 4K pages?\r
+ if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) {\r
+ Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
+ if (EFI_ERROR(Status)) {\r
+ // Exit for loop\r
+ break;\r
+ }\r
+\r
+ // Re-read descriptor\r
+ Descriptor = FirstLevelTable[FirstLevelIdx];\r
+ }\r
+\r
+ // Obtain page table base address\r
+ PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor);\r
+\r
+ // Calculate index into the page table\r
+ PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
+ ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
+\r
+ // Get the entry\r
+ CurrentPageTableEntry = PageTable[PageTableIndex];\r
+\r
+ // Mask off appropriate fields\r
+ PageTableEntry = CurrentPageTableEntry & ~EntryMask;\r
+\r
+ // Mask in new attributes and/or permissions\r
+ PageTableEntry |= EntryValue;\r
+\r
+ if (VirtualMask != 0) {\r
+ // Make this virtual address point at a physical page\r
+ PageTableEntry &= ~VirtualMask;\r
+ }\r
+\r
+ if (CurrentPageTableEntry != PageTableEntry) {\r
+ Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
+ if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {\r
+ // The current section mapping is cacheable so Clean/Invalidate the MVA of the page\r
+ // Note assumes switch(Attributes), not ARMv7 possibilities\r
+ WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);\r
+ }\r
+\r
+ // Only need to update if we are changing the entry\r
+ PageTable[PageTableIndex] = PageTableEntry;\r
+ ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ Offset += TT_DESCRIPTOR_PAGE_SIZE;\r
+\r
+ } // End first level translation table loop\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+UpdateSectionEntries (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 Attributes,\r
+ IN EFI_PHYSICAL_ADDRESS VirtualMask\r
+ )\r
+{\r
+ EFI_STATUS Status = EFI_SUCCESS;\r
+ UINT32 EntryMask;\r
+ UINT32 EntryValue;\r
+ UINT32 FirstLevelIdx;\r
+ UINT32 NumSections;\r
+ UINT32 i;\r
+ UINT32 CurrentDescriptor;\r
+ UINT32 Descriptor;\r
+ VOID *Mva;\r
+ volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
+\r
+ // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
+ // EntryValue: values at bit positions specified by EntryMask\r
+\r
+ // Make sure we handle a section range that is unmapped\r
+ EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK;\r
+ EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION;\r
+\r
+ // Although the PI spec is unclear on this the GCD guarantees that only\r
+ // one Attribute bit is set at a time, so we can safely use a switch statement\r
+ switch(Attributes) {\r
+ case EFI_MEMORY_UC:\r
+ // modify cacheability attributes\r
+ EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
+ // map to strongly ordered\r
+ EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WC:\r
+ // modify cacheability attributes\r
+ EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
+ // map to normal non-cachable\r
+ EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WT:\r
+ // modify cacheability attributes\r
+ EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
+ // write through with no-allocate\r
+ EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WB:\r
+ // modify cacheability attributes\r
+ EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
+ // write back (with allocate)\r
+ EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
+ break;\r
+\r
+ case EFI_MEMORY_WP:\r
+ case EFI_MEMORY_XP:\r
+ case EFI_MEMORY_RP:\r
+ case EFI_MEMORY_UCE:\r
+ // cannot be implemented UEFI definition unclear for ARM\r
+ // Cause a page fault if these ranges are accessed.\r
+ EntryValue = TT_DESCRIPTOR_SECTION_TYPE_FAULT;\r
+ DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting section %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));\r
+ break;\r
+\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ // obtain page table base\r
+ FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
+\r
+ // calculate index into first level translation table for start of modification\r
+ FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
+ ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
+\r
+ // calculate number of 1MB first level entries this applies to\r
+ NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE;\r
+\r
+ // iterate through each descriptor\r
+ for(i=0; i<NumSections; i++) {\r
+ CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i];\r
+\r
+ // has this descriptor already been coverted to pages?\r
+ if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {\r
+ // forward this 1MB range to page table function instead\r
+ Status = UpdatePageEntries ((FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT, TT_DESCRIPTOR_SECTION_SIZE, Attributes, VirtualMask);\r
+ } else {\r
+ // still a section entry\r
+\r
+ // mask off appropriate fields\r
+ Descriptor = CurrentDescriptor & ~EntryMask;\r
+\r
+ // mask in new attributes and/or permissions\r
+ Descriptor |= EntryValue;\r
+ if (VirtualMask != 0) {\r
+ Descriptor &= ~VirtualMask;\r
+ }\r
+\r
+ if (CurrentDescriptor != Descriptor) {\r
+ Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
+ if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {\r
+ // The current section mapping is cacheable so Clean/Invalidate the MVA of the section\r
+ // Note assumes switch(Attributes), not ARMv7 possabilities\r
+ WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);\r
+ }\r
+\r
+ // Only need to update if we are changing the descriptor\r
+ FirstLevelTable[FirstLevelIdx + i] = Descriptor;\r
+ ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+ConvertSectionToPages (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS PageTableAddr;\r
+ UINT32 FirstLevelIdx;\r
+ UINT32 SectionDescriptor;\r
+ UINT32 PageTableDescriptor;\r
+ UINT32 PageDescriptor;\r
+ UINT32 Index;\r
+\r
+ volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
+ volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
+\r
+ DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));\r
+\r
+ // Obtain page table base\r
+ FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
+\r
+ // Calculate index into first level translation table for start of modification\r
+ FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
+ ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
+\r
+ // Get section attributes and convert to page attributes\r
+ SectionDescriptor = FirstLevelTable[FirstLevelIdx];\r
+ PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (SectionDescriptor, FALSE);\r
+\r
+ // Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB)\r
+ Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1, &PageTableAddr);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr;\r
+\r
+ // Write the page table entries out\r
+ for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {\r
+ PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor;\r
+ }\r
+\r
+ // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
+ WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, TT_DESCRIPTOR_PAGE_SIZE);\r
+\r
+ // Formulate page table entry, Domain=0, NS=0\r
+ PageTableDescriptor = (((UINTN)PageTableAddr) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;\r
+\r
+ // Write the page table entry out, replacing section entry\r
+ FirstLevelTable[FirstLevelIdx] = PageTableDescriptor;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+EFI_STATUS\r
+SetMemoryAttributes (\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 Attributes,\r
+ IN EFI_PHYSICAL_ADDRESS VirtualMask\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if(((BaseAddress & 0xFFFFF) == 0) && ((Length & 0xFFFFF) == 0)) {\r
+ // Is the base and length a multiple of 1 MB?\r
+ DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
+ Status = UpdateSectionEntries (BaseAddress, Length, Attributes, VirtualMask);\r
+ } else {\r
+ // Base and/or length is not a multiple of 1 MB\r
+ DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU page 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
+ Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask);\r
+ }\r
+\r
+ // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
+ // flush and invalidate pages\r
+ //TODO: Do we really need to invalidate the caches everytime we change the memory attributes ?\r
+ ArmCleanInvalidateDataCache ();\r
+\r
+ ArmInvalidateInstructionCache ();\r
+\r
+ // Invalidate all TLB entries so changes are synced\r
+ ArmInvalidateTlb ();\r
+\r
+ return Status;\r
+}\r
+\r
+UINT64\r
+EfiAttributeToArmAttribute (\r
+ IN UINT64 EfiAttributes\r
+ )\r
+{\r
+ UINT64 ArmAttributes;\r
+\r
+ switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {\r
+ case EFI_MEMORY_UC:\r
+ // Map to strongly ordered\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WC:\r
+ // Map to normal non-cachable\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WT:\r
+ // Write through with no-allocate\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
+ break;\r
+\r
+ case EFI_MEMORY_WB:\r
+ // Write back (with allocate)\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
+ break;\r
+\r
+ case EFI_MEMORY_WP:\r
+ case EFI_MEMORY_XP:\r
+ case EFI_MEMORY_RP:\r
+ case EFI_MEMORY_UCE:\r
+ default:\r
+ // Cannot be implemented UEFI definition unclear for ARM\r
+ // Cause a page fault if these ranges are accessed.\r
+ ArmAttributes = TT_DESCRIPTOR_SECTION_TYPE_FAULT;\r
+ DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): Unsupported attribute %x will page fault on access\n", EfiAttributes));\r
+ break;\r
+ }\r
+\r
+ // Determine protection attributes\r
+ if (EfiAttributes & EFI_MEMORY_WP) {\r
+ ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RO_RO;\r
+ } else {\r
+ ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RW_RW;\r
+ }\r
+\r
+ // Determine eXecute Never attribute\r
+ if (EfiAttributes & EFI_MEMORY_XP) {\r
+ ArmAttributes |= TT_DESCRIPTOR_SECTION_XN_MASK;\r
+ }\r
+\r
+ return ArmAttributes;\r
+}\r
+\r
+EFI_STATUS\r
+GetMemoryRegionPage (\r
+ IN UINT32 *PageTable,\r
+ IN OUT UINTN *BaseAddress,\r
+ OUT UINTN *RegionLength,\r
+ OUT UINTN *RegionAttributes\r
+ )\r
+{\r
+ UINT32 PageAttributes;\r
+ UINT32 TableIndex;\r
+ UINT32 PageDescriptor;\r
+\r
+ // Convert the section attributes into page attributes\r
+ PageAttributes = ConvertSectionAttributesToPageAttributes (*RegionAttributes, 0);\r
+\r
+ // Calculate index into first level translation table for start of modification\r
+ TableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
+ ASSERT (TableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
+\r
+ // Go through the page table to find the end of the section\r
+ for (; TableIndex < TRANSLATION_TABLE_PAGE_COUNT; TableIndex++) {\r
+ // Get the section at the given index\r
+ PageDescriptor = PageTable[TableIndex];\r
+\r
+ if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_FAULT) {\r
+ // Case: End of the boundary of the region\r
+ return EFI_SUCCESS;\r
+ } else if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_PAGE) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {\r
+ if ((PageDescriptor & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK) == PageAttributes) {\r
+ *RegionLength = *RegionLength + TT_DESCRIPTOR_PAGE_SIZE;\r
+ } else {\r
+ // Case: End of the boundary of the region\r
+ return EFI_SUCCESS;\r
+ }\r
+ } else {\r
+ // We do not support Large Page yet. We return EFI_SUCCESS that means end of the region.\r
+ ASSERT(0);\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+GetMemoryRegion (\r
+ IN OUT UINTN *BaseAddress,\r
+ OUT UINTN *RegionLength,\r
+ OUT UINTN *RegionAttributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 TableIndex;\r
+ UINT32 PageAttributes;\r
+ UINT32 PageTableIndex;\r
+ UINT32 SectionDescriptor;\r
+ ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
+ UINT32 *PageTable;\r
+\r
+ // Initialize the arguments\r
+ *RegionLength = 0;\r
+\r
+ // Obtain page table base\r
+ FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
+\r
+ // Calculate index into first level translation table for start of modification\r
+ TableIndex = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (*BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
+ ASSERT (TableIndex < TRANSLATION_TABLE_SECTION_COUNT);\r
+\r
+ // Get the section at the given index\r
+ SectionDescriptor = FirstLevelTable[TableIndex];\r
+\r
+ // If 'BaseAddress' belongs to the section then round it to the section boundary\r
+ if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
+ ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION))\r
+ {\r
+ *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;\r
+ *RegionAttributes = SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK;\r
+ } else {\r
+ // Otherwise, we round it to the page boundary\r
+ *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK;\r
+\r
+ // Get the attribute at the page table level (Level 2)\r
+ PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
+\r
+ // Calculate index into first level translation table for start of modification\r
+ PageTableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
+ ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
+\r
+ PageAttributes = PageTable[PageTableIndex] & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK;\r
+ *RegionAttributes = TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY (PageAttributes, 0) |\r
+ TT_DESCRIPTOR_CONVERT_TO_SECTION_AP (PageAttributes);\r
+ }\r
+\r
+ for (;TableIndex < TRANSLATION_TABLE_SECTION_COUNT; TableIndex++) {\r
+ // Get the section at the given index\r
+ SectionDescriptor = FirstLevelTable[TableIndex];\r
+\r
+ // If the entry is a level-2 page table then we scan it to find the end of the region\r
+ if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE (SectionDescriptor)) {\r
+ // Extract the page table location from the descriptor\r
+ PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
+\r
+ // Scan the page table to find the end of the region.\r
+ Status = GetMemoryRegionPage (PageTable, BaseAddress, RegionLength, RegionAttributes);\r
+\r
+ // If we have found the end of the region (Status == EFI_SUCCESS) then we exit the for-loop\r
+ if (Status == EFI_SUCCESS) {\r
+ break;\r
+ }\r
+ } else if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
+ ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION)) {\r
+ if ((SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK) != *RegionAttributes) {\r
+ // If the attributes of the section differ from the one targeted then we exit the loop\r
+ break;\r
+ } else {\r
+ *RegionLength = *RegionLength + TT_DESCRIPTOR_SECTION_SIZE;\r
+ }\r
+ } else {\r
+ // If we are on an invalid section then it means it is the end of our section.\r
+ break;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+++ /dev/null
-#------------------------------------------------------------------------------\r
-#\r
-# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
-#\r
-# This program and the accompanying materials\r
-# are licensed and made available under the terms and conditions of the BSD License\r
-# which accompanies this distribution. The full text of the license may be found at\r
-# http://opensource.org/licenses/bsd-license.php\r
-#\r
-# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-#\r
-#------------------------------------------------------------------------------\r
-\r
-.text\r
-.align 3\r
-\r
-GCC_ASM_EXPORT(ExceptionHandlersStart)\r
-GCC_ASM_EXPORT(ExceptionHandlersEnd)\r
-GCC_ASM_EXPORT(CommonExceptionEntry)\r
-GCC_ASM_EXPORT(AsmCommonExceptionEntry)\r
-GCC_ASM_EXPORT(CommonCExceptionHandler)\r
-\r
-ASM_PFX(ExceptionHandlersStart):\r
-\r
-ASM_PFX(Reset):\r
- b ASM_PFX(ResetEntry)\r
-\r
-ASM_PFX(UndefinedInstruction):\r
- b ASM_PFX(UndefinedInstructionEntry)\r
-\r
-ASM_PFX(SoftwareInterrupt):\r
- b ASM_PFX(SoftwareInterruptEntry)\r
-\r
-ASM_PFX(PrefetchAbort):\r
- b ASM_PFX(PrefetchAbortEntry)\r
-\r
-ASM_PFX(DataAbort):\r
- b ASM_PFX(DataAbortEntry)\r
-\r
-ASM_PFX(ReservedException):\r
- b ASM_PFX(ReservedExceptionEntry)\r
-\r
-ASM_PFX(Irq):\r
- b ASM_PFX(IrqEntry)\r
-\r
-ASM_PFX(Fiq):\r
- b ASM_PFX(FiqEntry)\r
-\r
-ASM_PFX(ResetEntry):\r
- srsdb #0x13! @ Store return state on SVC stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov R0,#0\r
- ldr R1,ASM_PFX(CommonExceptionEntry)\r
- bx R1\r
-\r
-ASM_PFX(UndefinedInstructionEntry):\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov r0,#1\r
- ldr r1,ASM_PFX(CommonExceptionEntry)\r
- bx r1\r
-\r
-ASM_PFX(SoftwareInterruptEntry):\r
- srsdb #0x13! @ Store return state on SVC stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov r0,#2\r
- ldr r1,ASM_PFX(CommonExceptionEntry)\r
- bx r1\r
-\r
-ASM_PFX(PrefetchAbortEntry):\r
- sub LR,LR,#4\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov r0,#3\r
- ldr r1,ASM_PFX(CommonExceptionEntry)\r
- bx r1\r
-\r
-ASM_PFX(DataAbortEntry):\r
- sub LR,LR,#8\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov r0,#4\r
- ldr r1,ASM_PFX(CommonExceptionEntry)\r
- bx r1\r
-\r
-ASM_PFX(ReservedExceptionEntry):\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov r0,#5\r
- ldr r1,ASM_PFX(CommonExceptionEntry)\r
- bx r1\r
-\r
-ASM_PFX(IrqEntry):\r
- sub LR,LR,#4\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov r0,#6\r
- ldr r1,ASM_PFX(CommonExceptionEntry)\r
- bx r1\r
-\r
-ASM_PFX(FiqEntry):\r
- sub LR,LR,#4\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov r0,#7\r
- ldr r1,ASM_PFX(CommonExceptionEntry)\r
- bx r1\r
-\r
-ASM_PFX(CommonExceptionEntry):\r
- .byte 0x12\r
- .byte 0x34\r
- .byte 0x56\r
- .byte 0x78\r
-\r
-ASM_PFX(ExceptionHandlersEnd):\r
-\r
-ASM_PFX(AsmCommonExceptionEntry):\r
- mrc p15, 0, R1, c6, c0, 2 @ Read IFAR\r
- str R1, [SP, #0x50] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR\r
-\r
- mrc p15, 0, R1, c5, c0, 1 @ Read IFSR\r
- str R1, [SP, #0x4c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR\r
-\r
- mrc p15, 0, R1, c6, c0, 0 @ Read DFAR\r
- str R1, [SP, #0x48] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR\r
-\r
- mrc p15, 0, R1, c5, c0, 0 @ Read DFSR\r
- str R1, [SP, #0x44] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR\r
-\r
- ldr R1, [SP, #0x5c] @ srsdb saved pre-exception CPSR on the stack\r
- str R1, [SP, #0x40] @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR\r
- and r1, r1, #0x1f @ Check to see if User or System Mode\r
- cmp r1, #0x1f\r
- cmpne r1, #0x10\r
- add R2, SP, #0x38 @ Store it in EFI_SYSTEM_CONTEXT_ARM.LR\r
- ldmneed r2, {lr}^ @ User or System mode, use unbanked register\r
- ldmneed r2, {lr} @ All other modes used banked register\r
-\r
- ldr R1, [SP, #0x58] @ PC is the LR pushed by srsdb\r
- str R1, [SP, #0x3c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC\r
-\r
- sub R1, SP, #0x60 @ We pused 0x60 bytes on the stack\r
- str R1, [SP, #0x34] @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP\r
-\r
- @ R0 is exception type\r
- mov R1,SP @ Prepare System Context pointer as an argument for the exception handler\r
- blx ASM_PFX(CommonCExceptionHandler) @ Call exception handler\r
-\r
- ldr R2,[SP,#0x40] @ EFI_SYSTEM_CONTEXT_ARM.CPSR\r
- str R2,[SP,#0x5c] @ Store it back to srsdb stack slot so it can be restored\r
-\r
- ldr R2,[SP,#0x3c] @ EFI_SYSTEM_CONTEXT_ARM.PC\r
- str R2,[SP,#0x58] @ Store it back to srsdb stack slot so it can be restored\r
-\r
- ldmfd SP!,{R0-R12} @ Restore general purpose registers\r
- @ Exception handler can not change SP or LR as we would blow chunks\r
-\r
- add SP,SP,#0x20 @ Clear out the remaining stack space\r
- ldmfd SP!,{LR} @ restore the link register for this context\r
- rfefd SP! @ return from exception via srsdb stack slot\r
+++ /dev/null
-//------------------------------------------------------------------------------\r
-//\r
-// Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
-//\r
-// This program and the accompanying materials\r
-// are licensed and made available under the terms and conditions of the BSD License\r
-// which accompanies this distribution. The full text of the license may be found at\r
-// http://opensource.org/licenses/bsd-license.php\r
-//\r
-// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-//\r
-//------------------------------------------------------------------------------\r
-\r
- EXPORT ExceptionHandlersStart\r
- EXPORT ExceptionHandlersEnd\r
- EXPORT CommonExceptionEntry\r
- EXPORT AsmCommonExceptionEntry\r
- IMPORT CommonCExceptionHandler\r
-\r
- PRESERVE8\r
- AREA DxeExceptionHandlers, CODE, READONLY\r
-\r
-ExceptionHandlersStart\r
-\r
-Reset\r
- b ResetEntry\r
-\r
-UndefinedInstruction\r
- b UndefinedInstructionEntry\r
-\r
-SoftwareInterrupt\r
- b SoftwareInterruptEntry\r
-\r
-PrefetchAbort\r
- b PrefetchAbortEntry\r
-\r
-DataAbort\r
- b DataAbortEntry\r
-\r
-ReservedException\r
- b ReservedExceptionEntry\r
-\r
-Irq\r
- b IrqEntry\r
-\r
-Fiq\r
- b FiqEntry\r
-\r
-ResetEntry\r
- stmfd SP!,{R0-R1}\r
- mov R0,#0\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-UndefinedInstructionEntry\r
- stmfd SP!,{R0-R1}\r
- mov R0,#1\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-SoftwareInterruptEntry\r
- stmfd SP!,{R0-R1}\r
- mov R0,#2\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-PrefetchAbortEntry\r
- stmfd SP!,{R0-R1}\r
- mov R0,#3\r
- SUB LR,LR,#4\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-DataAbortEntry\r
- stmfd SP!,{R0-R1}\r
- mov R0,#4\r
- SUB LR,LR,#8\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-ReservedExceptionEntry\r
- stmfd SP!,{R0-R1}\r
- mov R0,#5\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-IrqEntry\r
- stmfd SP!,{R0-R1}\r
- mov R0,#6\r
- SUB LR,LR,#4\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-FiqEntry\r
- stmfd SP!,{R0-R1}\r
- mov R0,#7\r
- SUB LR,LR,#4\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-CommonExceptionEntry\r
- dcd 0x12345678\r
-\r
-ExceptionHandlersEnd\r
-\r
-AsmCommonExceptionEntry\r
- mrc p15, 0, r1, c6, c0, 2 ; Read IFAR\r
- stmfd SP!,{R1} ; Store the IFAR\r
-\r
- mrc p15, 0, r1, c5, c0, 1 ; Read IFSR\r
- stmfd SP!,{R1} ; Store the IFSR\r
-\r
- mrc p15, 0, r1, c6, c0, 0 ; Read DFAR\r
- stmfd SP!,{R1} ; Store the DFAR\r
-\r
- mrc p15, 0, r1, c5, c0, 0 ; Read DFSR\r
- stmfd SP!,{R1} ; Store the DFSR\r
-\r
- mrs R1,SPSR ; Read SPSR (which is the pre-exception CPSR)\r
- stmfd SP!,{R1} ; Store the SPSR\r
-\r
- stmfd SP!,{LR} ; Store the link register (which is the pre-exception PC)\r
- stmfd SP,{SP,LR}^ ; Store user/system mode stack pointer and link register\r
- nop ; Required by ARM architecture\r
- SUB SP,SP,#0x08 ; Adjust stack pointer\r
- stmfd SP!,{R2-R12} ; Store general purpose registers\r
-\r
- ldr R3,[SP,#0x50] ; Read saved R1 from the stack (it was saved by the exception entry routine)\r
- ldr R2,[SP,#0x4C] ; Read saved R0 from the stack (it was saved by the exception entry routine)\r
- stmfd SP!,{R2-R3} ; Store general purpose registers R0 and R1\r
-\r
- mov R1,SP ; Prepare System Context pointer as an argument for the exception handler\r
-\r
- sub SP,SP,#4 ; Adjust SP to preserve 8-byte alignment\r
- blx CommonCExceptionHandler ; Call exception handler\r
- add SP,SP,#4 ; Adjust SP back to where we were\r
-\r
- ldr R2,[SP,#0x40] ; Load CPSR from context, in case it has changed\r
- MSR SPSR_cxsf,R2 ; Store it back to the SPSR to be restored when exiting this handler\r
-\r
- ldmfd SP!,{R0-R12} ; Restore general purpose registers\r
- ldm SP,{SP,LR}^ ; Restore user/system mode stack pointer and link register\r
- nop ; Required by ARM architecture\r
- add SP,SP,#0x08 ; Adjust stack pointer\r
- ldmfd SP!,{LR} ; Restore the link register (which is the pre-exception PC)\r
- add SP,SP,#0x1C ; Clear out the remaining stack space\r
- movs PC,LR ; Return from exception\r
-\r
- END\r
-\r
-\r
+++ /dev/null
-/** @file\r
-\r
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
- Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
-\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include "CpuDxe.h"\r
-\r
-//FIXME: Will not compile on non-ARMv7 builds\r
-#include <Chipset/ArmV7.h>\r
-\r
-VOID\r
-ExceptionHandlersStart (\r
- VOID\r
- );\r
-\r
-VOID\r
-ExceptionHandlersEnd (\r
- VOID\r
- );\r
-\r
-VOID\r
-CommonExceptionEntry (\r
- VOID\r
- );\r
-\r
-VOID\r
-AsmCommonExceptionEntry (\r
- VOID\r
- );\r
-\r
-\r
-EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_ARM_EXCEPTION + 1];\r
-EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1];\r
-\r
-\r
-\r
-/**\r
- This function registers and enables the handler specified by InterruptHandler for a processor\r
- interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the\r
- handler for the processor interrupt or exception type specified by InterruptType is uninstalled.\r
- The installed handler is called once for each processor interrupt or exception.\r
-\r
- @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts\r
- are enabled and FALSE if interrupts are disabled.\r
- @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called\r
- when a processor interrupt occurs. If this parameter is NULL, then the handler\r
- will be uninstalled.\r
-\r
- @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
- @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was\r
- previously installed.\r
- @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not\r
- previously installed.\r
- @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-RegisterInterruptHandler (\r
- IN EFI_EXCEPTION_TYPE InterruptType,\r
- IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
- )\r
-{\r
- if (InterruptType > MAX_ARM_EXCEPTION) {\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) {\r
- return EFI_ALREADY_STARTED;\r
- }\r
-\r
- gExceptionHandlers[InterruptType] = InterruptHandler;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-\r
-\r
-VOID\r
-EFIAPI\r
-CommonCExceptionHandler (\r
- IN EFI_EXCEPTION_TYPE ExceptionType,\r
- IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
- )\r
-{\r
- if (ExceptionType <= MAX_ARM_EXCEPTION) {\r
- if (gExceptionHandlers[ExceptionType]) {\r
- gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext);\r
- return;\r
- }\r
- } else {\r
- DEBUG ((EFI_D_ERROR, "Unknown exception type %d from %08x\n", ExceptionType, SystemContext.SystemContextArm->PC));\r
- ASSERT (FALSE);\r
- }\r
-\r
- if (ExceptionType == EXCEPT_ARM_SOFTWARE_INTERRUPT) {\r
- //\r
- // ARM JTAG debuggers some times use this vector, so it is not an error to get one\r
- //\r
- return;\r
- }\r
-\r
- DefaultExceptionHandler (ExceptionType, SystemContext);\r
-}\r
-\r
-\r
-\r
-EFI_STATUS\r
-InitializeExceptions (\r
- IN EFI_CPU_ARCH_PROTOCOL *Cpu\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Offset;\r
- UINTN Length;\r
- UINTN Index;\r
- BOOLEAN IrqEnabled;\r
- BOOLEAN FiqEnabled;\r
- EFI_PHYSICAL_ADDRESS Base;\r
- UINT32 *VectorBase;\r
-\r
- Status = EFI_SUCCESS;\r
- ZeroMem (gExceptionHandlers,sizeof(*gExceptionHandlers));\r
-\r
- //\r
- // Disable interrupts\r
- //\r
- Cpu->GetInterruptState (Cpu, &IrqEnabled);\r
- Cpu->DisableInterrupt (Cpu);\r
-\r
- //\r
- // EFI does not use the FIQ, but a debugger might so we must disable\r
- // as we take over the exception vectors.\r
- //\r
- FiqEnabled = ArmGetFiqState ();\r
- ArmDisableFiq ();\r
-\r
- if (FeaturePcdGet(PcdRelocateVectorTable) == TRUE) {\r
- //\r
- // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.\r
- //\r
- Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;\r
-\r
- // Check if the exception vector is in the low address\r
- if (PcdGet32 (PcdCpuVectorBaseAddress) == 0x0) {\r
- // Set SCTLR.V to 0 to enable VBAR to be used\r
- ArmSetLowVectors ();\r
- } else {\r
- ArmSetHighVectors ();\r
- }\r
-\r
- //\r
- // Reserve space for the exception handlers\r
- //\r
- Base = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdCpuVectorBaseAddress);\r
- VectorBase = (UINT32 *)(UINTN)Base;\r
- Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, EFI_SIZE_TO_PAGES (Length), &Base);\r
- // If the request was for memory that's not in the memory map (which is often the case for 0x00000000\r
- // on embedded systems, for example, we don't want to hang up. So we'll check here for a status of\r
- // EFI_NOT_FOUND, and continue in that case.\r
- if (EFI_ERROR(Status) && (Status != EFI_NOT_FOUND)) {\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- if (FeaturePcdGet(PcdDebuggerExceptionSupport) == TRUE) {\r
- // Save existing vector table, in case debugger is already hooked in\r
- CopyMem ((VOID *)gDebuggerExceptionHandlers, (VOID *)VectorBase, sizeof (gDebuggerExceptionHandlers));\r
- }\r
-\r
- // Copy our assembly code into the page that contains the exception vectors.\r
- CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);\r
-\r
- //\r
- // Patch in the common Assembly exception handler\r
- //\r
- Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;\r
- *(UINTN *) ((UINT8 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress) + Offset) = (UINTN)AsmCommonExceptionEntry;\r
-\r
- //\r
- // Initialize the C entry points for interrupts\r
- //\r
- for (Index = 0; Index <= MAX_ARM_EXCEPTION; Index++) {\r
- if (!FeaturePcdGet(PcdDebuggerExceptionSupport) ||\r
- (gDebuggerExceptionHandlers[Index] == 0) || (gDebuggerExceptionHandlers[Index] == (VOID *)(UINTN)0xEAFFFFFE)) {\r
- // Exception handler contains branch to vector location (jmp $) so no handler\r
- // NOTE: This code assumes vectors are ARM and not Thumb code\r
- Status = RegisterInterruptHandler (Index, NULL);\r
- ASSERT_EFI_ERROR (Status);\r
- } else {\r
- // If the debugger has already hooked put its vector back\r
- VectorBase[Index] = (UINT32)(UINTN)gDebuggerExceptionHandlers[Index];\r
- }\r
- }\r
-\r
- // Flush Caches since we updated executable stuff\r
- InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length);\r
-\r
- //Note: On ARM processor with the Security Extension, the Vector Table can be located anywhere in the memory.\r
- // The Vector Base Address Register defines the location\r
- ArmWriteVBar (PcdGet32(PcdCpuVectorBaseAddress));\r
- } else {\r
- // The Vector table must be 32-byte aligned\r
- if (((UINT32)ExceptionHandlersStart & ARM_VECTOR_TABLE_ALIGNMENT) != 0) {\r
- ASSERT (0);\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector Base Address to point into CpuDxe code.\r
- ArmWriteVBar ((UINT32)ExceptionHandlersStart);\r
- }\r
-\r
- if (FiqEnabled) {\r
- ArmEnableFiq ();\r
- }\r
-\r
- if (IrqEnabled) {\r
- //\r
- // Restore interrupt state\r
- //\r
- Status = Cpu->EnableInterrupt (Cpu);\r
- }\r
-\r
- return Status;\r
-}\r
+++ /dev/null
-#------------------------------------------------------------------------------\r
-#\r
-# Use ARMv6 instruction to operate on a single stack\r
-#\r
-# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
-# Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
-#\r
-# This program and the accompanying materials\r
-# are licensed and made available under the terms and conditions of the BSD License\r
-# which accompanies this distribution. The full text of the license may be found at\r
-# http://opensource.org/licenses/bsd-license.php\r
-#\r
-# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-#\r
-#------------------------------------------------------------------------------\r
-\r
-#include <Library/PcdLib.h>\r
-\r
-/*\r
-\r
-This is the stack constructed by the exception handler (low address to high address)\r
- # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM\r
- Reg Offset\r
- === ======\r
- R0 0x00 # stmfd SP!,{R0-R12}\r
- R1 0x04\r
- R2 0x08\r
- R3 0x0c\r
- R4 0x10\r
- R5 0x14\r
- R6 0x18\r
- R7 0x1c\r
- R8 0x20\r
- R9 0x24\r
- R10 0x28\r
- R11 0x2c\r
- R12 0x30\r
- SP 0x34 # reserved via subtraction 0x20 (32) from SP\r
- LR 0x38\r
- PC 0x3c\r
- CPSR 0x40\r
- DFSR 0x44\r
- DFAR 0x48\r
- IFSR 0x4c\r
- IFAR 0x50\r
-\r
- LR 0x54 # SVC Link register (we need to restore it)\r
-\r
- LR 0x58 # pushed by srsfd\r
- CPSR 0x5c\r
-\r
- */\r
-\r
-\r
-GCC_ASM_EXPORT(ExceptionHandlersStart)\r
-GCC_ASM_EXPORT(ExceptionHandlersEnd)\r
-GCC_ASM_EXPORT(CommonExceptionEntry)\r
-GCC_ASM_EXPORT(AsmCommonExceptionEntry)\r
-GCC_ASM_EXPORT(CommonCExceptionHandler)\r
-\r
-.text\r
-#if !defined(__APPLE__)\r
-.fpu neon @ makes vpush/vpop assemble\r
-#endif\r
-.align 5\r
-\r
-\r
-//\r
-// This code gets copied to the ARM vector table\r
-// ExceptionHandlersStart - ExceptionHandlersEnd gets copied\r
-//\r
-ASM_PFX(ExceptionHandlersStart):\r
-\r
-ASM_PFX(Reset):\r
- b ASM_PFX(ResetEntry)\r
-\r
-ASM_PFX(UndefinedInstruction):\r
- b ASM_PFX(UndefinedInstructionEntry)\r
-\r
-ASM_PFX(SoftwareInterrupt):\r
- b ASM_PFX(SoftwareInterruptEntry)\r
-\r
-ASM_PFX(PrefetchAbort):\r
- b ASM_PFX(PrefetchAbortEntry)\r
-\r
-ASM_PFX(DataAbort):\r
- b ASM_PFX(DataAbortEntry)\r
-\r
-ASM_PFX(ReservedException):\r
- b ASM_PFX(ReservedExceptionEntry)\r
-\r
-ASM_PFX(Irq):\r
- b ASM_PFX(IrqEntry)\r
-\r
-ASM_PFX(Fiq):\r
- b ASM_PFX(FiqEntry)\r
-\r
-ASM_PFX(ResetEntry):\r
- srsdb #0x13! @ Store return state on SVC stack\r
- @ We are already in SVC mode\r
-\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov R0,#0 @ ExceptionType\r
- ldr R1,ASM_PFX(CommonExceptionEntry)\r
- bx R1\r
-\r
-ASM_PFX(UndefinedInstructionEntry):\r
- sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov R0,#1 @ ExceptionType\r
- ldr R1,ASM_PFX(CommonExceptionEntry)\r
- bx R1\r
-\r
-ASM_PFX(SoftwareInterruptEntry):\r
- srsdb #0x13! @ Store return state on SVC stack\r
- @ We are already in SVC mode\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov R0,#2 @ ExceptionType\r
- ldr R1,ASM_PFX(CommonExceptionEntry)\r
- bx R1\r
-\r
-ASM_PFX(PrefetchAbortEntry):\r
- sub LR,LR,#4\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov R0,#3 @ ExceptionType\r
- ldr R1,ASM_PFX(CommonExceptionEntry)\r
- bx R1\r
-\r
-ASM_PFX(DataAbortEntry):\r
- sub LR,LR,#8\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov R0,#4\r
- ldr R1,ASM_PFX(CommonExceptionEntry)\r
- bx R1\r
-\r
-ASM_PFX(ReservedExceptionEntry):\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov R0,#5\r
- ldr R1,ASM_PFX(CommonExceptionEntry)\r
- bx R1\r
-\r
-ASM_PFX(IrqEntry):\r
- sub LR,LR,#4\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
-\r
- mov R0,#6 @ ExceptionType\r
- ldr R1,ASM_PFX(CommonExceptionEntry)\r
- bx R1\r
-\r
-ASM_PFX(FiqEntry):\r
- sub LR,LR,#4\r
- srsdb #0x13! @ Store return state on SVC stack\r
- cps #0x13 @ Switch to SVC for common stack\r
- stmfd SP!,{LR} @ Store the link register for the current mode\r
- sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} @ Store the register state\r
- @ Since we have already switch to SVC R8_fiq - R12_fiq\r
- @ never get used or saved\r
- mov R0,#7 @ ExceptionType\r
- ldr R1,ASM_PFX(CommonExceptionEntry)\r
- bx R1\r
-\r
-//\r
-// This gets patched by the C code that patches in the vector table\r
-//\r
-ASM_PFX(CommonExceptionEntry):\r
- .word ASM_PFX(AsmCommonExceptionEntry)\r
-\r
-ASM_PFX(ExceptionHandlersEnd):\r
-\r
-//\r
-// This code runs from CpuDxe driver loaded address. It is patched into\r
-// CommonExceptionEntry.\r
-//\r
-ASM_PFX(AsmCommonExceptionEntry):\r
- mrc p15, 0, R1, c6, c0, 2 @ Read IFAR\r
- str R1, [SP, #0x50] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR\r
-\r
- mrc p15, 0, R1, c5, c0, 1 @ Read IFSR\r
- str R1, [SP, #0x4c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR\r
-\r
- mrc p15, 0, R1, c6, c0, 0 @ Read DFAR\r
- str R1, [SP, #0x48] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR\r
-\r
- mrc p15, 0, R1, c5, c0, 0 @ Read DFSR\r
- str R1, [SP, #0x44] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR\r
-\r
- ldr R1, [SP, #0x5c] @ srsdb saved pre-exception CPSR on the stack\r
- str R1, [SP, #0x40] @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR\r
-\r
- add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
- and R3, R1, #0x1f @ Check CPSR to see if User or System Mode\r
- cmp R3, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f))\r
- cmpne R3, #0x10 @\r
- stmeqed R2, {lr}^ @ save unbanked lr\r
- @ else\r
- stmneed R2, {lr} @ save SVC lr\r
-\r
-\r
- ldr R5, [SP, #0x58] @ PC is the LR pushed by srsfd\r
- @ Check to see if we have to adjust for Thumb entry\r
- sub r4, r0, #1 @ if (ExceptionType == 1 || ExceptionType == 2)) {\r
- cmp r4, #1 @ // UND & SVC have differnt LR adjust for Thumb\r
- bhi NoAdjustNeeded\r
-\r
- tst r1, #0x20 @ if ((CPSR & T)) == T) { // Thumb Mode on entry\r
- addne R5, R5, #2 @ PC += 2;\r
- strne R5,[SP,#0x58] @ Update LR value pushed by srsfd\r
-\r
-NoAdjustNeeded:\r
-\r
- str R5, [SP, #0x3c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC\r
-\r
- add R1, SP, #0x60 @ We pushed 0x60 bytes on the stack\r
- str R1, [SP, #0x34] @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP\r
-\r
- @ R0 is ExceptionType\r
- mov R1,SP @ R1 is SystemContext\r
-\r
-#if (FixedPcdGet32(PcdVFPEnabled))\r
- vpush {d0-d15} @ save vstm registers in case they are used in optimizations\r
-#endif\r
-\r
- mov R4, SP @ Save current SP\r
- tst R4, #4\r
- subne SP, SP, #4 @ Adjust SP if not 8-byte aligned\r
-\r
-/*\r
-VOID\r
-EFIAPI\r
-CommonCExceptionHandler (\r
- IN EFI_EXCEPTION_TYPE ExceptionType, R0\r
- IN OUT EFI_SYSTEM_CONTEXT SystemContext R1\r
- )\r
-\r
-*/\r
- blx ASM_PFX(CommonCExceptionHandler) @ Call exception handler\r
-\r
- mov SP, R4 @ Restore SP\r
-\r
-#if (FixedPcdGet32(PcdVFPEnabled))\r
- vpop {d0-d15}\r
-#endif\r
-\r
- ldr R1, [SP, #0x4c] @ Restore EFI_SYSTEM_CONTEXT_ARM.IFSR\r
- mcr p15, 0, R1, c5, c0, 1 @ Write IFSR\r
-\r
- ldr R1, [SP, #0x44] @ Restore EFI_SYSTEM_CONTEXT_ARM.DFSR\r
- mcr p15, 0, R1, c5, c0, 0 @ Write DFSR\r
-\r
- ldr R1,[SP,#0x3c] @ EFI_SYSTEM_CONTEXT_ARM.PC\r
- str R1,[SP,#0x58] @ Store it back to srsfd stack slot so it can be restored\r
-\r
- ldr R1,[SP,#0x40] @ EFI_SYSTEM_CONTEXT_ARM.CPSR\r
- str R1,[SP,#0x5c] @ Store it back to srsfd stack slot so it can be restored\r
-\r
- add R3, SP, #0x54 @ Make R3 point to SVC LR saved on entry\r
- add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
- and R1, R1, #0x1f @ Check to see if User or System Mode\r
- cmp R1, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f))\r
- cmpne R1, #0x10 @\r
- ldmeqed R2, {lr}^ @ restore unbanked lr\r
- @ else\r
- ldmneed R3, {lr} @ restore SVC lr, via ldmfd SP!, {LR}\r
-\r
- ldmfd SP!,{R0-R12} @ Restore general purpose registers\r
- @ Exception handler can not change SP\r
-\r
- add SP,SP,#0x20 @ Clear out the remaining stack space\r
- ldmfd SP!,{LR} @ restore the link register for this context\r
- rfefd SP! @ return from exception via srsfd stack slot\r
-\r
+++ /dev/null
-//------------------------------------------------------------------------------\r
-//\r
-// Use ARMv6 instruction to operate on a single stack\r
-//\r
-// Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>\r
-// Copyright (c) 2014, ARM Limited. All rights reserved.<BR>\r
-//\r
-// This program and the accompanying materials\r
-// are licensed and made available under the terms and conditions of the BSD License\r
-// which accompanies this distribution. The full text of the license may be found at\r
-// http://opensource.org/licenses/bsd-license.php\r
-//\r
-// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-//\r
-//------------------------------------------------------------------------------\r
-\r
-#include <Library/PcdLib.h>\r
-\r
-/*\r
-\r
-This is the stack constructed by the exception handler (low address to high address)\r
- # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM\r
- Reg Offset\r
- === ======\r
- R0 0x00 # stmfd SP!,{R0-R12}\r
- R1 0x04\r
- R2 0x08\r
- R3 0x0c\r
- R4 0x10\r
- R5 0x14\r
- R6 0x18\r
- R7 0x1c\r
- R8 0x20\r
- R9 0x24\r
- R10 0x28\r
- R11 0x2c\r
- R12 0x30\r
- SP 0x34 # reserved via subtraction 0x20 (32) from SP\r
- LR 0x38\r
- PC 0x3c\r
- CPSR 0x40\r
- DFSR 0x44\r
- DFAR 0x48\r
- IFSR 0x4c\r
- IFAR 0x50\r
-\r
- LR 0x54 # SVC Link register (we need to restore it)\r
-\r
- LR 0x58 # pushed by srsfd\r
- CPSR 0x5c\r
-\r
- */\r
-\r
-\r
- EXPORT ExceptionHandlersStart\r
- EXPORT ExceptionHandlersEnd\r
- EXPORT CommonExceptionEntry\r
- EXPORT AsmCommonExceptionEntry\r
- IMPORT CommonCExceptionHandler\r
-\r
- PRESERVE8\r
- AREA DxeExceptionHandlers, CODE, READONLY, CODEALIGN, ALIGN=5\r
-\r
-//\r
-// This code gets copied to the ARM vector table\r
-// ExceptionHandlersStart - ExceptionHandlersEnd gets copied\r
-//\r
-ExceptionHandlersStart\r
-\r
-Reset\r
- b ResetEntry\r
-\r
-UndefinedInstruction\r
- b UndefinedInstructionEntry\r
-\r
-SoftwareInterrupt\r
- b SoftwareInterruptEntry\r
-\r
-PrefetchAbort\r
- b PrefetchAbortEntry\r
-\r
-DataAbort\r
- b DataAbortEntry\r
-\r
-ReservedException\r
- b ReservedExceptionEntry\r
-\r
-Irq\r
- b IrqEntry\r
-\r
-Fiq\r
- b FiqEntry\r
-\r
-ResetEntry\r
- srsfd #0x13! ; Store return state on SVC stack\r
- ; We are already in SVC mode\r
- stmfd SP!,{LR} ; Store the link register for the current mode\r
- sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} ; Store the register state\r
-\r
- mov R0,#0 ; ExceptionType\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-UndefinedInstructionEntry\r
- sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry\r
- srsfd #0x13! ; Store return state on SVC stack\r
- cps #0x13 ; Switch to SVC for common stack\r
- stmfd SP!,{LR} ; Store the link register for the current mode\r
- sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} ; Store the register state\r
-\r
- mov R0,#1 ; ExceptionType\r
- ldr R1,CommonExceptionEntry;\r
- bx R1\r
-\r
-SoftwareInterruptEntry\r
- srsfd #0x13! ; Store return state on SVC stack\r
- ; We are already in SVC mode\r
- stmfd SP!,{LR} ; Store the link register for the current mode\r
- sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} ; Store the register state\r
-\r
- mov R0,#2 ; ExceptionType\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-PrefetchAbortEntry\r
- sub LR,LR,#4\r
- srsfd #0x13! ; Store return state on SVC stack\r
- cps #0x13 ; Switch to SVC for common stack\r
- stmfd SP!,{LR} ; Store the link register for the current mode\r
- sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} ; Store the register state\r
-\r
- mov R0,#3 ; ExceptionType\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-DataAbortEntry\r
- sub LR,LR,#8\r
- srsfd #0x13! ; Store return state on SVC stack\r
- cps #0x13 ; Switch to SVC for common stack\r
- stmfd SP!,{LR} ; Store the link register for the current mode\r
- sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} ; Store the register state\r
-\r
- mov R0,#4 ; ExceptionType\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-ReservedExceptionEntry\r
- srsfd #0x13! ; Store return state on SVC stack\r
- cps #0x13 ; Switch to SVC for common stack\r
- stmfd SP!,{LR} ; Store the link register for the current mode\r
- sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} ; Store the register state\r
-\r
- mov R0,#5 ; ExceptionType\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-IrqEntry\r
- sub LR,LR,#4\r
- srsfd #0x13! ; Store return state on SVC stack\r
- cps #0x13 ; Switch to SVC for common stack\r
- stmfd SP!,{LR} ; Store the link register for the current mode\r
- sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} ; Store the register state\r
-\r
- mov R0,#6 ; ExceptionType\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-FiqEntry\r
- sub LR,LR,#4\r
- srsfd #0x13! ; Store return state on SVC stack\r
- cps #0x13 ; Switch to SVC for common stack\r
- stmfd SP!,{LR} ; Store the link register for the current mode\r
- sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR\r
- stmfd SP!,{R0-R12} ; Store the register state\r
- ; Since we have already switch to SVC R8_fiq - R12_fiq\r
- ; never get used or saved\r
- mov R0,#7 ; ExceptionType\r
- ldr R1,CommonExceptionEntry\r
- bx R1\r
-\r
-//\r
-// This gets patched by the C code that patches in the vector table\r
-//\r
-CommonExceptionEntry\r
- dcd AsmCommonExceptionEntry\r
-\r
-ExceptionHandlersEnd\r
-\r
-//\r
-// This code runs from CpuDxe driver loaded address. It is patched into\r
-// CommonExceptionEntry.\r
-//\r
-AsmCommonExceptionEntry\r
- mrc p15, 0, R1, c6, c0, 2 ; Read IFAR\r
- str R1, [SP, #0x50] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR\r
-\r
- mrc p15, 0, R1, c5, c0, 1 ; Read IFSR\r
- str R1, [SP, #0x4c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR\r
-\r
- mrc p15, 0, R1, c6, c0, 0 ; Read DFAR\r
- str R1, [SP, #0x48] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR\r
-\r
- mrc p15, 0, R1, c5, c0, 0 ; Read DFSR\r
- str R1, [SP, #0x44] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR\r
-\r
- ldr R1, [SP, #0x5c] ; srsfd saved pre-exception CPSR on the stack\r
- str R1, [SP, #0x40] ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR\r
-\r
- add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
- and R3, R1, #0x1f ; Check CPSR to see if User or System Mode\r
- cmp R3, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f))\r
- cmpne R3, #0x10 ;\r
- stmeqed R2, {lr}^ ; save unbanked lr\r
- ; else\r
- stmneed R2, {lr} ; save SVC lr\r
-\r
-\r
- ldr R5, [SP, #0x58] ; PC is the LR pushed by srsfd\r
- ; Check to see if we have to adjust for Thumb entry\r
- sub r4, r0, #1 ; if (ExceptionType == 1 || ExceptionType == 2)) {\r
- cmp r4, #1 ; // UND & SVC have differnt LR adjust for Thumb\r
- bhi NoAdjustNeeded\r
-\r
- tst r1, #0x20 ; if ((CPSR & T)) == T) { // Thumb Mode on entry\r
- addne R5, R5, #2 ; PC += 2;\r
- strne R5,[SP,#0x58] ; Update LR value pushed by srsfd\r
-\r
-NoAdjustNeeded\r
-\r
- str R5, [SP, #0x3c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC\r
-\r
- add R1, SP, #0x60 ; We pushed 0x60 bytes on the stack\r
- str R1, [SP, #0x34] ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP\r
-\r
- ; R0 is ExceptionType\r
- mov R1,SP ; R1 is SystemContext\r
-\r
-#if (FixedPcdGet32(PcdVFPEnabled))\r
- vpush {d0-d15} ; save vstm registers in case they are used in optimizations\r
-#endif\r
-\r
- mov R4, SP ; Save current SP\r
- tst R4, #4\r
- subne SP, SP, #4 ; Adjust SP if not 8-byte aligned\r
-\r
-/*\r
-VOID\r
-EFIAPI\r
-CommonCExceptionHandler (\r
- IN EFI_EXCEPTION_TYPE ExceptionType, R0\r
- IN OUT EFI_SYSTEM_CONTEXT SystemContext R1\r
- )\r
-\r
-*/\r
- blx CommonCExceptionHandler ; Call exception handler\r
-\r
- mov SP, R4 ; Restore SP\r
-\r
-#if (FixedPcdGet32(PcdVFPEnabled))\r
- vpop {d0-d15}\r
-#endif\r
-\r
- ldr R1, [SP, #0x4c] ; Restore EFI_SYSTEM_CONTEXT_ARM.IFSR\r
- mcr p15, 0, R1, c5, c0, 1 ; Write IFSR\r
-\r
- ldr R1, [SP, #0x44] ; Restore EFI_SYSTEM_CONTEXT_ARM.DFSR\r
- mcr p15, 0, R1, c5, c0, 0 ; Write DFSR\r
-\r
- ldr R1,[SP,#0x3c] ; EFI_SYSTEM_CONTEXT_ARM.PC\r
- str R1,[SP,#0x58] ; Store it back to srsfd stack slot so it can be restored\r
-\r
- ldr R1,[SP,#0x40] ; EFI_SYSTEM_CONTEXT_ARM.CPSR\r
- str R1,[SP,#0x5c] ; Store it back to srsfd stack slot so it can be restored\r
-\r
- add R3, SP, #0x54 ; Make R3 point to SVC LR saved on entry\r
- add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR\r
- and R1, R1, #0x1f ; Check to see if User or System Mode\r
- cmp R1, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f))\r
- cmpne R1, #0x10 ;\r
- ldmeqed R2, {lr}^ ; restore unbanked lr\r
- ; else\r
- ldmneed R3, {lr} ; restore SVC lr, via ldmfd SP!, {LR}\r
-\r
- ldmfd SP!,{R0-R12} ; Restore general purpose registers\r
- ; Exception handler can not change SP\r
-\r
- add SP,SP,#0x20 ; Clear out the remaining stack space\r
- ldmfd SP!,{LR} ; restore the link register for this context\r
- rfefd SP! ; return from exception via srsfd stack slot\r
-\r
- END\r
-\r
-\r
+++ /dev/null
-/*++\r
-\r
-Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.<BR>\r
-Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR>\r
-Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>\r
-\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-\r
---*/\r
-\r
-#include <Library/MemoryAllocationLib.h>\r
-#include "CpuDxe.h"\r
-\r
-// First Level Descriptors\r
-typedef UINT32 ARM_FIRST_LEVEL_DESCRIPTOR;\r
-\r
-// Second Level Descriptors\r
-typedef UINT32 ARM_PAGE_TABLE_ENTRY;\r
-\r
-EFI_STATUS\r
-SectionToGcdAttributes (\r
- IN UINT32 SectionAttributes,\r
- OUT UINT64 *GcdAttributes\r
- )\r
-{\r
- *GcdAttributes = 0;\r
-\r
- // determine cacheability attributes\r
- switch(SectionAttributes & TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK) {\r
- case TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED:\r
- *GcdAttributes |= EFI_MEMORY_UC;\r
- break;\r
- case TT_DESCRIPTOR_SECTION_CACHE_POLICY_SHAREABLE_DEVICE:\r
- *GcdAttributes |= EFI_MEMORY_UC;\r
- break;\r
- case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:\r
- *GcdAttributes |= EFI_MEMORY_WT;\r
- break;\r
- case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_NO_ALLOC:\r
- *GcdAttributes |= EFI_MEMORY_WB;\r
- break;\r
- case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE:\r
- *GcdAttributes |= EFI_MEMORY_WC;\r
- break;\r
- case TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC:\r
- *GcdAttributes |= EFI_MEMORY_WB;\r
- break;\r
- case TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_SHAREABLE_DEVICE:\r
- *GcdAttributes |= EFI_MEMORY_UC;\r
- break;\r
- default:\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- // determine protection attributes\r
- switch(SectionAttributes & TT_DESCRIPTOR_SECTION_AP_MASK) {\r
- case TT_DESCRIPTOR_SECTION_AP_NO_NO: // no read, no write\r
- //*GcdAttributes |= EFI_MEMORY_WP | EFI_MEMORY_RP;\r
- break;\r
-\r
- case TT_DESCRIPTOR_SECTION_AP_RW_NO:\r
- case TT_DESCRIPTOR_SECTION_AP_RW_RW:\r
- // normal read/write access, do not add additional attributes\r
- break;\r
-\r
- // read only cases map to write-protect\r
- case TT_DESCRIPTOR_SECTION_AP_RO_NO:\r
- case TT_DESCRIPTOR_SECTION_AP_RO_RO:\r
- *GcdAttributes |= EFI_MEMORY_WP;\r
- break;\r
-\r
- default:\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- // now process eXectue Never attribute\r
- if ((SectionAttributes & TT_DESCRIPTOR_SECTION_XN_MASK) != 0 ) {\r
- *GcdAttributes |= EFI_MEMORY_XP;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-PageToGcdAttributes (\r
- IN UINT32 PageAttributes,\r
- OUT UINT64 *GcdAttributes\r
- )\r
-{\r
- *GcdAttributes = 0;\r
-\r
- // determine cacheability attributes\r
- switch(PageAttributes & TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK) {\r
- case TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED:\r
- *GcdAttributes |= EFI_MEMORY_UC;\r
- break;\r
- case TT_DESCRIPTOR_PAGE_CACHE_POLICY_SHAREABLE_DEVICE:\r
- *GcdAttributes |= EFI_MEMORY_UC;\r
- break;\r
- case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC:\r
- *GcdAttributes |= EFI_MEMORY_WT;\r
- break;\r
- case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_NO_ALLOC:\r
- *GcdAttributes |= EFI_MEMORY_WB;\r
- break;\r
- case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE:\r
- *GcdAttributes |= EFI_MEMORY_WC;\r
- break;\r
- case TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC:\r
- *GcdAttributes |= EFI_MEMORY_WB;\r
- break;\r
- case TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_SHAREABLE_DEVICE:\r
- *GcdAttributes |= EFI_MEMORY_UC;\r
- break;\r
- default:\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- // determine protection attributes\r
- switch(PageAttributes & TT_DESCRIPTOR_PAGE_AP_MASK) {\r
- case TT_DESCRIPTOR_PAGE_AP_NO_NO: // no read, no write\r
- //*GcdAttributes |= EFI_MEMORY_WP | EFI_MEMORY_RP;\r
- break;\r
-\r
- case TT_DESCRIPTOR_PAGE_AP_RW_NO:\r
- case TT_DESCRIPTOR_PAGE_AP_RW_RW:\r
- // normal read/write access, do not add additional attributes\r
- break;\r
-\r
- // read only cases map to write-protect\r
- case TT_DESCRIPTOR_PAGE_AP_RO_NO:\r
- case TT_DESCRIPTOR_PAGE_AP_RO_RO:\r
- *GcdAttributes |= EFI_MEMORY_WP;\r
- break;\r
-\r
- default:\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- // now process eXectue Never attribute\r
- if ((PageAttributes & TT_DESCRIPTOR_PAGE_XN_MASK) != 0 ) {\r
- *GcdAttributes |= EFI_MEMORY_XP;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-SyncCacheConfigPage (\r
- IN UINT32 SectionIndex,\r
- IN UINT32 FirstLevelDescriptor,\r
- IN UINTN NumberOfDescriptors,\r
- IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,\r
- IN OUT EFI_PHYSICAL_ADDRESS *NextRegionBase,\r
- IN OUT UINT64 *NextRegionLength,\r
- IN OUT UINT32 *NextSectionAttributes\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 i;\r
- volatile ARM_PAGE_TABLE_ENTRY *SecondLevelTable;\r
- UINT32 NextPageAttributes = 0;\r
- UINT32 PageAttributes = 0;\r
- UINT32 BaseAddress;\r
- UINT64 GcdAttributes;\r
-\r
- // Get the Base Address from FirstLevelDescriptor;\r
- BaseAddress = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(SectionIndex << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
-\r
- // Convert SectionAttributes into PageAttributes\r
- NextPageAttributes =\r
- TT_DESCRIPTOR_CONVERT_TO_PAGE_CACHE_POLICY(*NextSectionAttributes,0) |\r
- TT_DESCRIPTOR_CONVERT_TO_PAGE_AP(*NextSectionAttributes);\r
-\r
- // obtain page table base\r
- SecondLevelTable = (ARM_PAGE_TABLE_ENTRY *)(FirstLevelDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
-\r
- for (i=0; i < TRANSLATION_TABLE_PAGE_COUNT; i++) {\r
- if ((SecondLevelTable[i] & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {\r
- // extract attributes (cacheability and permissions)\r
- PageAttributes = SecondLevelTable[i] & (TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK | TT_DESCRIPTOR_PAGE_AP_MASK);\r
-\r
- if (NextPageAttributes == 0) {\r
- // start on a new region\r
- *NextRegionLength = 0;\r
- *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
- NextPageAttributes = PageAttributes;\r
- } else if (PageAttributes != NextPageAttributes) {\r
- // Convert Section Attributes into GCD Attributes\r
- Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
- SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);\r
-\r
- // start on a new region\r
- *NextRegionLength = 0;\r
- *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
- NextPageAttributes = PageAttributes;\r
- }\r
- } else if (NextPageAttributes != 0) {\r
- // Convert Page Attributes into GCD Attributes\r
- Status = PageToGcdAttributes (NextPageAttributes, &GcdAttributes);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
- SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, *NextRegionBase, *NextRegionLength, GcdAttributes);\r
-\r
- *NextRegionLength = 0;\r
- *NextRegionBase = BaseAddress | (i << TT_DESCRIPTOR_PAGE_BASE_SHIFT);\r
- NextPageAttributes = 0;\r
- }\r
- *NextRegionLength += TT_DESCRIPTOR_PAGE_SIZE;\r
- }\r
-\r
- // Convert back PageAttributes into SectionAttributes\r
- *NextSectionAttributes =\r
- TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY(NextPageAttributes,0) |\r
- TT_DESCRIPTOR_CONVERT_TO_SECTION_AP(NextPageAttributes);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-SyncCacheConfig (\r
- IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 i;\r
- EFI_PHYSICAL_ADDRESS NextRegionBase;\r
- UINT64 NextRegionLength;\r
- UINT32 NextSectionAttributes = 0;\r
- UINT32 SectionAttributes = 0;\r
- UINT64 GcdAttributes;\r
- volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
- UINTN NumberOfDescriptors;\r
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
-\r
-\r
- DEBUG ((EFI_D_PAGE, "SyncCacheConfig()\n"));\r
-\r
- // This code assumes MMU is enabled and filed with section translations\r
- ASSERT (ArmMmuEnabled ());\r
-\r
- //\r
- // Get the memory space map from GCD\r
- //\r
- MemorySpaceMap = NULL;\r
- Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
-\r
- // The GCD implementation maintains its own copy of the state of memory space attributes. GCD needs\r
- // to know what the initial memory space attributes are. The CPU Arch. Protocol does not provide a\r
- // GetMemoryAttributes function for GCD to get this so we must resort to calling GCD (as if we were\r
- // a client) to update its copy of the attributes. This is bad architecture and should be replaced\r
- // with a way for GCD to query the CPU Arch. driver of the existing memory space attributes instead.\r
-\r
- // obtain page table base\r
- FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)(ArmGetTTBR0BaseAddress ());\r
-\r
- // Get the first region\r
- NextSectionAttributes = FirstLevelTable[0] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);\r
-\r
- // iterate through each 1MB descriptor\r
- NextRegionBase = NextRegionLength = 0;\r
- for (i=0; i < TRANSLATION_TABLE_SECTION_COUNT; i++) {\r
- if ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) {\r
- // extract attributes (cacheability and permissions)\r
- SectionAttributes = FirstLevelTable[i] & (TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK | TT_DESCRIPTOR_SECTION_AP_MASK);\r
-\r
- if (NextSectionAttributes == 0) {\r
- // start on a new region\r
- NextRegionLength = 0;\r
- NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
- NextSectionAttributes = SectionAttributes;\r
- } else if (SectionAttributes != NextSectionAttributes) {\r
- // Convert Section Attributes into GCD Attributes\r
- Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
- SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
-\r
- // start on a new region\r
- NextRegionLength = 0;\r
- NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
- NextSectionAttributes = SectionAttributes;\r
- }\r
- NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;\r
- } else if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(FirstLevelTable[i])) {\r
- Status = SyncCacheConfigPage (\r
- i,FirstLevelTable[i],\r
- NumberOfDescriptors, MemorySpaceMap,\r
- &NextRegionBase,&NextRegionLength,&NextSectionAttributes);\r
- ASSERT_EFI_ERROR (Status);\r
- } else {\r
- // We do not support yet 16MB sections\r
- ASSERT ((FirstLevelTable[i] & TT_DESCRIPTOR_SECTION_TYPE_MASK) != TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION);\r
-\r
- // start on a new region\r
- if (NextSectionAttributes != 0) {\r
- // Convert Section Attributes into GCD Attributes\r
- Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
- SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
-\r
- NextRegionLength = 0;\r
- NextRegionBase = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(i << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
- NextSectionAttributes = 0;\r
- }\r
- NextRegionLength += TT_DESCRIPTOR_SECTION_SIZE;\r
- }\r
- } // section entry loop\r
-\r
- if (NextSectionAttributes != 0) {\r
- // Convert Section Attributes into GCD Attributes\r
- Status = SectionToGcdAttributes (NextSectionAttributes, &GcdAttributes);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- // update GCD with these changes (this will recurse into our own CpuSetMemoryAttributes below which is OK)\r
- SetGcdMemorySpaceAttributes (MemorySpaceMap, NumberOfDescriptors, NextRegionBase, NextRegionLength, GcdAttributes);\r
- }\r
-\r
- FreePool (MemorySpaceMap);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-\r
-EFI_STATUS\r
-UpdatePageEntries (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length,\r
- IN UINT64 Attributes,\r
- IN EFI_PHYSICAL_ADDRESS VirtualMask\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 EntryValue;\r
- UINT32 EntryMask;\r
- UINT32 FirstLevelIdx;\r
- UINT32 Offset;\r
- UINT32 NumPageEntries;\r
- UINT32 Descriptor;\r
- UINT32 p;\r
- UINT32 PageTableIndex;\r
- UINT32 PageTableEntry;\r
- UINT32 CurrentPageTableEntry;\r
- VOID *Mva;\r
-\r
- volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
- volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
-\r
- Status = EFI_SUCCESS;\r
-\r
- // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
- // EntryValue: values at bit positions specified by EntryMask\r
- EntryMask = TT_DESCRIPTOR_PAGE_TYPE_MASK;\r
- EntryValue = TT_DESCRIPTOR_PAGE_TYPE_PAGE;\r
- // Although the PI spec is unclear on this the GCD guarantees that only\r
- // one Attribute bit is set at a time, so we can safely use a switch statement\r
- switch (Attributes) {\r
- case EFI_MEMORY_UC:\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
- // map to strongly ordered\r
- EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
- break;\r
-\r
- case EFI_MEMORY_WC:\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
- // map to normal non-cachable\r
- EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
- break;\r
-\r
- case EFI_MEMORY_WT:\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
- // write through with no-allocate\r
- EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
- break;\r
-\r
- case EFI_MEMORY_WB:\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_MASK;\r
- // write back (with allocate)\r
- EntryValue |= TT_DESCRIPTOR_PAGE_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
- break;\r
-\r
- case EFI_MEMORY_WP:\r
- case EFI_MEMORY_XP:\r
- case EFI_MEMORY_UCE:\r
- // cannot be implemented UEFI definition unclear for ARM\r
- // Cause a page fault if these ranges are accessed.\r
- EntryValue = TT_DESCRIPTOR_PAGE_TYPE_FAULT;\r
- DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting page %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));\r
- break;\r
-\r
- default:\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- // Obtain page table base\r
- FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
-\r
- // Calculate number of 4KB page table entries to change\r
- NumPageEntries = Length / TT_DESCRIPTOR_PAGE_SIZE;\r
-\r
- // Iterate for the number of 4KB pages to change\r
- Offset = 0;\r
- for(p = 0; p < NumPageEntries; p++) {\r
- // Calculate index into first level translation table for page table value\r
-\r
- FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress + Offset) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
- ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
-\r
- // Read the descriptor from the first level page table\r
- Descriptor = FirstLevelTable[FirstLevelIdx];\r
-\r
- // Does this descriptor need to be converted from section entry to 4K pages?\r
- if (!TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(Descriptor)) {\r
- Status = ConvertSectionToPages (FirstLevelIdx << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
- if (EFI_ERROR(Status)) {\r
- // Exit for loop\r
- break;\r
- }\r
-\r
- // Re-read descriptor\r
- Descriptor = FirstLevelTable[FirstLevelIdx];\r
- }\r
-\r
- // Obtain page table base address\r
- PageTable = (ARM_PAGE_TABLE_ENTRY *)TT_DESCRIPTOR_PAGE_BASE_ADDRESS(Descriptor);\r
-\r
- // Calculate index into the page table\r
- PageTableIndex = ((BaseAddress + Offset) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
- ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
-\r
- // Get the entry\r
- CurrentPageTableEntry = PageTable[PageTableIndex];\r
-\r
- // Mask off appropriate fields\r
- PageTableEntry = CurrentPageTableEntry & ~EntryMask;\r
-\r
- // Mask in new attributes and/or permissions\r
- PageTableEntry |= EntryValue;\r
-\r
- if (VirtualMask != 0) {\r
- // Make this virtual address point at a physical page\r
- PageTableEntry &= ~VirtualMask;\r
- }\r
-\r
- if (CurrentPageTableEntry != PageTableEntry) {\r
- Mva = (VOID *)(UINTN)((((UINTN)FirstLevelIdx) << TT_DESCRIPTOR_SECTION_BASE_SHIFT) + (PageTableIndex << TT_DESCRIPTOR_PAGE_BASE_SHIFT));\r
- if ((CurrentPageTableEntry & TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) == TT_DESCRIPTOR_PAGE_CACHEABLE_MASK) {\r
- // The current section mapping is cacheable so Clean/Invalidate the MVA of the page\r
- // Note assumes switch(Attributes), not ARMv7 possibilities\r
- WriteBackInvalidateDataCacheRange (Mva, TT_DESCRIPTOR_PAGE_SIZE);\r
- }\r
-\r
- // Only need to update if we are changing the entry\r
- PageTable[PageTableIndex] = PageTableEntry;\r
- ArmUpdateTranslationTableEntry ((VOID *)&PageTable[PageTableIndex], Mva);\r
- }\r
-\r
- Status = EFI_SUCCESS;\r
- Offset += TT_DESCRIPTOR_PAGE_SIZE;\r
-\r
- } // End first level translation table loop\r
-\r
- return Status;\r
-}\r
-\r
-\r
-\r
-EFI_STATUS\r
-UpdateSectionEntries (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length,\r
- IN UINT64 Attributes,\r
- IN EFI_PHYSICAL_ADDRESS VirtualMask\r
- )\r
-{\r
- EFI_STATUS Status = EFI_SUCCESS;\r
- UINT32 EntryMask;\r
- UINT32 EntryValue;\r
- UINT32 FirstLevelIdx;\r
- UINT32 NumSections;\r
- UINT32 i;\r
- UINT32 CurrentDescriptor;\r
- UINT32 Descriptor;\r
- VOID *Mva;\r
- volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
-\r
- // EntryMask: bitmask of values to change (1 = change this value, 0 = leave alone)\r
- // EntryValue: values at bit positions specified by EntryMask\r
-\r
- // Make sure we handle a section range that is unmapped\r
- EntryMask = TT_DESCRIPTOR_SECTION_TYPE_MASK;\r
- EntryValue = TT_DESCRIPTOR_SECTION_TYPE_SECTION;\r
-\r
- // Although the PI spec is unclear on this the GCD guarantees that only\r
- // one Attribute bit is set at a time, so we can safely use a switch statement\r
- switch(Attributes) {\r
- case EFI_MEMORY_UC:\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
- // map to strongly ordered\r
- EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
- break;\r
-\r
- case EFI_MEMORY_WC:\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
- // map to normal non-cachable\r
- EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
- break;\r
-\r
- case EFI_MEMORY_WT:\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
- // write through with no-allocate\r
- EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
- break;\r
-\r
- case EFI_MEMORY_WB:\r
- // modify cacheability attributes\r
- EntryMask |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_MASK;\r
- // write back (with allocate)\r
- EntryValue |= TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
- break;\r
-\r
- case EFI_MEMORY_WP:\r
- case EFI_MEMORY_XP:\r
- case EFI_MEMORY_RP:\r
- case EFI_MEMORY_UCE:\r
- // cannot be implemented UEFI definition unclear for ARM\r
- // Cause a page fault if these ranges are accessed.\r
- EntryValue = TT_DESCRIPTOR_SECTION_TYPE_FAULT;\r
- DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): setting section %lx with unsupported attribute %x will page fault on access\n", BaseAddress, Attributes));\r
- break;\r
-\r
-\r
- default:\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- // obtain page table base\r
- FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
-\r
- // calculate index into first level translation table for start of modification\r
- FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
- ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
-\r
- // calculate number of 1MB first level entries this applies to\r
- NumSections = Length / TT_DESCRIPTOR_SECTION_SIZE;\r
-\r
- // iterate through each descriptor\r
- for(i=0; i<NumSections; i++) {\r
- CurrentDescriptor = FirstLevelTable[FirstLevelIdx + i];\r
-\r
- // has this descriptor already been coverted to pages?\r
- if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE(CurrentDescriptor)) {\r
- // forward this 1MB range to page table function instead\r
- Status = UpdatePageEntries ((FirstLevelIdx + i) << TT_DESCRIPTOR_SECTION_BASE_SHIFT, TT_DESCRIPTOR_SECTION_SIZE, Attributes, VirtualMask);\r
- } else {\r
- // still a section entry\r
-\r
- // mask off appropriate fields\r
- Descriptor = CurrentDescriptor & ~EntryMask;\r
-\r
- // mask in new attributes and/or permissions\r
- Descriptor |= EntryValue;\r
- if (VirtualMask != 0) {\r
- Descriptor &= ~VirtualMask;\r
- }\r
-\r
- if (CurrentDescriptor != Descriptor) {\r
- Mva = (VOID *)(UINTN)(((UINTN)FirstLevelTable) << TT_DESCRIPTOR_SECTION_BASE_SHIFT);\r
- if ((CurrentDescriptor & TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) == TT_DESCRIPTOR_SECTION_CACHEABLE_MASK) {\r
- // The current section mapping is cacheable so Clean/Invalidate the MVA of the section\r
- // Note assumes switch(Attributes), not ARMv7 possabilities\r
- WriteBackInvalidateDataCacheRange (Mva, SIZE_1MB);\r
- }\r
-\r
- // Only need to update if we are changing the descriptor\r
- FirstLevelTable[FirstLevelIdx + i] = Descriptor;\r
- ArmUpdateTranslationTableEntry ((VOID *)&FirstLevelTable[FirstLevelIdx + i], Mva);\r
- }\r
-\r
- Status = EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-ConvertSectionToPages (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS PageTableAddr;\r
- UINT32 FirstLevelIdx;\r
- UINT32 SectionDescriptor;\r
- UINT32 PageTableDescriptor;\r
- UINT32 PageDescriptor;\r
- UINT32 Index;\r
-\r
- volatile ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
- volatile ARM_PAGE_TABLE_ENTRY *PageTable;\r
-\r
- DEBUG ((EFI_D_PAGE, "Converting section at 0x%x to pages\n", (UINTN)BaseAddress));\r
-\r
- // Obtain page table base\r
- FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
-\r
- // Calculate index into first level translation table for start of modification\r
- FirstLevelIdx = TT_DESCRIPTOR_SECTION_BASE_ADDRESS(BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
- ASSERT (FirstLevelIdx < TRANSLATION_TABLE_SECTION_COUNT);\r
-\r
- // Get section attributes and convert to page attributes\r
- SectionDescriptor = FirstLevelTable[FirstLevelIdx];\r
- PageDescriptor = TT_DESCRIPTOR_PAGE_TYPE_PAGE | ConvertSectionAttributesToPageAttributes (SectionDescriptor, FALSE);\r
-\r
- // Allocate a page table for the 4KB entries (we use up a full page even though we only need 1KB)\r
- Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, 1, &PageTableAddr);\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
-\r
- PageTable = (volatile ARM_PAGE_TABLE_ENTRY *)(UINTN)PageTableAddr;\r
-\r
- // Write the page table entries out\r
- for (Index = 0; Index < TRANSLATION_TABLE_PAGE_COUNT; Index++) {\r
- PageTable[Index] = TT_DESCRIPTOR_PAGE_BASE_ADDRESS(BaseAddress + (Index << 12)) | PageDescriptor;\r
- }\r
-\r
- // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
- WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)PageTableAddr, TT_DESCRIPTOR_PAGE_SIZE);\r
-\r
- // Formulate page table entry, Domain=0, NS=0\r
- PageTableDescriptor = (((UINTN)PageTableAddr) & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK) | TT_DESCRIPTOR_SECTION_TYPE_PAGE_TABLE;\r
-\r
- // Write the page table entry out, replacing section entry\r
- FirstLevelTable[FirstLevelIdx] = PageTableDescriptor;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-\r
-EFI_STATUS\r
-SetMemoryAttributes (\r
- IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
- IN UINT64 Length,\r
- IN UINT64 Attributes,\r
- IN EFI_PHYSICAL_ADDRESS VirtualMask\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- if(((BaseAddress & 0xFFFFF) == 0) && ((Length & 0xFFFFF) == 0)) {\r
- // Is the base and length a multiple of 1 MB?\r
- DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU section 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
- Status = UpdateSectionEntries (BaseAddress, Length, Attributes, VirtualMask);\r
- } else {\r
- // Base and/or length is not a multiple of 1 MB\r
- DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): MMU page 0x%x length 0x%x to %lx\n", (UINTN)BaseAddress, (UINTN)Length, Attributes));\r
- Status = UpdatePageEntries (BaseAddress, Length, Attributes, VirtualMask);\r
- }\r
-\r
- // Flush d-cache so descriptors make it back to uncached memory for subsequent table walks\r
- // flush and invalidate pages\r
- //TODO: Do we really need to invalidate the caches everytime we change the memory attributes ?\r
- ArmCleanInvalidateDataCache ();\r
-\r
- ArmInvalidateInstructionCache ();\r
-\r
- // Invalidate all TLB entries so changes are synced\r
- ArmInvalidateTlb ();\r
-\r
- return Status;\r
-}\r
-\r
-UINT64\r
-EfiAttributeToArmAttribute (\r
- IN UINT64 EfiAttributes\r
- )\r
-{\r
- UINT64 ArmAttributes;\r
-\r
- switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {\r
- case EFI_MEMORY_UC:\r
- // Map to strongly ordered\r
- ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_STRONGLY_ORDERED; // TEX[2:0] = 0, C=0, B=0\r
- break;\r
-\r
- case EFI_MEMORY_WC:\r
- // Map to normal non-cachable\r
- ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_NON_CACHEABLE; // TEX [2:0]= 001 = 0x2, B=0, C=0\r
- break;\r
-\r
- case EFI_MEMORY_WT:\r
- // Write through with no-allocate\r
- ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_THROUGH_NO_ALLOC; // TEX [2:0] = 0, C=1, B=0\r
- break;\r
-\r
- case EFI_MEMORY_WB:\r
- // Write back (with allocate)\r
- ArmAttributes = TT_DESCRIPTOR_SECTION_CACHE_POLICY_WRITE_BACK_ALLOC; // TEX [2:0] = 001, C=1, B=1\r
- break;\r
-\r
- case EFI_MEMORY_WP:\r
- case EFI_MEMORY_XP:\r
- case EFI_MEMORY_RP:\r
- case EFI_MEMORY_UCE:\r
- default:\r
- // Cannot be implemented UEFI definition unclear for ARM\r
- // Cause a page fault if these ranges are accessed.\r
- ArmAttributes = TT_DESCRIPTOR_SECTION_TYPE_FAULT;\r
- DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(): Unsupported attribute %x will page fault on access\n", EfiAttributes));\r
- break;\r
- }\r
-\r
- // Determine protection attributes\r
- if (EfiAttributes & EFI_MEMORY_WP) {\r
- ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RO_RO;\r
- } else {\r
- ArmAttributes |= TT_DESCRIPTOR_SECTION_AP_RW_RW;\r
- }\r
-\r
- // Determine eXecute Never attribute\r
- if (EfiAttributes & EFI_MEMORY_XP) {\r
- ArmAttributes |= TT_DESCRIPTOR_SECTION_XN_MASK;\r
- }\r
-\r
- return ArmAttributes;\r
-}\r
-\r
-EFI_STATUS\r
-GetMemoryRegionPage (\r
- IN UINT32 *PageTable,\r
- IN OUT UINTN *BaseAddress,\r
- OUT UINTN *RegionLength,\r
- OUT UINTN *RegionAttributes\r
- )\r
-{\r
- UINT32 PageAttributes;\r
- UINT32 TableIndex;\r
- UINT32 PageDescriptor;\r
-\r
- // Convert the section attributes into page attributes\r
- PageAttributes = ConvertSectionAttributesToPageAttributes (*RegionAttributes, 0);\r
-\r
- // Calculate index into first level translation table for start of modification\r
- TableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
- ASSERT (TableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
-\r
- // Go through the page table to find the end of the section\r
- for (; TableIndex < TRANSLATION_TABLE_PAGE_COUNT; TableIndex++) {\r
- // Get the section at the given index\r
- PageDescriptor = PageTable[TableIndex];\r
-\r
- if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_MASK) == TT_DESCRIPTOR_PAGE_TYPE_FAULT) {\r
- // Case: End of the boundary of the region\r
- return EFI_SUCCESS;\r
- } else if ((PageDescriptor & TT_DESCRIPTOR_PAGE_TYPE_PAGE) == TT_DESCRIPTOR_PAGE_TYPE_PAGE) {\r
- if ((PageDescriptor & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK) == PageAttributes) {\r
- *RegionLength = *RegionLength + TT_DESCRIPTOR_PAGE_SIZE;\r
- } else {\r
- // Case: End of the boundary of the region\r
- return EFI_SUCCESS;\r
- }\r
- } else {\r
- // We do not support Large Page yet. We return EFI_SUCCESS that means end of the region.\r
- ASSERT(0);\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-EFI_STATUS\r
-GetMemoryRegion (\r
- IN OUT UINTN *BaseAddress,\r
- OUT UINTN *RegionLength,\r
- OUT UINTN *RegionAttributes\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 TableIndex;\r
- UINT32 PageAttributes;\r
- UINT32 PageTableIndex;\r
- UINT32 SectionDescriptor;\r
- ARM_FIRST_LEVEL_DESCRIPTOR *FirstLevelTable;\r
- UINT32 *PageTable;\r
-\r
- // Initialize the arguments\r
- *RegionLength = 0;\r
-\r
- // Obtain page table base\r
- FirstLevelTable = (ARM_FIRST_LEVEL_DESCRIPTOR *)ArmGetTTBR0BaseAddress ();\r
-\r
- // Calculate index into first level translation table for start of modification\r
- TableIndex = TT_DESCRIPTOR_SECTION_BASE_ADDRESS (*BaseAddress) >> TT_DESCRIPTOR_SECTION_BASE_SHIFT;\r
- ASSERT (TableIndex < TRANSLATION_TABLE_SECTION_COUNT);\r
-\r
- // Get the section at the given index\r
- SectionDescriptor = FirstLevelTable[TableIndex];\r
-\r
- // If 'BaseAddress' belongs to the section then round it to the section boundary\r
- if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
- ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION))\r
- {\r
- *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_SECTION_BASE_ADDRESS_MASK;\r
- *RegionAttributes = SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK;\r
- } else {\r
- // Otherwise, we round it to the page boundary\r
- *BaseAddress = (*BaseAddress) & TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK;\r
-\r
- // Get the attribute at the page table level (Level 2)\r
- PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
-\r
- // Calculate index into first level translation table for start of modification\r
- PageTableIndex = ((*BaseAddress) & TT_DESCRIPTOR_PAGE_INDEX_MASK) >> TT_DESCRIPTOR_PAGE_BASE_SHIFT;\r
- ASSERT (PageTableIndex < TRANSLATION_TABLE_PAGE_COUNT);\r
-\r
- PageAttributes = PageTable[PageTableIndex] & TT_DESCRIPTOR_PAGE_ATTRIBUTE_MASK;\r
- *RegionAttributes = TT_DESCRIPTOR_CONVERT_TO_SECTION_CACHE_POLICY (PageAttributes, 0) |\r
- TT_DESCRIPTOR_CONVERT_TO_SECTION_AP (PageAttributes);\r
- }\r
-\r
- for (;TableIndex < TRANSLATION_TABLE_SECTION_COUNT; TableIndex++) {\r
- // Get the section at the given index\r
- SectionDescriptor = FirstLevelTable[TableIndex];\r
-\r
- // If the entry is a level-2 page table then we scan it to find the end of the region\r
- if (TT_DESCRIPTOR_SECTION_TYPE_IS_PAGE_TABLE (SectionDescriptor)) {\r
- // Extract the page table location from the descriptor\r
- PageTable = (UINT32*)(SectionDescriptor & TT_DESCRIPTOR_SECTION_PAGETABLE_ADDRESS_MASK);\r
-\r
- // Scan the page table to find the end of the region.\r
- Status = GetMemoryRegionPage (PageTable, BaseAddress, RegionLength, RegionAttributes);\r
-\r
- // If we have found the end of the region (Status == EFI_SUCCESS) then we exit the for-loop\r
- if (Status == EFI_SUCCESS) {\r
- break;\r
- }\r
- } else if (((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SECTION) ||\r
- ((SectionDescriptor & TT_DESCRIPTOR_SECTION_TYPE_MASK) == TT_DESCRIPTOR_SECTION_TYPE_SUPERSECTION)) {\r
- if ((SectionDescriptor & TT_DESCRIPTOR_SECTION_ATTRIBUTE_MASK) != *RegionAttributes) {\r
- // If the attributes of the section differ from the one targeted then we exit the loop\r
- break;\r
- } else {\r
- *RegionLength = *RegionLength + TT_DESCRIPTOR_SECTION_SIZE;\r
- }\r
- } else {\r
- // If we are on an invalid section then it means it is the end of our section.\r
- break;\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
CpuMpCore.c\r
CpuMmuCommon.c\r
\r
-#\r
-# Prior to ARMv6 we have multiple stacks, one per mode\r
-#\r
-# ArmV4/ExceptionSupport.asm | RVCT\r
-# ArmV4/ExceptionSupport.S | GCC\r
-\r
-#\r
-# ARMv6 or later uses a single stack via srs/stm instructions\r
-#\r
-\r
[Sources.ARM]\r
- ArmV6/Mmu.c\r
- ArmV6/Exception.c\r
- ArmV6/ExceptionSupport.asm | RVCT\r
- ArmV6/ExceptionSupport.S | GCC\r
+ Arm/Mmu.c\r
+ Arm/Exception.c\r
+ Arm/ExceptionSupport.asm | RVCT\r
+ Arm/ExceptionSupport.S | GCC\r
\r
[Sources.AARCH64]\r
AArch64/Mmu.c\r