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.biesheu...@linaro.org> --- ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S | 235 +++++++++----------- 1 file changed, 109 insertions(+), 126 deletions(-) diff --git a/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S b/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S index 0fd304db2dbf..fef7d908c1cc 100644 --- a/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S +++ b/ArmPkg/Library/ArmExceptionLib/AArch64/ExceptionSupport.S @@ -107,54 +107,6 @@ GCC_ASM_EXPORT(CommonCExceptionHandler) #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); - // // There are two methods for installing AArch64 exception vectors: // 1. Install a copy of the vectors to a location specified by a PCD @@ -170,18 +122,35 @@ ASM_PFX(ExceptionHandlersStart): VECTOR_BASE(ExceptionHandlersStart) #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 // 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 + // 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 @@ -278,49 +247,44 @@ ASM_PFX(ExceptionHandlersEnd): 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. - SAVE_SP - - // Preserve the stack pointer we came in with before we modify it - EL1_OR_EL2_OR_EL3(x1) -1:mrs x1, elr_el1 // Exception Link Register - mrs x2, spsr_el1 // Saved Processor Status Register 32bit - mrs x4, esr_el1 // EL1 Exception syndrome register 32bit - mrs x5, far_el1 // EL1 Fault Address Register - b 4f -2:mrs x1, elr_el2 // Exception Link Register - mrs x2, spsr_el2 // Saved Processor Status Register 32bit - mrs x4, esr_el2 // EL2 Exception syndrome register 32bit - 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 + // 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 - 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 - sub sp, sp, #(GP_CONTEXT_SIZE + FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE) + // 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 @@ -337,13 +301,44 @@ ASM_PFX(CommonExceptionEntry): // 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)] + // 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, @@ -353,35 +348,23 @@ ASM_PFX(CommonExceptionEntry): 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_OR_EL3(x6) -1:msr elr_el1, x1 // Exception Link Register - msr spsr_el1,x2 // Saved Processor Status Register 32bit + 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, x1 // Exception Link Register - msr spsr_el2,x2 // Saved Processor Status Register 32bit +2:msr elr_el2, x29 // Exception Link Register + msr spsr_el2,x30 // Saved Processor Status Register 32bit b 4f -3:msr elr_el3, x1 // Exception Link Register - msr spsr_el3,x2 // Saved Processor Status Register 32bit -4:msr fpsr, x3 // Floating point Status Register 32bit - - // pop all regs and return from exception. - sub sp, sp, #(FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE) - ALL_GP_REGS +3:msr elr_el3, x29 // Exception Link Register + msr spsr_el3,x30 // Saved Processor Status Register 32bit +4: - // Adjust SP to pop next set - add sp, sp, #FP_CONTEXT_SIZE - // Pop FP regs to Stack. - ALL_FP_REGS + // pop remaining GP regs and return from exception. + ldr x30, [sp, #GP_CONTEXT_SIZE - 0xf0] + 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, #SYS_CONTEXT_SIZE + add sp, sp, #FP_CONTEXT_SIZE + SYS_CONTEXT_SIZE eret - -#undef REG_PAIR -#undef REG_ONE -- 2.5.0 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel