root/tools/testing/selftests/kvm/lib/arm64/handlers.S
/* 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