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 <eugene@hp.com> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
This commit is contained in:
committed by
Ard Biesheuvel
parent
8a47a6cb9e
commit
5811eea0fd
@@ -1,154 +0,0 @@
|
|||||||
/** @file
|
|
||||||
|
|
||||||
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
|
|
||||||
Portions Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
|
|
||||||
|
|
||||||
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 <Chipset/AArch64.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
@@ -1,402 +0,0 @@
|
|||||||
//
|
|
||||||
// Copyright (c) 2011 - 2014 ARM LTD. All rights reserved.<BR>
|
|
||||||
// Portion of Copyright (c) 2014 NVIDIA Corporation. All rights reserved.<BR>
|
|
||||||
//
|
|
||||||
// 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 <Chipset/AArch64.h>
|
|
||||||
#include <Library/PcdLib.h>
|
|
||||||
#include <AsmMacroIoLibV8.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
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
|
|
@@ -1,234 +0,0 @@
|
|||||||
/** @file
|
|
||||||
|
|
||||||
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
|
|
||||||
Copyright (c) 2014, ARM Limited. All rights reserved.<BR>
|
|
||||||
|
|
||||||
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 <Chipset/ArmV7.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
@@ -1,304 +0,0 @@
|
|||||||
#------------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Use ARMv6 instruction to operate on a single stack
|
|
||||||
#
|
|
||||||
# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
|
|
||||||
# Copyright (c) 2014, ARM Limited. All rights reserved.<BR>
|
|
||||||
#
|
|
||||||
# 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 <Library/PcdLib.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
@@ -1,301 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Use ARMv6 instruction to operate on a single stack
|
|
||||||
//
|
|
||||||
// Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
|
|
||||||
// Copyright (c) 2014, ARM Limited. All rights reserved.<BR>
|
|
||||||
//
|
|
||||||
// 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 <Library/PcdLib.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
@@ -29,17 +29,13 @@
|
|||||||
CpuDxe.h
|
CpuDxe.h
|
||||||
CpuMpCore.c
|
CpuMpCore.c
|
||||||
CpuMmuCommon.c
|
CpuMmuCommon.c
|
||||||
|
Exception.c
|
||||||
|
|
||||||
[Sources.ARM]
|
[Sources.ARM]
|
||||||
Arm/Mmu.c
|
Arm/Mmu.c
|
||||||
Arm/Exception.c
|
|
||||||
Arm/ExceptionSupport.asm | RVCT
|
|
||||||
Arm/ExceptionSupport.S | GCC
|
|
||||||
|
|
||||||
[Sources.AARCH64]
|
[Sources.AARCH64]
|
||||||
AArch64/Mmu.c
|
AArch64/Mmu.c
|
||||||
AArch64/Exception.c
|
|
||||||
AArch64/ExceptionSupport.S
|
|
||||||
|
|
||||||
[Packages]
|
[Packages]
|
||||||
ArmPkg/ArmPkg.dec
|
ArmPkg/ArmPkg.dec
|
||||||
@@ -52,6 +48,7 @@
|
|||||||
BaseMemoryLib
|
BaseMemoryLib
|
||||||
CacheMaintenanceLib
|
CacheMaintenanceLib
|
||||||
CpuLib
|
CpuLib
|
||||||
|
CpuExceptionHandlerLib
|
||||||
DebugLib
|
DebugLib
|
||||||
DefaultExceptionHandlerLib
|
DefaultExceptionHandlerLib
|
||||||
DxeServicesTableLib
|
DxeServicesTableLib
|
||||||
@@ -69,14 +66,13 @@
|
|||||||
gEfiDebugImageInfoTableGuid
|
gEfiDebugImageInfoTableGuid
|
||||||
gArmMpCoreInfoGuid
|
gArmMpCoreInfoGuid
|
||||||
gIdleLoopEventGuid
|
gIdleLoopEventGuid
|
||||||
|
gEfiVectorHandoffTableGuid
|
||||||
|
|
||||||
[Pcd.common]
|
[Pcd.common]
|
||||||
gArmTokenSpaceGuid.PcdVFPEnabled
|
gArmTokenSpaceGuid.PcdVFPEnabled
|
||||||
gArmTokenSpaceGuid.PcdCpuVectorBaseAddress
|
|
||||||
|
|
||||||
[FeaturePcd.common]
|
[FeaturePcd.common]
|
||||||
gArmTokenSpaceGuid.PcdCpuDxeProduceDebugSupport
|
gArmTokenSpaceGuid.PcdCpuDxeProduceDebugSupport
|
||||||
gArmTokenSpaceGuid.PcdRelocateVectorTable
|
|
||||||
gArmTokenSpaceGuid.PcdDebuggerExceptionSupport
|
gArmTokenSpaceGuid.PcdDebuggerExceptionSupport
|
||||||
|
|
||||||
[Depex]
|
[Depex]
|
||||||
|
95
ArmPkg/Drivers/CpuDxe/Exception.c
Normal file
95
ArmPkg/Drivers/CpuDxe/Exception.c
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/** @file
|
||||||
|
|
||||||
|
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
|
||||||
|
Portions Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
|
||||||
|
|
||||||
|
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 <Library/CpuExceptionHandlerLib.h>
|
||||||
|
#include <Guid/VectorHandoffTable.h>
|
||||||
|
|
||||||
|
EFI_STATUS
|
||||||
|
InitializeExceptions (
|
||||||
|
IN EFI_CPU_ARCH_PROTOCOL *Cpu
|
||||||
|
) {
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
|
||||||
|
EFI_VECTOR_HANDOFF_INFO *VectorInfo;
|
||||||
|
BOOLEAN IrqEnabled;
|
||||||
|
BOOLEAN FiqEnabled;
|
||||||
|
|
||||||
|
VectorInfo = (EFI_VECTOR_HANDOFF_INFO *)NULL;
|
||||||
|
Status = EfiGetSystemConfigurationTable(&gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
|
||||||
|
if (Status == EFI_SUCCESS && VectorInfoList != NULL) {
|
||||||
|
VectorInfo = VectorInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
Reference in New Issue
Block a user