audk/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S

371 lines
12 KiB
ArmAsm

//
// Copyright (c) 2011 - 2014 ARM LTD. All rights reserved.<BR>
// Portion of Copyright (c) 2014 NVIDIA Corporation. All rights reserved.<BR>
// Copyright (c) 2016 HP Development Company, L.P.
//
// 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>
#include <Protocol/DebugSupport.h> // for exception type definitions
/*
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(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)
//
// There are two methods for installing AArch64 exception vectors:
// 1. Install a copy of the vectors to a location specified by a PCD
// 2. Write VBAR directly, requiring that vectors have proper alignment (2K)
// The conditional below adjusts the alignment requirement based on which
// exception vector initialization method is used.
//
#if defined(ARM_RELOCATE_VECTORS)
GCC_ASM_EXPORT(ExceptionHandlersStart)
ASM_PFX(ExceptionHandlersStart):
#else
VECTOR_BASE(ExceptionHandlersStart)
#endif
.macro ExceptionEntry, val
// Move the stackpointer so we can reach our structure with the str instruction.
sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
// Push some GP registers so we can record the exception context
stp x0, x1, [sp, #-GP_CONTEXT_SIZE]!
stp x2, x3, [sp, #0x10]
stp x4, x5, [sp, #0x20]
stp x6, x7, [sp, #0x30]
EL1_OR_EL2_OR_EL3(x1)
1:mrs x2, elr_el1 // Exception Link Register
mrs x3, spsr_el1 // Saved Processor Status Register 32bit
mrs x5, esr_el1 // EL1 Exception syndrome register 32bit
mrs x6, far_el1 // EL1 Fault Address Register
b 4f
2:mrs x2, elr_el2 // Exception Link Register
mrs x3, spsr_el2 // Saved Processor Status Register 32bit
mrs x5, esr_el2 // EL2 Exception syndrome register 32bit
mrs x6, far_el2 // EL2 Fault Address Register
b 4f
3:mrs x2, elr_el3 // Exception Link Register
mrs x3, spsr_el3 // Saved Processor Status Register 32bit
mrs x5, esr_el3 // EL3 Exception syndrome register 32bit
mrs x6, far_el3 // EL3 Fault Address Register
4:mrs x4, fpsr // Floating point Status Register 32bit
// Record the type of exception that occurred.
mov x0, #\val
// Jump to our general handler to deal with all the common parts and process the exception.
#if defined(ARM_RELOCATE_VECTORS)
ldr x1, =ASM_PFX(CommonExceptionEntry)
br x1
.ltorg
#else
b ASM_PFX(CommonExceptionEntry)
#endif
.endm
//
// Current EL with SP0 : 0x0 - 0x180
//
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SYNC)
ASM_PFX(SynchronousExceptionSP0):
ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_IRQ)
ASM_PFX(IrqSP0):
ExceptionEntry EXCEPT_AARCH64_IRQ
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_FIQ)
ASM_PFX(FiqSP0):
ExceptionEntry EXCEPT_AARCH64_FIQ
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SP0_SERR)
ASM_PFX(SErrorSP0):
ExceptionEntry EXCEPT_AARCH64_SERROR
//
// Current EL with SPx: 0x200 - 0x380
//
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SYNC)
ASM_PFX(SynchronousExceptionSPx):
ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_IRQ)
ASM_PFX(IrqSPx):
ExceptionEntry EXCEPT_AARCH64_IRQ
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_FIQ)
ASM_PFX(FiqSPx):
ExceptionEntry EXCEPT_AARCH64_FIQ
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_CUR_SPx_SERR)
ASM_PFX(SErrorSPx):
ExceptionEntry EXCEPT_AARCH64_SERROR
//
// Lower EL using AArch64 : 0x400 - 0x580
//
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SYNC)
ASM_PFX(SynchronousExceptionA64):
ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_IRQ)
ASM_PFX(IrqA64):
ExceptionEntry EXCEPT_AARCH64_IRQ
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_FIQ)
ASM_PFX(FiqA64):
ExceptionEntry EXCEPT_AARCH64_FIQ
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A64_SERR)
ASM_PFX(SErrorA64):
ExceptionEntry EXCEPT_AARCH64_SERROR
//
// Lower EL using AArch32 : 0x600 - 0x780
//
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SYNC)
ASM_PFX(SynchronousExceptionA32):
ExceptionEntry EXCEPT_AARCH64_SYNCHRONOUS_EXCEPTIONS
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_IRQ)
ASM_PFX(IrqA32):
ExceptionEntry EXCEPT_AARCH64_IRQ
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_FIQ)
ASM_PFX(FiqA32):
ExceptionEntry EXCEPT_AARCH64_FIQ
VECTOR_ENTRY(ExceptionHandlersStart, ARM_VECTOR_LOW_A32_SERR)
ASM_PFX(SErrorA32):
ExceptionEntry EXCEPT_AARCH64_SERROR
VECTOR_END(ExceptionHandlersStart)
ASM_PFX(ExceptionHandlersEnd):
ASM_PFX(CommonExceptionEntry):
// Stack the remaining GP registers
stp x8, x9, [sp, #0x40]
stp x10, x11, [sp, #0x50]
stp x12, x13, [sp, #0x60]
stp x14, x15, [sp, #0x70]
stp x16, x17, [sp, #0x80]
stp x18, x19, [sp, #0x90]
stp x20, x21, [sp, #0xa0]
stp x22, x23, [sp, #0xb0]
stp x24, x25, [sp, #0xc0]
stp x26, x27, [sp, #0xd0]
stp x28, x29, [sp, #0xe0]
add x28, sp, #GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE
stp x30, x28, [sp, #0xf0]
// Save the SYS regs
stp x2, x3, [x28, #-SYS_CONTEXT_SIZE]!
stp x4, x5, [x28, #0x10]
str x6, [x28, #0x20]
// Push FP regs to Stack.
stp q0, q1, [x28, #-FP_CONTEXT_SIZE]!
stp q2, q3, [x28, #0x20]
stp q4, q5, [x28, #0x40]
stp q6, q7, [x28, #0x60]
stp q8, q9, [x28, #0x80]
stp q10, q11, [x28, #0xa0]
stp q12, q13, [x28, #0xc0]
stp q14, q15, [x28, #0xe0]
stp q16, q17, [x28, #0x100]
stp q18, q19, [x28, #0x120]
stp q20, q21, [x28, #0x140]
stp q22, q23, [x28, #0x160]
stp q24, q25, [x28, #0x180]
stp q26, q27, [x28, #0x1a0]
stp q28, q29, [x28, #0x1c0]
stp q30, q31, [x28, #0x1e0]
// 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
// Pop as many GP regs as we can before entering the critical section below
ldp x2, x3, [sp, #0x10]
ldp x4, x5, [sp, #0x20]
ldp x6, x7, [sp, #0x30]
ldp x8, x9, [sp, #0x40]
ldp x10, x11, [sp, #0x50]
ldp x12, x13, [sp, #0x60]
ldp x14, x15, [sp, #0x70]
ldp x16, x17, [sp, #0x80]
ldp x18, x19, [sp, #0x90]
ldp x20, x21, [sp, #0xa0]
ldp x22, x23, [sp, #0xb0]
ldp x24, x25, [sp, #0xc0]
ldp x26, x27, [sp, #0xd0]
ldp x0, x1, [sp], #0xe0
// Pop FP regs from Stack.
ldp q2, q3, [x28, #0x20]
ldp q4, q5, [x28, #0x40]
ldp q6, q7, [x28, #0x60]
ldp q8, q9, [x28, #0x80]
ldp q10, q11, [x28, #0xa0]
ldp q12, q13, [x28, #0xc0]
ldp q14, q15, [x28, #0xe0]
ldp q16, q17, [x28, #0x100]
ldp q18, q19, [x28, #0x120]
ldp q20, q21, [x28, #0x140]
ldp q22, q23, [x28, #0x160]
ldp q24, q25, [x28, #0x180]
ldp q26, q27, [x28, #0x1a0]
ldp q28, q29, [x28, #0x1c0]
ldp q30, q31, [x28, #0x1e0]
ldp q0, q1, [x28], #FP_CONTEXT_SIZE
// Pop the SYS regs we need
ldp x29, x30, [x28]
ldr x28, [x28, #0x10]
msr fpsr, x28
//
// 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
EL1_OR_EL2_OR_EL3(x28)
1:msr elr_el1, x29 // Exception Link Register
msr spsr_el1, x30 // Saved Processor Status Register 32bit
b 4f
2:msr elr_el2, x29 // Exception Link Register
msr spsr_el2, x30 // Saved Processor Status Register 32bit
b 4f
3:msr elr_el3, x29 // Exception Link Register
msr spsr_el3, x30 // Saved Processor Status Register 32bit
4:
// pop remaining GP regs and return from exception.
ldr x30, [sp, #0xf0 - 0xe0]
ldp x28, x29, [sp], #GP_CONTEXT_SIZE - 0xe0
// Adjust SP to be where we started from when we came into the handler.
// The handler can not change the SP.
add sp, sp, #FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE
eret