You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
5.8 KiB
ArmAsm
191 lines
5.8 KiB
ArmAsm
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
//
|
|
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Definitions
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
/// Call the function provided by parameter `\handler` after saving the exception context. Provide
|
|
/// the context as the first parameter to '\handler'.
|
|
.macro CALL_WITH_CONTEXT handler is_lower_el is_sync
|
|
__vector_\handler:
|
|
// Make room on the stack for the exception context.
|
|
sub sp, sp, #16 * 18
|
|
|
|
// Store all general purpose registers on the stack.
|
|
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]
|
|
|
|
// Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
|
|
// syndrome register (ESR_EL1).
|
|
mrs x1, ELR_EL1
|
|
mrs x2, SPSR_EL1
|
|
mrs x3, ESR_EL1
|
|
|
|
stp lr, x1, [sp, #16 * 15]
|
|
stp x2, x3, [sp, #16 * 16]
|
|
|
|
// Build a stack frame for backtracing.
|
|
.if \is_lower_el == 1
|
|
// If we came from a lower EL, make it a root frame (by storing zero) so that the kernel
|
|
// does not attempt to trace into userspace.
|
|
stp xzr, xzr, [sp, #16 * 17]
|
|
.else
|
|
// For normal branches, the link address points to the instruction to be executed _after_
|
|
// returning from a branch. In a backtrace, we want to show the instruction that caused the
|
|
// branch, though. That is why code in backtrace.rs subtracts 4 (length of one instruction)
|
|
// from the link address.
|
|
//
|
|
// Here we have a special case, though, because ELR_EL1 is used instead of LR to build the
|
|
// stack frame, so that it becomes possible to trace beyond an exception. Hence, it must be
|
|
// considered that semantics for ELR_EL1 differ from case to case.
|
|
//
|
|
// Unless an "exception generating instruction" was executed, ELR_EL1 already points to the
|
|
// the correct instruction, and hence the subtraction by 4 in backtrace.rs would yield wrong
|
|
// results. To cover for this, 4 is added to ELR_EL1 below unless the cause of exception was
|
|
// an SVC instruction. BRK and HLT are "exception generating instructions" as well, but they
|
|
// are not expected and therefore left out for now.
|
|
//
|
|
// For reference: Search for "preferred exception return address" in the Architecture
|
|
// Reference Manual for ARMv8-A.
|
|
.if \is_sync == 1
|
|
lsr w3, w3, {CONST_ESR_EL1_EC_SHIFT} // w3 = ESR_EL1.EC
|
|
cmp w3, {CONST_ESR_EL1_EC_VALUE_SVC64} // w3 == SVC64 ?
|
|
b.eq 1f
|
|
.endif
|
|
add x1, x1, #4
|
|
1:
|
|
stp x29, x1, [sp, #16 * 17]
|
|
.endif
|
|
|
|
// Set the frame pointer to the stack frame record.
|
|
add x29, sp, #16 * 17
|
|
|
|
// x0 is the first argument for the function called through `\handler`.
|
|
mov x0, sp
|
|
|
|
// Call `\handler`.
|
|
bl \handler
|
|
|
|
// After returning from exception handling code, replay the saved context and return via
|
|
// `eret`.
|
|
b __exception_restore_context
|
|
|
|
.size __vector_\handler, . - __vector_\handler
|
|
.type __vector_\handler, function
|
|
.endm
|
|
|
|
.macro FIQ_SUSPEND
|
|
1: wfe
|
|
b 1b
|
|
.endm
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Private Code
|
|
//--------------------------------------------------------------------------------------------------
|
|
.section .text
|
|
|
|
//------------------------------------------------------------------------------
|
|
// The exception vector table.
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Align by 2^11 bytes, as demanded by ARMv8-A. Same as ALIGN(2048) in an ld script.
|
|
.align 11
|
|
|
|
// Export a symbol for the Rust code to use.
|
|
__exception_vector_start:
|
|
|
|
// Current exception level with SP_EL0.
|
|
//
|
|
// .org sets the offset relative to section start.
|
|
//
|
|
// # Safety
|
|
//
|
|
// - It must be ensured that `CALL_WITH_CONTEXT` <= 0x80 bytes.
|
|
.org 0x000
|
|
CALL_WITH_CONTEXT current_el0_synchronous, 0, 1
|
|
.org 0x080
|
|
CALL_WITH_CONTEXT current_el0_irq, 0, 0
|
|
.org 0x100
|
|
FIQ_SUSPEND
|
|
.org 0x180
|
|
CALL_WITH_CONTEXT current_el0_serror, 0, 0
|
|
|
|
// Current exception level with SP_ELx, x > 0.
|
|
.org 0x200
|
|
CALL_WITH_CONTEXT current_elx_synchronous, 0, 1
|
|
.org 0x280
|
|
CALL_WITH_CONTEXT current_elx_irq, 0, 0
|
|
.org 0x300
|
|
FIQ_SUSPEND
|
|
.org 0x380
|
|
CALL_WITH_CONTEXT current_elx_serror, 0, 0
|
|
|
|
// Lower exception level, AArch64
|
|
.org 0x400
|
|
CALL_WITH_CONTEXT lower_aarch64_synchronous, 1, 1
|
|
.org 0x480
|
|
CALL_WITH_CONTEXT lower_aarch64_irq, 1, 0
|
|
.org 0x500
|
|
FIQ_SUSPEND
|
|
.org 0x580
|
|
CALL_WITH_CONTEXT lower_aarch64_serror, 1, 0
|
|
|
|
// Lower exception level, AArch32
|
|
.org 0x600
|
|
CALL_WITH_CONTEXT lower_aarch32_synchronous, 1, 0
|
|
.org 0x680
|
|
CALL_WITH_CONTEXT lower_aarch32_irq, 1, 0
|
|
.org 0x700
|
|
FIQ_SUSPEND
|
|
.org 0x780
|
|
CALL_WITH_CONTEXT lower_aarch32_serror, 1, 0
|
|
.org 0x800
|
|
|
|
//------------------------------------------------------------------------------
|
|
// fn __exception_restore_context()
|
|
//------------------------------------------------------------------------------
|
|
__exception_restore_context:
|
|
ldr w19, [sp, #16 * 16]
|
|
ldp lr, x20, [sp, #16 * 15]
|
|
|
|
msr SPSR_EL1, x19
|
|
msr ELR_EL1, x20
|
|
|
|
ldp x0, x1, [sp, #16 * 0]
|
|
ldp x2, x3, [sp, #16 * 1]
|
|
ldp x4, x5, [sp, #16 * 2]
|
|
ldp x6, x7, [sp, #16 * 3]
|
|
ldp x8, x9, [sp, #16 * 4]
|
|
ldp x10, x11, [sp, #16 * 5]
|
|
ldp x12, x13, [sp, #16 * 6]
|
|
ldp x14, x15, [sp, #16 * 7]
|
|
ldp x16, x17, [sp, #16 * 8]
|
|
ldp x18, x19, [sp, #16 * 9]
|
|
ldp x20, x21, [sp, #16 * 10]
|
|
ldp x22, x23, [sp, #16 * 11]
|
|
ldp x24, x25, [sp, #16 * 12]
|
|
ldp x26, x27, [sp, #16 * 13]
|
|
ldp x28, x29, [sp, #16 * 14]
|
|
|
|
add sp, sp, #16 * 18
|
|
|
|
eret
|
|
|
|
.size __exception_restore_context, . - __exception_restore_context
|
|
.type __exception_restore_context, function
|