| /* SPDX-License-Identifier: GPL-2.0 */ |
| .macro save_registers |
| add sp, sp, #-16 * 17 |
| |
| stp x0, x1, [sp, #16 * 0] |
| stp x2, x3, [sp, #16 * 1] |
| stp x4, x5, [sp, #16 * 2] |
| stp x6, x7, [sp, #16 * 3] |
| stp x8, x9, [sp, #16 * 4] |
| stp x10, x11, [sp, #16 * 5] |
| stp x12, x13, [sp, #16 * 6] |
| stp x14, x15, [sp, #16 * 7] |
| stp x16, x17, [sp, #16 * 8] |
| stp x18, x19, [sp, #16 * 9] |
| stp x20, x21, [sp, #16 * 10] |
| stp x22, x23, [sp, #16 * 11] |
| stp x24, x25, [sp, #16 * 12] |
| stp x26, x27, [sp, #16 * 13] |
| stp x28, x29, [sp, #16 * 14] |
| |
| /* |
| * This stores sp_el1 into ex_regs.sp so exception handlers can "look" |
| * at it. It will _not_ be used to restore the sp on return from the |
| * exception so handlers can not update it. |
| */ |
| add x1, sp, #16 * 17 |
| stp x30, x1, [sp, #16 * 15] /* x30, SP */ |
| |
| mrs x1, elr_el1 |
| mrs x2, spsr_el1 |
| stp x1, x2, [sp, #16 * 16] /* PC, PSTATE */ |
| .endm |
| |
| .macro restore_registers |
| ldp x1, x2, [sp, #16 * 16] /* PC, PSTATE */ |
| msr elr_el1, x1 |
| msr spsr_el1, x2 |
| |
| /* sp is not restored */ |
| ldp x30, xzr, [sp, #16 * 15] /* x30, SP */ |
| |
| ldp x28, x29, [sp, #16 * 14] |
| ldp x26, x27, [sp, #16 * 13] |
| ldp x24, x25, [sp, #16 * 12] |
| ldp x22, x23, [sp, #16 * 11] |
| ldp x20, x21, [sp, #16 * 10] |
| ldp x18, x19, [sp, #16 * 9] |
| ldp x16, x17, [sp, #16 * 8] |
| ldp x14, x15, [sp, #16 * 7] |
| ldp x12, x13, [sp, #16 * 6] |
| ldp x10, x11, [sp, #16 * 5] |
| ldp x8, x9, [sp, #16 * 4] |
| ldp x6, x7, [sp, #16 * 3] |
| ldp x4, x5, [sp, #16 * 2] |
| ldp x2, x3, [sp, #16 * 1] |
| ldp x0, x1, [sp, #16 * 0] |
| |
| add sp, sp, #16 * 17 |
| |
| eret |
| .endm |
| |
| .pushsection ".entry.text", "ax" |
| .balign 0x800 |
| .global vectors |
| vectors: |
| .popsection |
| |
| .set vector, 0 |
| |
| /* |
| * Build an exception handler for vector and append a jump to it into |
| * vectors (while making sure that it's 0x80 aligned). |
| */ |
| .macro HANDLER, label |
| handler_\label: |
| save_registers |
| mov x0, sp |
| mov x1, #vector |
| bl route_exception |
| restore_registers |
| |
| .pushsection ".entry.text", "ax" |
| .balign 0x80 |
| b handler_\label |
| .popsection |
| |
| .set vector, vector + 1 |
| .endm |
| |
| .macro HANDLER_INVALID |
| .pushsection ".entry.text", "ax" |
| .balign 0x80 |
| /* This will abort so no need to save and restore registers. */ |
| mov x0, #vector |
| mov x1, #0 /* ec */ |
| mov x2, #0 /* valid_ec */ |
| b kvm_exit_unexpected_exception |
| .popsection |
| |
| .set vector, vector + 1 |
| .endm |
| |
| /* |
| * Caution: be sure to not add anything between the declaration of vectors |
| * above and these macro calls that will build the vectors table below it. |
| */ |
| HANDLER_INVALID // Synchronous EL1t |
| HANDLER_INVALID // IRQ EL1t |
| HANDLER_INVALID // FIQ EL1t |
| HANDLER_INVALID // Error EL1t |
| |
| HANDLER el1h_sync // Synchronous EL1h |
| HANDLER el1h_irq // IRQ EL1h |
| HANDLER el1h_fiq // FIQ EL1h |
| HANDLER el1h_error // Error EL1h |
| |
| HANDLER el0_sync_64 // Synchronous 64-bit EL0 |
| HANDLER el0_irq_64 // IRQ 64-bit EL0 |
| HANDLER el0_fiq_64 // FIQ 64-bit EL0 |
| HANDLER el0_error_64 // Error 64-bit EL0 |
| |
| HANDLER el0_sync_32 // Synchronous 32-bit EL0 |
| HANDLER el0_irq_32 // IRQ 32-bit EL0 |
| HANDLER el0_fiq_32 // FIQ 32-bit EL0 |
| HANDLER el0_error_32 // Error 32-bit EL0 |