From 5811eea0fdb56187597e50b1282e7cfab4965a65 Mon Sep 17 00:00:00 2001 From: "Cohen, Eugene" Date: Mon, 7 Mar 2016 15:16:38 +0000 Subject: [PATCH] ArmPkg: update CpuDxe to use CpuExceptionHandlerLib Use the new ARM/AArch64 implementation of the base CpuExceptionHandlerLib library from CpuDxe to centralize exception handling. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eugene Cohen Reviewed-by: Ard Biesheuvel --- ArmPkg/Drivers/CpuDxe/AArch64/Exception.c | 154 ------- .../Drivers/CpuDxe/AArch64/ExceptionSupport.S | 402 ------------------ ArmPkg/Drivers/CpuDxe/Arm/Exception.c | 234 ---------- ArmPkg/Drivers/CpuDxe/Arm/ExceptionSupport.S | 304 ------------- .../Drivers/CpuDxe/Arm/ExceptionSupport.asm | 301 ------------- ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 10 +- ArmPkg/Drivers/CpuDxe/Exception.c | 95 +++++ 7 files changed, 98 insertions(+), 1402 deletions(-) delete mode 100644 ArmPkg/Drivers/CpuDxe/AArch64/Exception.c delete mode 100644 ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S delete mode 100644 ArmPkg/Drivers/CpuDxe/Arm/Exception.c delete mode 100644 ArmPkg/Drivers/CpuDxe/Arm/ExceptionSupport.S delete mode 100644 ArmPkg/Drivers/CpuDxe/Arm/ExceptionSupport.asm create mode 100644 ArmPkg/Drivers/CpuDxe/Exception.c diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/Exception.c b/ArmPkg/Drivers/CpuDxe/AArch64/Exception.c deleted file mode 100644 index ce1c6ce09a..0000000000 --- a/ArmPkg/Drivers/CpuDxe/AArch64/Exception.c +++ /dev/null @@ -1,154 +0,0 @@ -/** @file - - Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
- Portions Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "CpuDxe.h" - -#include - -VOID -ExceptionHandlersStart ( - VOID - ); - -VOID -ExceptionHandlersEnd ( - VOID - ); - -VOID -CommonExceptionEntry ( - VOID - ); - -VOID -AsmCommonExceptionEntry ( - VOID - ); - - -EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_AARCH64_EXCEPTION + 1]; -EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_AARCH64_EXCEPTION + 1]; - - - -/** - This function registers and enables the handler specified by InterruptHandler for a processor - interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the - handler for the processor interrupt or exception type specified by InterruptType is uninstalled. - The installed handler is called once for each processor interrupt or exception. - - @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts - are enabled and FALSE if interrupts are disabled. - @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called - when a processor interrupt occurs. If this parameter is NULL, then the handler - will be uninstalled. - - @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. - @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was - previously installed. - @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not - previously installed. - @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. - -**/ -EFI_STATUS -RegisterInterruptHandler ( - IN EFI_EXCEPTION_TYPE InterruptType, - IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler - ) -{ - if (InterruptType > MAX_AARCH64_EXCEPTION) { - return EFI_UNSUPPORTED; - } - - if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) { - return EFI_ALREADY_STARTED; - } - - gExceptionHandlers[InterruptType] = InterruptHandler; - - return EFI_SUCCESS; -} - - - -VOID -EFIAPI -CommonCExceptionHandler ( - IN EFI_EXCEPTION_TYPE ExceptionType, - IN OUT EFI_SYSTEM_CONTEXT SystemContext - ) -{ - if (ExceptionType <= MAX_AARCH64_EXCEPTION) { - if (gExceptionHandlers[ExceptionType]) { - gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext); - return; - } - } else { - DEBUG ((EFI_D_ERROR, "Unknown exception type %d from %016lx\n", ExceptionType, SystemContext.SystemContextAArch64->ELR)); - ASSERT (FALSE); - } - - DefaultExceptionHandler (ExceptionType, SystemContext); -} - - - -EFI_STATUS -InitializeExceptions ( - IN EFI_CPU_ARCH_PROTOCOL *Cpu - ) -{ - EFI_STATUS Status; - BOOLEAN IrqEnabled; - BOOLEAN FiqEnabled; - - Status = EFI_SUCCESS; - ZeroMem (gExceptionHandlers,sizeof(*gExceptionHandlers)); - - // - // Disable interrupts - // - Cpu->GetInterruptState (Cpu, &IrqEnabled); - Cpu->DisableInterrupt (Cpu); - - // - // EFI does not use the FIQ, but a debugger might so we must disable - // as we take over the exception vectors. - // - FiqEnabled = ArmGetFiqState (); - ArmDisableFiq (); - - // The AArch64 Vector table must be 2k-byte aligned - if this assertion fails ensure 'Align=4K' - // is defined into your FDF for this module. - ASSERT (((UINTN)ExceptionHandlersStart & ARM_VECTOR_TABLE_ALIGNMENT) == 0); - - // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector - // Base Address to point into CpuDxe code. - ArmWriteVBar ((UINTN)ExceptionHandlersStart); - - if (FiqEnabled) { - ArmEnableFiq (); - } - - if (IrqEnabled) { - // - // Restore interrupt state - // - Status = Cpu->EnableInterrupt (Cpu); - } - - return Status; -} diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S b/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S deleted file mode 100644 index edf9973494..0000000000 --- a/ArmPkg/Drivers/CpuDxe/AArch64/ExceptionSupport.S +++ /dev/null @@ -1,402 +0,0 @@ -// -// Copyright (c) 2011 - 2014 ARM LTD. All rights reserved.
-// Portion of Copyright (c) 2014 NVIDIA Corporation. All rights reserved.
-// -// This program and the accompanying materials -// are licensed and made available under the terms and conditions of the BSD License -// which accompanies this distribution. The full text of the license may be found at -// http://opensource.org/licenses/bsd-license.php -// -// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -// -//------------------------------------------------------------------------------ - -#include -#include -#include - -/* - This is the stack constructed by the exception handler (low address to high address). - X0 to FAR makes up the EFI_SYSTEM_CONTEXT for AArch64. - - UINT64 X0; 0x000 - UINT64 X1; 0x008 - UINT64 X2; 0x010 - UINT64 X3; 0x018 - UINT64 X4; 0x020 - UINT64 X5; 0x028 - UINT64 X6; 0x030 - UINT64 X7; 0x038 - UINT64 X8; 0x040 - UINT64 X9; 0x048 - UINT64 X10; 0x050 - UINT64 X11; 0x058 - UINT64 X12; 0x060 - UINT64 X13; 0x068 - UINT64 X14; 0x070 - UINT64 X15; 0x078 - UINT64 X16; 0x080 - UINT64 X17; 0x088 - UINT64 X18; 0x090 - UINT64 X19; 0x098 - UINT64 X20; 0x0a0 - UINT64 X21; 0x0a8 - UINT64 X22; 0x0b0 - UINT64 X23; 0x0b8 - UINT64 X24; 0x0c0 - UINT64 X25; 0x0c8 - UINT64 X26; 0x0d0 - UINT64 X27; 0x0d8 - UINT64 X28; 0x0e0 - UINT64 FP; 0x0e8 // x29 - Frame Pointer - UINT64 LR; 0x0f0 // x30 - Link Register - UINT64 SP; 0x0f8 // x31 - Stack Pointer - - // FP/SIMD Registers. 128bit if used as Q-regs. - UINT64 V0[2]; 0x100 - UINT64 V1[2]; 0x110 - UINT64 V2[2]; 0x120 - UINT64 V3[2]; 0x130 - UINT64 V4[2]; 0x140 - UINT64 V5[2]; 0x150 - UINT64 V6[2]; 0x160 - UINT64 V7[2]; 0x170 - UINT64 V8[2]; 0x180 - UINT64 V9[2]; 0x190 - UINT64 V10[2]; 0x1a0 - UINT64 V11[2]; 0x1b0 - UINT64 V12[2]; 0x1c0 - UINT64 V13[2]; 0x1d0 - UINT64 V14[2]; 0x1e0 - UINT64 V15[2]; 0x1f0 - UINT64 V16[2]; 0x200 - UINT64 V17[2]; 0x210 - UINT64 V18[2]; 0x220 - UINT64 V19[2]; 0x230 - UINT64 V20[2]; 0x240 - UINT64 V21[2]; 0x250 - UINT64 V22[2]; 0x260 - UINT64 V23[2]; 0x270 - UINT64 V24[2]; 0x280 - UINT64 V25[2]; 0x290 - UINT64 V26[2]; 0x2a0 - UINT64 V27[2]; 0x2b0 - UINT64 V28[2]; 0x2c0 - UINT64 V29[2]; 0x2d0 - UINT64 V30[2]; 0x2e0 - UINT64 V31[2]; 0x2f0 - - // System Context - UINT64 ELR; 0x300 // Exception Link Register - UINT64 SPSR; 0x308 // Saved Processor Status Register - UINT64 FPSR; 0x310 // Floating Point Status Register - UINT64 ESR; 0x318 // Exception syndrome register - UINT64 FAR; 0x320 // Fault Address Register - UINT64 Padding;0x328 // Required for stack alignment -*/ - -GCC_ASM_EXPORT(ExceptionHandlersEnd) -GCC_ASM_EXPORT(CommonExceptionEntry) -GCC_ASM_EXPORT(AsmCommonExceptionEntry) -GCC_ASM_EXPORT(CommonCExceptionHandler) - -.text - -#define GP_CONTEXT_SIZE (32 * 8) -#define FP_CONTEXT_SIZE (32 * 16) -#define SYS_CONTEXT_SIZE ( 6 * 8) // 5 SYS regs + Alignment requirement (ie: the stack must be aligned on 0x10) - -// Cannot str x31 directly -#define ALL_GP_REGS \ - REG_PAIR (x0, x1, 0x000, GP_CONTEXT_SIZE); \ - REG_PAIR (x2, x3, 0x010, GP_CONTEXT_SIZE); \ - REG_PAIR (x4, x5, 0x020, GP_CONTEXT_SIZE); \ - REG_PAIR (x6, x7, 0x030, GP_CONTEXT_SIZE); \ - REG_PAIR (x8, x9, 0x040, GP_CONTEXT_SIZE); \ - REG_PAIR (x10, x11, 0x050, GP_CONTEXT_SIZE); \ - REG_PAIR (x12, x13, 0x060, GP_CONTEXT_SIZE); \ - REG_PAIR (x14, x15, 0x070, GP_CONTEXT_SIZE); \ - REG_PAIR (x16, x17, 0x080, GP_CONTEXT_SIZE); \ - REG_PAIR (x18, x19, 0x090, GP_CONTEXT_SIZE); \ - REG_PAIR (x20, x21, 0x0a0, GP_CONTEXT_SIZE); \ - REG_PAIR (x22, x23, 0x0b0, GP_CONTEXT_SIZE); \ - REG_PAIR (x24, x25, 0x0c0, GP_CONTEXT_SIZE); \ - REG_PAIR (x26, x27, 0x0d0, GP_CONTEXT_SIZE); \ - REG_PAIR (x28, x29, 0x0e0, GP_CONTEXT_SIZE); \ - REG_ONE (x30, 0x0f0, GP_CONTEXT_SIZE); - -// In order to save the SP we need to put it somewhere else first. -// STR only works with XZR/WZR directly -#define SAVE_SP \ - add x1, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE); \ - REG_ONE (x1, 0x0f8, GP_CONTEXT_SIZE); - -#define ALL_FP_REGS \ - REG_PAIR (q0, q1, 0x000, FP_CONTEXT_SIZE); \ - REG_PAIR (q2, q3, 0x020, FP_CONTEXT_SIZE); \ - REG_PAIR (q4, q5, 0x040, FP_CONTEXT_SIZE); \ - REG_PAIR (q6, q7, 0x060, FP_CONTEXT_SIZE); \ - REG_PAIR (q8, q9, 0x080, FP_CONTEXT_SIZE); \ - REG_PAIR (q10, q11, 0x0a0, FP_CONTEXT_SIZE); \ - REG_PAIR (q12, q13, 0x0c0, FP_CONTEXT_SIZE); \ - REG_PAIR (q14, q15, 0x0e0, FP_CONTEXT_SIZE); \ - REG_PAIR (q16, q17, 0x100, FP_CONTEXT_SIZE); \ - REG_PAIR (q18, q19, 0x120, FP_CONTEXT_SIZE); \ - REG_PAIR (q20, q21, 0x140, FP_CONTEXT_SIZE); \ - REG_PAIR (q22, q23, 0x160, FP_CONTEXT_SIZE); \ - REG_PAIR (q24, q25, 0x180, FP_CONTEXT_SIZE); \ - REG_PAIR (q26, q27, 0x1a0, FP_CONTEXT_SIZE); \ - REG_PAIR (q28, q29, 0x1c0, FP_CONTEXT_SIZE); \ - REG_PAIR (q30, q31, 0x1e0, FP_CONTEXT_SIZE); - -#define ALL_SYS_REGS \ - REG_PAIR (x1, x2, 0x000, SYS_CONTEXT_SIZE); \ - REG_PAIR (x3, x4, 0x010, SYS_CONTEXT_SIZE); \ - REG_ONE (x5, 0x020, SYS_CONTEXT_SIZE); - -// -// This code gets copied to the ARM vector table -// VectorTableStart - VectorTableEnd gets copied -// -VECTOR_BASE(ExceptionHandlersStart) - -// -// Current EL with SP0 : 0x0 - 0x180 -// -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SYNC) -ASM_PFX(SynchronousExceptionSP0): - b ASM_PFX(SynchronousExceptionEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_IRQ) -ASM_PFX(IrqSP0): - b ASM_PFX(IrqEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_FIQ) -ASM_PFX(FiqSP0): - b ASM_PFX(FiqEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SERR) -ASM_PFX(SErrorSP0): - b ASM_PFX(SErrorEntry) - -// -// Current EL with SPx: 0x200 - 0x380 -// -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SYNC) -ASM_PFX(SynchronousExceptionSPx): - b ASM_PFX(SynchronousExceptionEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_IRQ) -ASM_PFX(IrqSPx): - b ASM_PFX(IrqEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_FIQ) -ASM_PFX(FiqSPx): - b ASM_PFX(FiqEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SERR) -ASM_PFX(SErrorSPx): - b ASM_PFX(SErrorEntry) - -// -// Lower EL using AArch64 : 0x400 - 0x580 -// -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SYNC) -ASM_PFX(SynchronousExceptionA64): - b ASM_PFX(SynchronousExceptionEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_IRQ) -ASM_PFX(IrqA64): - b ASM_PFX(IrqEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_FIQ) -ASM_PFX(FiqA64): - b ASM_PFX(FiqEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SERR) -ASM_PFX(SErrorA64): - b ASM_PFX(SErrorEntry) - -// -// Lower EL using AArch32 : 0x600 - 0x780 -// -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SYNC) -ASM_PFX(SynchronousExceptionA32): - b ASM_PFX(SynchronousExceptionEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_IRQ) -ASM_PFX(IrqA32): - b ASM_PFX(IrqEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_FIQ) -ASM_PFX(FiqA32): - b ASM_PFX(FiqEntry) - -VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SERR) -ASM_PFX(SErrorA32): - b ASM_PFX(SErrorEntry) - -VECTOR_END(ExceptionHandlersStart) - -#undef REG_PAIR -#undef REG_ONE -#define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE) stp REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)] -#define REG_ONE(REG1, OFFSET, CONTEXT_SIZE) stur REG1, [sp, #(OFFSET-CONTEXT_SIZE)] - -ASM_PFX(SynchronousExceptionEntry): - // Move the stackpointer so we can reach our structure with the str instruction. - sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE) - - // Save all the General regs before touching x0 and x1. - // This does not save r31(SP) as it is special. We do that later. - ALL_GP_REGS - - // Record the type of exception that occurred. - mov x0, #EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS - - // Jump to our general handler to deal with all the common parts and process the exception. - ldr x1, ASM_PFX(CommonExceptionEntry) - br x1 - -ASM_PFX(IrqEntry): - sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE) - ALL_GP_REGS - mov x0, #EXCEPT_AARCH64_IRQ - ldr x1, ASM_PFX(CommonExceptionEntry) - br x1 - -ASM_PFX(FiqEntry): - sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE) - ALL_GP_REGS - mov x0, #EXCEPT_AARCH64_FIQ - ldr x1, ASM_PFX(CommonExceptionEntry) - br x1 - -ASM_PFX(SErrorEntry): - sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE) - ALL_GP_REGS - mov x0, #EXCEPT_AARCH64_SERROR - ldr x1, ASM_PFX(CommonExceptionEntry) - br x1 - - -// -// This gets patched by the C code that patches in the vector table -// -.align 3 -ASM_PFX(CommonExceptionEntry): - .8byte ASM_PFX(AsmCommonExceptionEntry) - -ASM_PFX(ExceptionHandlersEnd): - - - -// -// This code runs from CpuDxe driver loaded address. It is patched into -// CommonExceptionEntry. -// -ASM_PFX(AsmCommonExceptionEntry): - /* NOTE: - We have to break up the save code because the immediate value to be used - with the SP is too big to do it all in one step so we need to shuffle the SP - along as we go. (we only have 9bits of immediate to work with) */ - - // Save the current Stack pointer before we start modifying it. - SAVE_SP - - // Preserve the stack pointer we came in with before we modify it - EL1_OR_EL2(x1) -1:mrs x1, elr_el1 // Exception Link Register - mrs x2, spsr_el1 // Saved Processor Status Register 32bit - mrs x3, fpsr // Floating point Status Register 32bit - mrs x4, esr_el1 // EL1 Exception syndrome register 32bit - mrs x5, far_el1 // EL1 Fault Address Register - b 3f - -2:mrs x1, elr_el2 // Exception Link Register - mrs x2, spsr_el2 // Saved Processor Status Register 32bit - mrs x3, fpsr // Floating point Status Register 32bit - mrs x4, esr_el2 // EL2 Exception syndrome register 32bit - mrs x5, far_el2 // EL2 Fault Address Register - - // Adjust SP to save next set -3:add sp, sp, #FP_CONTEXT_SIZE - - // Push FP regs to Stack. - ALL_FP_REGS - - // Adjust SP to save next set - add sp, sp, #SYS_CONTEXT_SIZE - - // Save the SYS regs - ALL_SYS_REGS - - // Point to top of struct after all regs saved - sub sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE) - - // x0 still holds the exception type. - // Set x1 to point to the top of our struct on the Stack - mov x1, sp - -// CommonCExceptionHandler ( -// IN EFI_EXCEPTION_TYPE ExceptionType, R0 -// IN OUT EFI_SYSTEM_CONTEXT SystemContext R1 -// ) - - // Call the handler as defined above - - // For now we spin in the handler if we received an abort of some kind. - // We do not try to recover. - bl ASM_PFX(CommonCExceptionHandler) // Call exception handler - - -// Defines for popping from stack - -#undef REG_PAIR -#undef REG_ONE -#define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE) ldp REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)] -#define REG_ONE(REG1, OFFSET, CONTEXT_SIZE) ldur REG1, [sp, #(OFFSET-CONTEXT_SIZE)] - - // - // Disable interrupt(IRQ and FIQ) before restoring context, - // or else the context will be corrupted by interrupt reentrance. - // Interrupt mask will be restored from spsr by hardware when we call eret - // - msr daifset, #3 - isb - - // Adjust SP to pop system registers - add sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE) - ALL_SYS_REGS - - EL1_OR_EL2(x6) -1:msr elr_el1, x1 // Exception Link Register - msr spsr_el1,x2 // Saved Processor Status Register 32bit - msr fpsr, x3 // Floating point Status Register 32bit - msr esr_el1, x4 // EL1 Exception syndrome register 32bit - msr far_el1, x5 // EL1 Fault Address Register - b 3f -2:msr elr_el2, x1 // Exception Link Register - msr spsr_el2,x2 // Saved Processor Status Register 32bit - msr fpsr, x3 // Floating point Status Register 32bit - msr esr_el2, x4 // EL2 Exception syndrome register 32bit - msr far_el2, x5 // EL2 Fault Address Register - -3:// pop all regs and return from exception. - sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE) - ALL_GP_REGS - - // Adjust SP to pop next set - add sp, sp, #FP_CONTEXT_SIZE - // Pop FP regs to Stack. - ALL_FP_REGS - - // Adjust SP to be where we started from when we came into the handler. - // The handler can not change the SP. - add sp, sp, #SYS_CONTEXT_SIZE - - eret - -#undef REG_PAIR -#undef REG_ONE diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Exception.c b/ArmPkg/Drivers/CpuDxe/Arm/Exception.c deleted file mode 100644 index 4b05199db3..0000000000 --- a/ArmPkg/Drivers/CpuDxe/Arm/Exception.c +++ /dev/null @@ -1,234 +0,0 @@ -/** @file - - Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
- Copyright (c) 2014, ARM Limited. All rights reserved.
- - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "CpuDxe.h" - -//FIXME: Will not compile on non-ARMv7 builds -#include - -VOID -ExceptionHandlersStart ( - VOID - ); - -VOID -ExceptionHandlersEnd ( - VOID - ); - -VOID -CommonExceptionEntry ( - VOID - ); - -VOID -AsmCommonExceptionEntry ( - VOID - ); - - -EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_ARM_EXCEPTION + 1]; -EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_ARM_EXCEPTION + 1]; - - - -/** - This function registers and enables the handler specified by InterruptHandler for a processor - interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the - handler for the processor interrupt or exception type specified by InterruptType is uninstalled. - The installed handler is called once for each processor interrupt or exception. - - @param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts - are enabled and FALSE if interrupts are disabled. - @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called - when a processor interrupt occurs. If this parameter is NULL, then the handler - will be uninstalled. - - @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. - @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was - previously installed. - @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not - previously installed. - @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. - -**/ -EFI_STATUS -RegisterInterruptHandler ( - IN EFI_EXCEPTION_TYPE InterruptType, - IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler - ) -{ - if (InterruptType > MAX_ARM_EXCEPTION) { - return EFI_UNSUPPORTED; - } - - if ((InterruptHandler != NULL) && (gExceptionHandlers[InterruptType] != NULL)) { - return EFI_ALREADY_STARTED; - } - - gExceptionHandlers[InterruptType] = InterruptHandler; - - return EFI_SUCCESS; -} - - - - -VOID -EFIAPI -CommonCExceptionHandler ( - IN EFI_EXCEPTION_TYPE ExceptionType, - IN OUT EFI_SYSTEM_CONTEXT SystemContext - ) -{ - if (ExceptionType <= MAX_ARM_EXCEPTION) { - if (gExceptionHandlers[ExceptionType]) { - gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext); - return; - } - } else { - DEBUG ((EFI_D_ERROR, "Unknown exception type %d from %08x\n", ExceptionType, SystemContext.SystemContextArm->PC)); - ASSERT (FALSE); - } - - if (ExceptionType == EXCEPT_ARM_SOFTWARE_INTERRUPT) { - // - // ARM JTAG debuggers some times use this vector, so it is not an error to get one - // - return; - } - - DefaultExceptionHandler (ExceptionType, SystemContext); -} - - - -EFI_STATUS -InitializeExceptions ( - IN EFI_CPU_ARCH_PROTOCOL *Cpu - ) -{ - EFI_STATUS Status; - UINTN Offset; - UINTN Length; - UINTN Index; - BOOLEAN IrqEnabled; - BOOLEAN FiqEnabled; - EFI_PHYSICAL_ADDRESS Base; - UINT32 *VectorBase; - - Status = EFI_SUCCESS; - ZeroMem (gExceptionHandlers,sizeof(*gExceptionHandlers)); - - // - // Disable interrupts - // - Cpu->GetInterruptState (Cpu, &IrqEnabled); - Cpu->DisableInterrupt (Cpu); - - // - // EFI does not use the FIQ, but a debugger might so we must disable - // as we take over the exception vectors. - // - FiqEnabled = ArmGetFiqState (); - ArmDisableFiq (); - - if (FeaturePcdGet(PcdRelocateVectorTable) == TRUE) { - // - // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress. - // - Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart; - - // Check if the exception vector is in the low address - if (PcdGet32 (PcdCpuVectorBaseAddress) == 0x0) { - // Set SCTLR.V to 0 to enable VBAR to be used - ArmSetLowVectors (); - } else { - ArmSetHighVectors (); - } - - // - // Reserve space for the exception handlers - // - Base = (EFI_PHYSICAL_ADDRESS)PcdGet32 (PcdCpuVectorBaseAddress); - VectorBase = (UINT32 *)(UINTN)Base; - Status = gBS->AllocatePages (AllocateAddress, EfiBootServicesCode, EFI_SIZE_TO_PAGES (Length), &Base); - // If the request was for memory that's not in the memory map (which is often the case for 0x00000000 - // on embedded systems, for example, we don't want to hang up. So we'll check here for a status of - // EFI_NOT_FOUND, and continue in that case. - if (EFI_ERROR(Status) && (Status != EFI_NOT_FOUND)) { - ASSERT_EFI_ERROR (Status); - } - - if (FeaturePcdGet(PcdDebuggerExceptionSupport) == TRUE) { - // Save existing vector table, in case debugger is already hooked in - CopyMem ((VOID *)gDebuggerExceptionHandlers, (VOID *)VectorBase, sizeof (gDebuggerExceptionHandlers)); - } - - // Copy our assembly code into the page that contains the exception vectors. - CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length); - - // - // Patch in the common Assembly exception handler - // - Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart; - *(UINTN *) ((UINT8 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress) + Offset) = (UINTN)AsmCommonExceptionEntry; - - // - // Initialize the C entry points for interrupts - // - for (Index = 0; Index <= MAX_ARM_EXCEPTION; Index++) { - if (!FeaturePcdGet(PcdDebuggerExceptionSupport) || - (gDebuggerExceptionHandlers[Index] == 0) || (gDebuggerExceptionHandlers[Index] == (VOID *)(UINTN)0xEAFFFFFE)) { - // Exception handler contains branch to vector location (jmp $) so no handler - // NOTE: This code assumes vectors are ARM and not Thumb code - Status = RegisterInterruptHandler (Index, NULL); - ASSERT_EFI_ERROR (Status); - } else { - // If the debugger has already hooked put its vector back - VectorBase[Index] = (UINT32)(UINTN)gDebuggerExceptionHandlers[Index]; - } - } - - // Flush Caches since we updated executable stuff - InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length); - - //Note: On ARM processor with the Security Extension, the Vector Table can be located anywhere in the memory. - // The Vector Base Address Register defines the location - ArmWriteVBar (PcdGet32(PcdCpuVectorBaseAddress)); - } else { - // The Vector table must be 32-byte aligned - if (((UINT32)ExceptionHandlersStart & ARM_VECTOR_TABLE_ALIGNMENT) != 0) { - ASSERT (0); - return EFI_INVALID_PARAMETER; - } - - // We do not copy the Exception Table at PcdGet32(PcdCpuVectorBaseAddress). We just set Vector Base Address to point into CpuDxe code. - ArmWriteVBar ((UINT32)ExceptionHandlersStart); - } - - if (FiqEnabled) { - ArmEnableFiq (); - } - - if (IrqEnabled) { - // - // Restore interrupt state - // - Status = Cpu->EnableInterrupt (Cpu); - } - - return Status; -} diff --git a/ArmPkg/Drivers/CpuDxe/Arm/ExceptionSupport.S b/ArmPkg/Drivers/CpuDxe/Arm/ExceptionSupport.S deleted file mode 100644 index 673b931297..0000000000 --- a/ArmPkg/Drivers/CpuDxe/Arm/ExceptionSupport.S +++ /dev/null @@ -1,304 +0,0 @@ -#------------------------------------------------------------------------------ -# -# Use ARMv6 instruction to operate on a single stack -# -# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
-# Copyright (c) 2014, ARM Limited. All rights reserved.
-# -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -#------------------------------------------------------------------------------ - -#include - -/* - -This is the stack constructed by the exception handler (low address to high address) - # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM - Reg Offset - === ====== - R0 0x00 # stmfd SP!,{R0-R12} - R1 0x04 - R2 0x08 - R3 0x0c - R4 0x10 - R5 0x14 - R6 0x18 - R7 0x1c - R8 0x20 - R9 0x24 - R10 0x28 - R11 0x2c - R12 0x30 - SP 0x34 # reserved via subtraction 0x20 (32) from SP - LR 0x38 - PC 0x3c - CPSR 0x40 - DFSR 0x44 - DFAR 0x48 - IFSR 0x4c - IFAR 0x50 - - LR 0x54 # SVC Link register (we need to restore it) - - LR 0x58 # pushed by srsfd - CPSR 0x5c - - */ - - -GCC_ASM_EXPORT(ExceptionHandlersStart) -GCC_ASM_EXPORT(ExceptionHandlersEnd) -GCC_ASM_EXPORT(CommonExceptionEntry) -GCC_ASM_EXPORT(AsmCommonExceptionEntry) -GCC_ASM_EXPORT(CommonCExceptionHandler) - -.text -.syntax unified -#if !defined(__APPLE__) -.fpu neon @ makes vpush/vpop assemble -#endif -.align 5 - - -// -// This code gets copied to the ARM vector table -// ExceptionHandlersStart - ExceptionHandlersEnd gets copied -// -ASM_PFX(ExceptionHandlersStart): - -ASM_PFX(Reset): - b ASM_PFX(ResetEntry) - -ASM_PFX(UndefinedInstruction): - b ASM_PFX(UndefinedInstructionEntry) - -ASM_PFX(SoftwareInterrupt): - b ASM_PFX(SoftwareInterruptEntry) - -ASM_PFX(PrefetchAbort): - b ASM_PFX(PrefetchAbortEntry) - -ASM_PFX(DataAbort): - b ASM_PFX(DataAbortEntry) - -ASM_PFX(ReservedException): - b ASM_PFX(ReservedExceptionEntry) - -ASM_PFX(Irq): - b ASM_PFX(IrqEntry) - -ASM_PFX(Fiq): - b ASM_PFX(FiqEntry) - -ASM_PFX(ResetEntry): - srsdb #0x13! @ Store return state on SVC stack - @ We are already in SVC mode - - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#0 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(UndefinedInstructionEntry): - sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#1 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(SoftwareInterruptEntry): - srsdb #0x13! @ Store return state on SVC stack - @ We are already in SVC mode - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#2 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(PrefetchAbortEntry): - sub LR,LR,#4 - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#3 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(DataAbortEntry): - sub LR,LR,#8 - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#4 - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(ReservedExceptionEntry): - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#5 - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(IrqEntry): - sub LR,LR,#4 - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - - mov R0,#6 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -ASM_PFX(FiqEntry): - sub LR,LR,#4 - srsdb #0x13! @ Store return state on SVC stack - cps #0x13 @ Switch to SVC for common stack - stmfd SP!,{LR} @ Store the link register for the current mode - sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} @ Store the register state - @ Since we have already switch to SVC R8_fiq - R12_fiq - @ never get used or saved - mov R0,#7 @ ExceptionType - ldr R1,ASM_PFX(CommonExceptionEntry) - bx R1 - -// -// This gets patched by the C code that patches in the vector table -// -ASM_PFX(CommonExceptionEntry): - .word ASM_PFX(AsmCommonExceptionEntry) - -ASM_PFX(ExceptionHandlersEnd): - -// -// This code runs from CpuDxe driver loaded address. It is patched into -// CommonExceptionEntry. -// -ASM_PFX(AsmCommonExceptionEntry): - mrc p15, 0, R1, c6, c0, 2 @ Read IFAR - str R1, [SP, #0x50] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR - - mrc p15, 0, R1, c5, c0, 1 @ Read IFSR - str R1, [SP, #0x4c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR - - mrc p15, 0, R1, c6, c0, 0 @ Read DFAR - str R1, [SP, #0x48] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR - - mrc p15, 0, R1, c5, c0, 0 @ Read DFSR - str R1, [SP, #0x44] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR - - ldr R1, [SP, #0x5c] @ srsdb saved pre-exception CPSR on the stack - str R1, [SP, #0x40] @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR - - add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR - and R3, R1, #0x1f @ Check CPSR to see if User or System Mode - cmp R3, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f)) - cmpne R3, #0x10 @ - stmdaeq R2, {lr}^ @ save unbanked lr - @ else - stmdane R2, {lr} @ save SVC lr - - - ldr R5, [SP, #0x58] @ PC is the LR pushed by srsfd - @ Check to see if we have to adjust for Thumb entry - sub r4, r0, #1 @ if (ExceptionType == 1 || ExceptionType == 2)) { - cmp r4, #1 @ // UND & SVC have differnt LR adjust for Thumb - bhi NoAdjustNeeded - - tst r1, #0x20 @ if ((CPSR & T)) == T) { // Thumb Mode on entry - addne R5, R5, #2 @ PC += 2; - strne R5,[SP,#0x58] @ Update LR value pushed by srsfd - -NoAdjustNeeded: - - str R5, [SP, #0x3c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC - - add R1, SP, #0x60 @ We pushed 0x60 bytes on the stack - str R1, [SP, #0x34] @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP - - @ R0 is ExceptionType - mov R1,SP @ R1 is SystemContext - -#if (FixedPcdGet32(PcdVFPEnabled)) - vpush {d0-d15} @ save vstm registers in case they are used in optimizations -#endif - - mov R4, SP @ Save current SP - tst R4, #4 - subne SP, SP, #4 @ Adjust SP if not 8-byte aligned - -/* -VOID -EFIAPI -CommonCExceptionHandler ( - IN EFI_EXCEPTION_TYPE ExceptionType, R0 - IN OUT EFI_SYSTEM_CONTEXT SystemContext R1 - ) - -*/ - blx ASM_PFX(CommonCExceptionHandler) @ Call exception handler - - mov SP, R4 @ Restore SP - -#if (FixedPcdGet32(PcdVFPEnabled)) - vpop {d0-d15} -#endif - - ldr R1, [SP, #0x4c] @ Restore EFI_SYSTEM_CONTEXT_ARM.IFSR - mcr p15, 0, R1, c5, c0, 1 @ Write IFSR - - ldr R1, [SP, #0x44] @ Restore EFI_SYSTEM_CONTEXT_ARM.DFSR - mcr p15, 0, R1, c5, c0, 0 @ Write DFSR - - ldr R1,[SP,#0x3c] @ EFI_SYSTEM_CONTEXT_ARM.PC - str R1,[SP,#0x58] @ Store it back to srsfd stack slot so it can be restored - - ldr R1,[SP,#0x40] @ EFI_SYSTEM_CONTEXT_ARM.CPSR - str R1,[SP,#0x5c] @ Store it back to srsfd stack slot so it can be restored - - add R3, SP, #0x54 @ Make R3 point to SVC LR saved on entry - add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR - and R1, R1, #0x1f @ Check to see if User or System Mode - cmp R1, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f)) - cmpne R1, #0x10 @ - ldmibeq R2, {lr}^ @ restore unbanked lr - @ else - ldmibne R3, {lr} @ restore SVC lr, via ldmfd SP!, {LR} - - ldmfd SP!,{R0-R12} @ Restore general purpose registers - @ Exception handler can not change SP - - add SP,SP,#0x20 @ Clear out the remaining stack space - ldmfd SP!,{LR} @ restore the link register for this context - rfefd SP! @ return from exception via srsfd stack slot - diff --git a/ArmPkg/Drivers/CpuDxe/Arm/ExceptionSupport.asm b/ArmPkg/Drivers/CpuDxe/Arm/ExceptionSupport.asm deleted file mode 100644 index b28ff9f7ee..0000000000 --- a/ArmPkg/Drivers/CpuDxe/Arm/ExceptionSupport.asm +++ /dev/null @@ -1,301 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Use ARMv6 instruction to operate on a single stack -// -// Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.
-// Copyright (c) 2014, ARM Limited. All rights reserved.
-// -// This program and the accompanying materials -// are licensed and made available under the terms and conditions of the BSD License -// which accompanies this distribution. The full text of the license may be found at -// http://opensource.org/licenses/bsd-license.php -// -// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -// -//------------------------------------------------------------------------------ - -#include - -/* - -This is the stack constructed by the exception handler (low address to high address) - # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM - Reg Offset - === ====== - R0 0x00 # stmfd SP!,{R0-R12} - R1 0x04 - R2 0x08 - R3 0x0c - R4 0x10 - R5 0x14 - R6 0x18 - R7 0x1c - R8 0x20 - R9 0x24 - R10 0x28 - R11 0x2c - R12 0x30 - SP 0x34 # reserved via subtraction 0x20 (32) from SP - LR 0x38 - PC 0x3c - CPSR 0x40 - DFSR 0x44 - DFAR 0x48 - IFSR 0x4c - IFAR 0x50 - - LR 0x54 # SVC Link register (we need to restore it) - - LR 0x58 # pushed by srsfd - CPSR 0x5c - - */ - - - EXPORT ExceptionHandlersStart - EXPORT ExceptionHandlersEnd - EXPORT CommonExceptionEntry - EXPORT AsmCommonExceptionEntry - IMPORT CommonCExceptionHandler - - PRESERVE8 - AREA DxeExceptionHandlers, CODE, READONLY, CODEALIGN, ALIGN=5 - -// -// This code gets copied to the ARM vector table -// ExceptionHandlersStart - ExceptionHandlersEnd gets copied -// -ExceptionHandlersStart - -Reset - b ResetEntry - -UndefinedInstruction - b UndefinedInstructionEntry - -SoftwareInterrupt - b SoftwareInterruptEntry - -PrefetchAbort - b PrefetchAbortEntry - -DataAbort - b DataAbortEntry - -ReservedException - b ReservedExceptionEntry - -Irq - b IrqEntry - -Fiq - b FiqEntry - -ResetEntry - srsfd #0x13! ; Store return state on SVC stack - ; We are already in SVC mode - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#0 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -UndefinedInstructionEntry - sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#1 ; ExceptionType - ldr R1,CommonExceptionEntry; - bx R1 - -SoftwareInterruptEntry - srsfd #0x13! ; Store return state on SVC stack - ; We are already in SVC mode - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#2 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -PrefetchAbortEntry - sub LR,LR,#4 - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#3 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -DataAbortEntry - sub LR,LR,#8 - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#4 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -ReservedExceptionEntry - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#5 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -IrqEntry - sub LR,LR,#4 - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - - mov R0,#6 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -FiqEntry - sub LR,LR,#4 - srsfd #0x13! ; Store return state on SVC stack - cps #0x13 ; Switch to SVC for common stack - stmfd SP!,{LR} ; Store the link register for the current mode - sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR - stmfd SP!,{R0-R12} ; Store the register state - ; Since we have already switch to SVC R8_fiq - R12_fiq - ; never get used or saved - mov R0,#7 ; ExceptionType - ldr R1,CommonExceptionEntry - bx R1 - -// -// This gets patched by the C code that patches in the vector table -// -CommonExceptionEntry - dcd AsmCommonExceptionEntry - -ExceptionHandlersEnd - -// -// This code runs from CpuDxe driver loaded address. It is patched into -// CommonExceptionEntry. -// -AsmCommonExceptionEntry - mrc p15, 0, R1, c6, c0, 2 ; Read IFAR - str R1, [SP, #0x50] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR - - mrc p15, 0, R1, c5, c0, 1 ; Read IFSR - str R1, [SP, #0x4c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR - - mrc p15, 0, R1, c6, c0, 0 ; Read DFAR - str R1, [SP, #0x48] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR - - mrc p15, 0, R1, c5, c0, 0 ; Read DFSR - str R1, [SP, #0x44] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR - - ldr R1, [SP, #0x5c] ; srsfd saved pre-exception CPSR on the stack - str R1, [SP, #0x40] ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR - - add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR - and R3, R1, #0x1f ; Check CPSR to see if User or System Mode - cmp R3, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f)) - cmpne R3, #0x10 ; - stmeqed R2, {lr}^ ; save unbanked lr - ; else - stmneed R2, {lr} ; save SVC lr - - - ldr R5, [SP, #0x58] ; PC is the LR pushed by srsfd - ; Check to see if we have to adjust for Thumb entry - sub r4, r0, #1 ; if (ExceptionType == 1 || ExceptionType == 2)) { - cmp r4, #1 ; // UND & SVC have differnt LR adjust for Thumb - bhi NoAdjustNeeded - - tst r1, #0x20 ; if ((CPSR & T)) == T) { // Thumb Mode on entry - addne R5, R5, #2 ; PC += 2; - strne R5,[SP,#0x58] ; Update LR value pushed by srsfd - -NoAdjustNeeded - - str R5, [SP, #0x3c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC - - add R1, SP, #0x60 ; We pushed 0x60 bytes on the stack - str R1, [SP, #0x34] ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP - - ; R0 is ExceptionType - mov R1,SP ; R1 is SystemContext - -#if (FixedPcdGet32(PcdVFPEnabled)) - vpush {d0-d15} ; save vstm registers in case they are used in optimizations -#endif - - mov R4, SP ; Save current SP - tst R4, #4 - subne SP, SP, #4 ; Adjust SP if not 8-byte aligned - -/* -VOID -EFIAPI -CommonCExceptionHandler ( - IN EFI_EXCEPTION_TYPE ExceptionType, R0 - IN OUT EFI_SYSTEM_CONTEXT SystemContext R1 - ) - -*/ - blx CommonCExceptionHandler ; Call exception handler - - mov SP, R4 ; Restore SP - -#if (FixedPcdGet32(PcdVFPEnabled)) - vpop {d0-d15} -#endif - - ldr R1, [SP, #0x4c] ; Restore EFI_SYSTEM_CONTEXT_ARM.IFSR - mcr p15, 0, R1, c5, c0, 1 ; Write IFSR - - ldr R1, [SP, #0x44] ; Restore EFI_SYSTEM_CONTEXT_ARM.DFSR - mcr p15, 0, R1, c5, c0, 0 ; Write DFSR - - ldr R1,[SP,#0x3c] ; EFI_SYSTEM_CONTEXT_ARM.PC - str R1,[SP,#0x58] ; Store it back to srsfd stack slot so it can be restored - - ldr R1,[SP,#0x40] ; EFI_SYSTEM_CONTEXT_ARM.CPSR - str R1,[SP,#0x5c] ; Store it back to srsfd stack slot so it can be restored - - add R3, SP, #0x54 ; Make R3 point to SVC LR saved on entry - add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR - and R1, R1, #0x1f ; Check to see if User or System Mode - cmp R1, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f)) - cmpne R1, #0x10 ; - ldmeqed R2, {lr}^ ; restore unbanked lr - ; else - ldmneed R3, {lr} ; restore SVC lr, via ldmfd SP!, {LR} - - ldmfd SP!,{R0-R12} ; Restore general purpose registers - ; Exception handler can not change SP - - add SP,SP,#0x20 ; Clear out the remaining stack space - ldmfd SP!,{LR} ; restore the link register for this context - rfefd SP! ; return from exception via srsfd stack slot - - END - - diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf index 9ad242a42e..21cdf319d4 100644 --- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf +++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf @@ -29,17 +29,13 @@ CpuDxe.h CpuMpCore.c CpuMmuCommon.c + Exception.c [Sources.ARM] Arm/Mmu.c - Arm/Exception.c - Arm/ExceptionSupport.asm | RVCT - Arm/ExceptionSupport.S | GCC [Sources.AARCH64] AArch64/Mmu.c - AArch64/Exception.c - AArch64/ExceptionSupport.S [Packages] ArmPkg/ArmPkg.dec @@ -52,6 +48,7 @@ BaseMemoryLib CacheMaintenanceLib CpuLib + CpuExceptionHandlerLib DebugLib DefaultExceptionHandlerLib DxeServicesTableLib @@ -69,14 +66,13 @@ gEfiDebugImageInfoTableGuid gArmMpCoreInfoGuid gIdleLoopEventGuid + gEfiVectorHandoffTableGuid [Pcd.common] gArmTokenSpaceGuid.PcdVFPEnabled - gArmTokenSpaceGuid.PcdCpuVectorBaseAddress [FeaturePcd.common] gArmTokenSpaceGuid.PcdCpuDxeProduceDebugSupport - gArmTokenSpaceGuid.PcdRelocateVectorTable gArmTokenSpaceGuid.PcdDebuggerExceptionSupport [Depex] diff --git a/ArmPkg/Drivers/CpuDxe/Exception.c b/ArmPkg/Drivers/CpuDxe/Exception.c new file mode 100644 index 0000000000..c3107cd4a6 --- /dev/null +++ b/ArmPkg/Drivers/CpuDxe/Exception.c @@ -0,0 +1,95 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+ Portions Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuDxe.h" +#include +#include + +EFI_STATUS +InitializeExceptions ( + IN EFI_CPU_ARCH_PROTOCOL *Cpu + ) { + EFI_STATUS Status; + EFI_VECTOR_HANDOFF_INFO *VectorInfoList; + EFI_VECTOR_HANDOFF_INFO *VectorInfo; + BOOLEAN IrqEnabled; + BOOLEAN FiqEnabled; + + VectorInfo = (EFI_VECTOR_HANDOFF_INFO *)NULL; + Status = EfiGetSystemConfigurationTable(&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList); + if (Status == EFI_SUCCESS && VectorInfoList != NULL) { + VectorInfo = VectorInfoList; + } + + // intialize the CpuExceptionHandlerLib so we take over the exception vector table from the DXE Core + InitializeCpuExceptionHandlers(VectorInfo); + + Status = EFI_SUCCESS; + + // + // Disable interrupts + // + Cpu->GetInterruptState (Cpu, &IrqEnabled); + Cpu->DisableInterrupt (Cpu); + + // + // EFI does not use the FIQ, but a debugger might so we must disable + // as we take over the exception vectors. + // + FiqEnabled = ArmGetFiqState (); + ArmDisableFiq (); + + if (FiqEnabled) { + ArmEnableFiq (); + } + + if (IrqEnabled) { + // + // Restore interrupt state + // + Status = Cpu->EnableInterrupt (Cpu); + } + + return Status; +} + +/** +This function registers and enables the handler specified by InterruptHandler for a processor +interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the +handler for the processor interrupt or exception type specified by InterruptType is uninstalled. +The installed handler is called once for each processor interrupt or exception. + +@param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts +are enabled and FALSE if interrupts are disabled. +@param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called +when a processor interrupt occurs. If this parameter is NULL, then the handler +will be uninstalled. + +@retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled. +@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was +previously installed. +@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not +previously installed. +@retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported. + +**/ +EFI_STATUS +RegisterInterruptHandler( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) { + // pass down to CpuExceptionHandlerLib + return (EFI_STATUS)RegisterCpuInterruptHandler(InterruptType, InterruptHandler); +}