1/* SPDX-License-Identifier: GPL-2.0-only */ 2 3/* 4 * transition_asm.S: This file handles the entry and exit from an exception 5 * 6 * Flow: exception --> exc_vectors --> exc_entry --> exc_dispatch --> 7 * exc_exit 8 * Transition Flow: transition --> trans_switch --> exc_exit 9 * 10 * |---| Exception Entry |---| 11 * 12 * On exception entry, it saves all the xregs on SP_ELx since SP_ELx is 13 * selected on entry. Some dummy pushes are performed to create space for 14 * elx_state structure. It then passes pointer to this saved set of regs and 15 * a unique id(for identifying exception) to exc_entry. 16 * 17 * |---| Exception Transition Dispatch |---| 18 * 19 * This is the C-component of exception entry. It does the work of initializing 20 * the exc_state registers. Finally it calls exception dispatch implemented by 21 * the user. This is point of no-return. 22 * 23 * |---| Exception Dispatch |---| 24 * 25 * User of this functionality is expected to implement exc_dispatch which 26 * acts as entry point for it. Once exception handling is complete, the user 27 * needs to call exc_exit with pointer to struct regs. 28 * 29 * |---| Exception Exit |---| 30 * 31 * Once exc_dispatch is done with handling the exception based on the id passed 32 * to it, it needs to call exc_exit with pointer to struct regs. This is done to 33 * unwind the exception stack by popping off all the xregs. 34 * 35 * |---| Exception Transition Exit |---| 36 * 37 * This routine makes SP_EL0 point to the regs structure passed and continues 38 * onto the exception exit routine described above. This is the reason that 39 * transition library does not handle initialization of SP_EL0 for the program 40 * to be executed. 41 */ 42 43#include <arch/asm.h> 44#include <arch/lib_helpers.h> 45#include <arch/transition.h> 46 47.macro eentry lbl id 48 .align 7 49\lbl: 50 stp x29, x30, [sp, #STACK_PUSH_BYTES]! 51 bl exc_prologue 52 mov x1, \id 53 mov x0, sp 54 b exc_entry 55.endm 56 57/* 58 * exc_vectors: Entry point for an exception 59 */ 60ENTRY_WITH_ALIGN(exc_vectors, 11) 61 62eentry sync_curr_sp0, #EXC_VID_CUR_SP_EL0_SYNC 63eentry irq_curr_sp0, #EXC_VID_CUR_SP_EL0_IRQ 64eentry fiq_curr_sp0, #EXC_VID_CUR_SP_EL0_FIRQ 65eentry serror_curr_sp0, #EXC_VID_CUR_SP_EL0_SERR 66eentry sync_curr_spx, #EXC_VID_CUR_SP_ELX_SYNC 67eentry irq_curr_spx, #EXC_VID_CUR_SP_ELX_IRQ 68eentry fiq_curr_spx, #EXC_VID_CUR_SP_ELX_FIQ 69eentry serror_curr_spx, #EXC_VID_CUR_SP_ELX_SERR 70eentry sync_lower_64, #EXC_VID_LOW64_SYNC 71eentry irq_lower_64, #EXC_VID_LOW64_IRQ 72eentry fiq_lower_64, #EXC_VID_LOW64_FIQ 73eentry serror_lower_64, #EXC_VID_LOW64_SERR 74eentry sync_lower_32, #EXC_VID_LOW32_SYNC 75eentry irq_lower_32, #EXC_VID_LOW32_IRQ 76eentry fiq_lower_32, #EXC_VID_LOW32_FIQ 77eentry serror_lower_32, #EXC_VID_LOW32_SERR 78 79ENDPROC(exc_vectors) 80 81ENTRY(exc_prologue) 82 stp x27, x28, [sp, #STACK_PUSH_BYTES]! 83 stp x25, x26, [sp, #STACK_PUSH_BYTES]! 84 stp x23, x24, [sp, #STACK_PUSH_BYTES]! 85 stp x21, x22, [sp, #STACK_PUSH_BYTES]! 86 stp x19, x20, [sp, #STACK_PUSH_BYTES]! 87 stp x17, x18, [sp, #STACK_PUSH_BYTES]! 88 stp x15, x16, [sp, #STACK_PUSH_BYTES]! 89 stp x13, x14, [sp, #STACK_PUSH_BYTES]! 90 stp x11, x12, [sp, #STACK_PUSH_BYTES]! 91 stp x9, x10, [sp, #STACK_PUSH_BYTES]! 92 stp x7, x8, [sp, #STACK_PUSH_BYTES]! 93 stp x5, x6, [sp, #STACK_PUSH_BYTES]! 94 stp x3, x4, [sp, #STACK_PUSH_BYTES]! 95 stp x1, x2, [sp, #STACK_PUSH_BYTES]! 96 /* xzr pushed as place holder for sp */ 97 stp xzr, x0, [sp, #STACK_PUSH_BYTES]! 98 /* 99 * xzr pushed as place holder for: 100 * 1. sp_elx and elr 101 */ 102 stp xzr, xzr, [sp, #STACK_PUSH_BYTES]! 103 /* 2. spsr and sp_el0 */ 104 stp xzr, xzr, [sp, #STACK_PUSH_BYTES]! 105 ret 106ENDPROC(exc_prologue) 107 108/* 109 * trans_switch: Set SPSel to use SP_EL0 110 * x0 = regs structure 111 */ 112ENTRY(trans_switch) 113 msr SPSel, #SPSR_USE_L 114 b exc_exit 115ENDPROC(trans_switch) 116 117/* 118 * exc_exit: Return from exception by restoring saved state of xregs 119 * x0 = regs structure 120 */ 121ENTRY(exc_exit) 122 /* Unwind the stack by making sp point to regs structure */ 123 mov sp, x0 124 /* Load registers x0-x30 */ 125 ldp xzr, x0, [sp], #STACK_POP_BYTES 126 ldp x1, x2, [sp], #STACK_POP_BYTES 127 ldp x3, x4, [sp], #STACK_POP_BYTES 128 ldp x5, x6, [sp], #STACK_POP_BYTES 129 ldp x7, x8, [sp], #STACK_POP_BYTES 130 ldp x9, x10, [sp], #STACK_POP_BYTES 131 ldp x11, x12, [sp], #STACK_POP_BYTES 132 ldp x13, x14, [sp], #STACK_POP_BYTES 133 ldp x15, x16, [sp], #STACK_POP_BYTES 134 ldp x17, x18, [sp], #STACK_POP_BYTES 135 ldp x19, x20, [sp], #STACK_POP_BYTES 136 ldp x21, x22, [sp], #STACK_POP_BYTES 137 ldp x23, x24, [sp], #STACK_POP_BYTES 138 ldp x25, x26, [sp], #STACK_POP_BYTES 139 ldp x27, x28, [sp], #STACK_POP_BYTES 140 ldp x29, x30, [sp], #STACK_POP_BYTES 141 eret 142ENDPROC(exc_exit) 143 144/* 145 * exception_init_asm: Initialize VBAR and point SP_ELx to exception stack. 146 * Also unmask aborts now that we can report them. x0 = end of exception stack 147 */ 148ENTRY(exception_init_asm) 149 msr SPSel, #SPSR_USE_H 150 mov sp, x0 151 msr SPSel, #SPSR_USE_L 152 adr x0, exc_vectors 153 msr CURRENT_EL(vbar), x0 154 msr DAIFClr, #0xf 155 dsb sy 156 isb 157 ret 158ENDPROC(exception_init_asm) 159