mirror of https://github.com/acidanthera/audk.git
ArmPkg/ArmExceptionLib: reimplement register stack/unstack routines
This replaces the somewhat opaque preprocessor based stack/unstack macros with open coded ldp/stp sequences to preserve the interrupted context before handing over to the exception handler in C. This removes various arithmetic operations on the stack pointer, and reduces the exception return critical section to its minimum size (i.e., the bare minimum required to populate the ELR and SPSR registers and invoke the eret). Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org> Reviewed-by: Eugene Cohen <eugene@hp.com>
This commit is contained in:
parent
5d7238cae8
commit
1b02a38329
|
@ -107,54 +107,6 @@ GCC_ASM_EXPORT(CommonCExceptionHandler)
|
||||||
#define FP_CONTEXT_SIZE (32 * 16)
|
#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)
|
#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);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// There are two methods for installing AArch64 exception vectors:
|
// There are two methods for installing AArch64 exception vectors:
|
||||||
// 1. Install a copy of the vectors to a location specified by a PCD
|
// 1. Install a copy of the vectors to a location specified by a PCD
|
||||||
|
@ -170,18 +122,35 @@ ASM_PFX(ExceptionHandlersStart):
|
||||||
VECTOR_BASE(ExceptionHandlersStart)
|
VECTOR_BASE(ExceptionHandlersStart)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#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)]
|
|
||||||
|
|
||||||
.macro ExceptionEntry, val
|
.macro ExceptionEntry, val
|
||||||
// Move the stackpointer so we can reach our structure with the str instruction.
|
// Move the stackpointer so we can reach our structure with the str instruction.
|
||||||
sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
|
sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
|
||||||
|
|
||||||
// Save all the General regs before touching x0 and x1.
|
// Push some GP registers so we can record the exception context
|
||||||
// This does not save r31(SP) as it is special. We do that later.
|
stp x0, x1, [sp, #-GP_CONTEXT_SIZE]!
|
||||||
ALL_GP_REGS
|
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.
|
// Record the type of exception that occurred.
|
||||||
mov x0, #\val
|
mov x0, #\val
|
||||||
|
@ -278,49 +247,44 @@ ASM_PFX(ExceptionHandlersEnd):
|
||||||
|
|
||||||
|
|
||||||
ASM_PFX(CommonExceptionEntry):
|
ASM_PFX(CommonExceptionEntry):
|
||||||
/* 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.
|
// Stack the remaining GP registers
|
||||||
SAVE_SP
|
stp x8, x9, [sp, #0x40]
|
||||||
|
stp x10, x11, [sp, #0x50]
|
||||||
// Preserve the stack pointer we came in with before we modify it
|
stp x12, x13, [sp, #0x60]
|
||||||
EL1_OR_EL2_OR_EL3(x1)
|
stp x14, x15, [sp, #0x70]
|
||||||
1:mrs x1, elr_el1 // Exception Link Register
|
stp x16, x17, [sp, #0x80]
|
||||||
mrs x2, spsr_el1 // Saved Processor Status Register 32bit
|
stp x18, x19, [sp, #0x90]
|
||||||
mrs x4, esr_el1 // EL1 Exception syndrome register 32bit
|
stp x20, x21, [sp, #0xa0]
|
||||||
mrs x5, far_el1 // EL1 Fault Address Register
|
stp x22, x23, [sp, #0xb0]
|
||||||
b 4f
|
stp x24, x25, [sp, #0xc0]
|
||||||
|
stp x26, x27, [sp, #0xd0]
|
||||||
2:mrs x1, elr_el2 // Exception Link Register
|
stp x28, x29, [sp, #0xe0]
|
||||||
mrs x2, spsr_el2 // Saved Processor Status Register 32bit
|
add x28, sp, #GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE
|
||||||
mrs x4, esr_el2 // EL2 Exception syndrome register 32bit
|
stp x30, x28, [sp, #0xf0]
|
||||||
mrs x5, far_el2 // EL2 Fault Address Register
|
|
||||||
b 4f
|
|
||||||
|
|
||||||
3:mrs x1, elr_el3 // Exception Link Register
|
|
||||||
mrs x2, spsr_el3 // Saved Processor Status Register 32bit
|
|
||||||
mrs x4, esr_el3 // EL3 Exception syndrome register 32bit
|
|
||||||
mrs x5, far_el3 // EL3 Fault Address Register
|
|
||||||
|
|
||||||
4:mrs x3, fpsr // Floating point Status Register 32bit
|
|
||||||
|
|
||||||
// Adjust SP to save next set
|
|
||||||
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
|
// Save the SYS regs
|
||||||
ALL_SYS_REGS
|
stp x2, x3, [x28, #-SYS_CONTEXT_SIZE]!
|
||||||
|
stp x4, x5, [x28, #0x10]
|
||||||
|
str x6, [x28, #0x20]
|
||||||
|
|
||||||
// Point to top of struct after all regs saved
|
// Push FP regs to Stack.
|
||||||
sub sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
|
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.
|
// x0 still holds the exception type.
|
||||||
// Set x1 to point to the top of our struct on the Stack
|
// Set x1 to point to the top of our struct on the Stack
|
||||||
|
@ -337,13 +301,44 @@ ASM_PFX(CommonExceptionEntry):
|
||||||
// We do not try to recover.
|
// We do not try to recover.
|
||||||
bl ASM_PFX(CommonCExceptionHandler) // Call exception handler
|
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
|
||||||
|
|
||||||
// Defines for popping from stack
|
// 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
|
||||||
|
|
||||||
#undef REG_PAIR
|
// Pop the SYS regs we need
|
||||||
#undef REG_ONE
|
ldp x29, x30, [x28]
|
||||||
#define REG_PAIR(REG1, REG2, OFFSET, CONTEXT_SIZE) ldp REG1, REG2, [sp, #(OFFSET-CONTEXT_SIZE)]
|
ldr x28, [x28, #0x10]
|
||||||
#define REG_ONE(REG1, OFFSET, CONTEXT_SIZE) ldur REG1, [sp, #(OFFSET-CONTEXT_SIZE)]
|
msr fpsr, x28
|
||||||
|
|
||||||
//
|
//
|
||||||
// Disable interrupt(IRQ and FIQ) before restoring context,
|
// Disable interrupt(IRQ and FIQ) before restoring context,
|
||||||
|
@ -353,35 +348,23 @@ ASM_PFX(CommonExceptionEntry):
|
||||||
msr daifset, #3
|
msr daifset, #3
|
||||||
isb
|
isb
|
||||||
|
|
||||||
// Adjust SP to pop system registers
|
EL1_OR_EL2_OR_EL3(x28)
|
||||||
add sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
|
1:msr elr_el1, x29 // Exception Link Register
|
||||||
ALL_SYS_REGS
|
msr spsr_el1, x30 // Saved Processor Status Register 32bit
|
||||||
|
|
||||||
EL1_OR_EL2_OR_EL3(x6)
|
|
||||||
1:msr elr_el1, x1 // Exception Link Register
|
|
||||||
msr spsr_el1,x2 // Saved Processor Status Register 32bit
|
|
||||||
b 4f
|
b 4f
|
||||||
2:msr elr_el2, x1 // Exception Link Register
|
2:msr elr_el2, x29 // Exception Link Register
|
||||||
msr spsr_el2,x2 // Saved Processor Status Register 32bit
|
msr spsr_el2, x30 // Saved Processor Status Register 32bit
|
||||||
b 4f
|
b 4f
|
||||||
3:msr elr_el3, x1 // Exception Link Register
|
3:msr elr_el3, x29 // Exception Link Register
|
||||||
msr spsr_el3,x2 // Saved Processor Status Register 32bit
|
msr spsr_el3, x30 // Saved Processor Status Register 32bit
|
||||||
4:msr fpsr, x3 // Floating point Status Register 32bit
|
4:
|
||||||
|
|
||||||
// pop all regs and return from exception.
|
// pop remaining GP regs and return from exception.
|
||||||
sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE)
|
ldr x30, [sp, #0xf0 - 0xe0]
|
||||||
ALL_GP_REGS
|
ldp x28, x29, [sp], #GP_CONTEXT_SIZE - 0xe0
|
||||||
|
|
||||||
// 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.
|
// Adjust SP to be where we started from when we came into the handler.
|
||||||
// The handler can not change the SP.
|
// The handler can not change the SP.
|
||||||
add sp, sp, #SYS_CONTEXT_SIZE
|
add sp, sp, #FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE
|
||||||
|
|
||||||
eret
|
eret
|
||||||
|
|
||||||
#undef REG_PAIR
|
|
||||||
#undef REG_ONE
|
|
||||||
|
|
Loading…
Reference in New Issue