From 6029b49a81b83d0ff216e0607bb59c20880b7b04 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Sat, 4 Jul 2026 23:26:09 +0100 Subject: [PATCH] I've tried to make sure every asm handler routine: 1. Numbers all the steps it takes on entry 2. Matches those numbered steps on exit 3. Uses `// Initial capital letter` for the comments 4. Has a consistent comment for any particular piece of assembly when used across handlers 5. If you need to do an `ldmfd sp!` on exit (usually because that variant can restore `SPSR` to `CPSR`), use matching `stmfd sp!` on entry, even if a `push` would do the same thing - just for consistency and to make the pairing obvious. 6. Removed references to chapters of the ARM ARM ARM, because the right ARM ARM ARM depends on which target you are building. 7. Talks about pushing and popping with the stack, or grabbing and restoring with MRS/MSR Also, doing a `and r12, sp, 7` does it in one instruction whereas before I sometimes used two. --- aarch32-rt/src/arch_v4/abort.rs | 60 ++++++++++++------------- aarch32-rt/src/arch_v4/interrupt.rs | 32 ++++++------- aarch32-rt/src/arch_v4/svc.rs | 32 ++++++------- aarch32-rt/src/arch_v4/undefined.rs | 28 ++++++------ aarch32-rt/src/arch_v7/abort.rs | 53 +++++++++++----------- aarch32-rt/src/arch_v7/hvc.rs | 16 +++---- aarch32-rt/src/arch_v7/interrupt.rs | 22 ++++----- aarch32-rt/src/arch_v7/svc.rs | 28 ++++++------ aarch32-rt/src/arch_v7/undefined.rs | 26 +++++------ aarch32-rt/src/arch_v8_hyp/abort.rs | 48 +++++++++----------- aarch32-rt/src/arch_v8_hyp/hvc.rs | 37 ++++++++------- aarch32-rt/src/arch_v8_hyp/interrupt.rs | 23 +++++----- aarch32-rt/src/arch_v8_hyp/svc.rs | 37 ++++++++------- aarch32-rt/src/arch_v8_hyp/undefined.rs | 24 +++++----- 14 files changed, 228 insertions(+), 238 deletions(-) diff --git a/aarch32-rt/src/arch_v4/abort.rs b/aarch32-rt/src/arch_v4/abort.rs index 20b46f40..c2caa8f1 100644 --- a/aarch32-rt/src/arch_v4/abort.rs +++ b/aarch32-rt/src/arch_v4/abort.rs @@ -13,28 +13,28 @@ core::arch::global_asm!( .global _asm_default_data_abort_handler .type _asm_default_data_abort_handler, %function _asm_default_data_abort_handler: - sub lr, lr, #8 // Subtract 8 from LR, see p.1214 of the ARMv7-A architecture manual. - push {{ r12 }} // Save preserved register R12 - can now use it - mrs r12, spsr // grab SPSR - push {{ r12 }} // save SPSR value - and r12, sp, 7 // align SP down to eight byte boundary using R12 - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r4, r12 }} // push alignment amount, and preserved registers - can now use R0-R3 (R4 is just padding) + sub lr, lr, #8 // Make sure we jump back to the right place + push {{ r12 }} // Push preserved register R12 (1) + mrs r12, spsr // Grab SPSR (2) + push {{ r12 }} // Push SPSR value (3) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (4) + push {{ r0-r4, r12 }} // Push preserved registers and alignment amount (R4 is just padding) (5) "#, crate::fpu_context!("save"), r#" mov r0, lr // Pass the faulting instruction address to the handler. - bl _data_abort_handler // call C handler - mov lr, r0 // if we get back here, assume they returned a new LR in r0 + bl _data_abort_handler // Call C handler + mov lr, r0 // If we get back here, assume they returned a new LR in r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r4, r12 }} // restore preserved registers, dummy value, and alignment amount - add sp, r12 // restore SP alignment using R12 - pop {{ r12 }} // restore SPSR using R12 - msr spsr, r12 // - pop {{ r12 }} // restore R12 - movs pc, lr // return from exception + pop {{ r0-r4, r12 }} // Pop preserved registers, dummy value, and alignment amount to undo (5) + add sp, r12 // Restore SP alignment using R12 to undo (4) + pop {{ r12 }} // Pop saved SPSR value to undo (3) + msr spsr, r12 // Restore SPSR using R12 to undo (2) + pop {{ r12 }} // Pop R12 to undo (1) + movs pc, lr // Return from exception .size _asm_default_data_abort_handler, . - _asm_default_data_abort_handler .popsection "# @@ -53,28 +53,28 @@ core::arch::global_asm!( .global _asm_default_prefetch_abort_handler .type _asm_default_prefetch_abort_handler, %function _asm_default_prefetch_abort_handler: - sub lr, lr, #4 // Subtract 4 from LR, see p.1212 of the ARMv7-A architecture manual. - push {{ r12 }} // Save preserved register R12 - can now use it - mrs r12, spsr // grab SPSR - push {{ r12 }} // save SPSR value - and r12, sp, 7 // align SP down to eight byte boundary using R12 - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r4, r12 }} // push alignment amount, and preserved registers - can now use R0-R3 (R4 is just padding) + sub lr, lr, #4 // Make sure we jump back to the right place + push {{ r12 }} // Push preserved register R12 (1) + mrs r12, spsr // Grab SPSR (2) + push {{ r12 }} // Push SPSR value (3) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (4) + push {{ r0-r4, r12 }} // Push preserved registers and alignment amount (R4 is just padding) (5) "#, crate::fpu_context!("save"), r#" mov r0, lr // Pass the faulting instruction address to the handler. - bl _prefetch_abort_handler // call C handler - mov lr, r0 // if we get back here, assume they returned a new LR in r0 + bl _prefetch_abort_handler // Call C handler + mov lr, r0 // If we get back here, assume they returned a new LR in r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r4, r12 }} // restore preserved registers, dummy value, and alignment amount - add sp, r12 // restore SP alignment using R12 - pop {{ r12 }} // restore SPSR using R12 - msr spsr, r12 // - pop {{ r12 }} // restore R12 - movs pc, lr // return from exception + pop {{ r0-r4, r12 }} // Pop preserved registers, dummy value, and alignment amount to undo (5) + add sp, r12 // Restore SP alignment using R12 to undo (4) + pop {{ r12 }} // Grab saved SPSR to undo (3) + msr spsr, r12 // Restore SPSR using R12 to undo (2) + pop {{ r12 }} // Pop R12 to undo (1) + movs pc, lr // Return from exception .size _asm_default_prefetch_abort_handler, . - _asm_default_prefetch_abort_handler .popsection "#, diff --git a/aarch32-rt/src/arch_v4/interrupt.rs b/aarch32-rt/src/arch_v4/interrupt.rs index dd7f76ae..a1f73783 100644 --- a/aarch32-rt/src/arch_v4/interrupt.rs +++ b/aarch32-rt/src/arch_v4/interrupt.rs @@ -30,29 +30,29 @@ core::arch::global_asm!( .global _asm_default_irq_handler .type _asm_default_irq_handler, %function _asm_default_irq_handler: - sub lr, lr, 4 // make sure we jump back to the right place - stmfd sp!, {{ lr }} // save adjusted LR to IRQ stack (1) - mrs lr, spsr // The hardware has copied the interrupted task's CPSR to SPSR_irq - grab it (2) and - push {{ lr }} // save it to IRQ stack using LR (3) - msr cpsr_c, {handler_mode} // switch to handler mode (4) - push {{ lr }} // Save LR of handler mode before using it for stack alignment (5) - and lr, sp, 7 // align SP down to eight byte boundary using LR + sub lr, lr, 4 // Make sure we jump back to the right place + stmfd sp!, {{ lr }} // Save adjusted LR to IRQ stack (1) + mrs lr, spsr // Grab SPSR (2) + push {{ lr }} // Push SPSR value (3) + msr cpsr_c, {handler_mode} // Switch to handler mode (4) + push {{ lr }} // Push LR of handler mode before using it for stack alignment (5) + and lr, sp, 7 // Align SP down to eight byte boundary using LR sub sp, lr // SP now aligned - only push 64-bit values from here (6) - push {{ r0-r3, r12, lr }} // push alignment amount (in LR) and preserved registers (7) + push {{ r0-r3, r12, lr }} // Push preserved registers and alignment amount (7) "#, crate::fpu_context!("save"), r#" - bl _irq_handler // call C handler in the selected handler mode (they may choose to re-enable interrupts) + bl _irq_handler // Call C handler in the selected handler mode (they may choose to re-enable interrupts) "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r3, r12, lr }} // restore alignment amount (in LR) and preserved registers to undo (7) - add sp, lr // restore SP alignment using LR to undo (6) - pop {{ lr }} // Restore the actual link register of handler mode to undo (5) - msr cpsr_c, {irq_mode} // switch back to IRQ mode (with IRQ masked) to undo (4) - pop {{ lr }} // load SPSR to undo (3) - msr spsr, lr // restore SPSR to undo (2) - ldmfd sp!, {{ pc }}^ // return from exception (^ => restore SPSR to CPSR) to undo (1) + pop {{ r0-r3, r12, lr }} // Pop alignment amount (in LR) and preserved registers to undo (7) + add sp, lr // Restore SP alignment using LR to undo (6) + pop {{ lr }} // Pop the actual link register of handler mode to undo (5) + msr cpsr_c, {irq_mode} // Switch back to IRQ mode (with IRQ masked) to undo (4) + pop {{ lr }} // Grab saved SPSR to undo (3) + msr spsr, lr // Restore SPSR using LR to undo (2) + ldmfd sp!, {{ pc }}^ // Return from exception to undo (1) (^ => restore SPSR to CPSR) .size _asm_default_irq_handler, . - _asm_default_irq_handler .popsection "#, diff --git a/aarch32-rt/src/arch_v4/svc.rs b/aarch32-rt/src/arch_v4/svc.rs index 3148127a..531803bf 100644 --- a/aarch32-rt/src/arch_v4/svc.rs +++ b/aarch32-rt/src/arch_v4/svc.rs @@ -14,13 +14,13 @@ core::arch::global_asm!( .global _asm_default_svc_handler .type _asm_default_svc_handler, %function _asm_default_svc_handler: - push {{ r12, lr }} // save LR and R12 - can now use R12 (but leave LR alone for SVC code lookup) - mrs r12, spsr // grab SPSR using R12 - push {{ r12 }} // save SPSR value - and r12, sp, 7 // align SP down to eight byte boundary using R12 - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r6, r12 }} // push alignment amount, and stacked SVC argument registers (must be even number of regs for alignment) - mov r12, sp // save SP for integer frame + stmfd sp!, {{ r12, lr }} // Save LR and R12 (1) + mrs r12, spsr // Grab SPSR (2) + push {{ r12 }} // Push SPSR value (3) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (4) + push {{ r0-r6, r12 }} // Push SVC frame registers and alignment amount (5) + mov r12, sp // Save SP for integer frame "#, crate::fpu_context!("save"), r#" @@ -33,18 +33,18 @@ core::arch::global_asm!( ldr r0, [lr,#-4] // No: Load word and... bic r0, r0, #0xFF000000 // ...extract 3-byte immediate 2: - mov r1, r12 // pass the stacked integer registers in r1 - bl _svc_handler - mov lr, r0 // move r0 out of the way - restore_fpu_context will trash it + mov r1, r12 // Pass the stacked integer registers in r1 + bl _svc_handler // Call C handler in SVC mode + mov lr, r0 // Move r0 out of the way - restore_fpu_context will trash it "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r6, r12 }} // restore stacked registers and alignment amount - mov r0, lr // replace R0 with return value from _svc_handler - add sp, r12 // restore SP alignment using R12 - pop {{ lr }} // restore SPSR using LR - msr spsr, lr // - ldmfd sp!, {{ r12, pc }}^ // restore R12 and return from exception (^ => restore SPSR to CPSR) + pop {{ r0-r6, r12 }} // Pop SVC frame registers and alignment amount to undo (5) + mov r0, lr // Replace R0 with return value from _svc_handler + add sp, r12 // Restore SP alignment using R12 to undo (4) + pop {{ r12 }} // Grab saved SPSR to undo (3) + msr spsr, r12 // Restore SPSR using R12 to undo (2) + ldmfd sp!, {{ r12, pc }}^ // Restore R12 and return from exception (^ => restore SPSR to CPSR) to undo (1) .size _asm_default_svc_handler, . - _asm_default_svc_handler .popsection "#, diff --git a/aarch32-rt/src/arch_v4/undefined.rs b/aarch32-rt/src/arch_v4/undefined.rs index 32f09ae4..2d655ea3 100644 --- a/aarch32-rt/src/arch_v4/undefined.rs +++ b/aarch32-rt/src/arch_v4/undefined.rs @@ -16,31 +16,31 @@ core::arch::global_asm!( .global _asm_default_undefined_handler .type _asm_default_undefined_handler, %function _asm_default_undefined_handler: - push {{ r12 }} // save R12 - can now use it - mrs r12, spsr // grab SPSR using R12 - push {{ r12 }} // save SPSR value + push {{ r12 }} // Push preserved register R12 (1) + mrs r12, spsr // Grab SPSR (2) + push {{ r12 }} // Push SPSR value (3) tst r12, {t_bit} // Was the code that triggered the exception in Thumb state? ite eq // Adjust LR to point to faulting instruction - see p.1206 of the ARMv7-A architecture manual. subeq lr, lr, #4 // Subtract 4 in Arm Mode subne lr, lr, #2 // Subtract 2 in Thumb Mode - and r12, sp, 7 // align SP down to eight byte boundary using R12 - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r4, r12 }} // push alignment amount, and preserved registers - can now use R0-R3 (R4 is just padding) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (4) + push {{ r0-r4, r12 }} // Push alignment amount, and preserved registers (R4 is just padding) (5) "#, crate::fpu_context!("save"), r#" mov r0, lr // Pass the faulting instruction address to the handler. - bl _undefined_handler // call C handler - mov lr, r0 // if we get back here, assume they returned a new LR in r0 + bl _undefined_handler // Call C handler + mov lr, r0 // If we get back here, assume they returned a new LR in r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r4, r12 }} // restore preserved registers, dummy value, and alignment amount - add sp, r12 // restore SP alignment using R12 - pop {{ r12 }} // restore SPSR using R12 - msr spsr, r12 // - pop {{ r12 }} // restore R12 - movs pc, lr // return from exception (movs => restore SPSR to CPSR) + pop {{ r0-r4, r12 }} // Pop preserved registers, dummy value, and alignment amount to undo (5) + add sp, r12 // Restore SP alignment using R12 to undo (4) + pop {{ r12 }} // Grab saved SPSR to undo (3) + msr spsr, r12 // Restore SPSR using LR to undo (2) + pop {{ r12 }} // Pop R12 to undo (1) + movs pc, lr // Return from exception (movs => restore SPSR to CPSR) .size _asm_default_undefined_handler, . - _asm_default_undefined_handler .popsection "#, diff --git a/aarch32-rt/src/arch_v7/abort.rs b/aarch32-rt/src/arch_v7/abort.rs index bea94f0a..81875981 100644 --- a/aarch32-rt/src/arch_v7/abort.rs +++ b/aarch32-rt/src/arch_v7/abort.rs @@ -5,7 +5,6 @@ core::arch::global_asm!( // Work around https://github.com/rust-lang/rust/issues/127269 .fpu vfp3 - // Called from the vector table when we have an undefined exception. // Saves state and calls a C-compatible handler like // `extern "C" fn _data_abort_handler(addr: usize);` @@ -14,26 +13,26 @@ core::arch::global_asm!( .global _asm_default_data_abort_handler .type _asm_default_data_abort_handler, %function _asm_default_data_abort_handler: - sub lr, lr, #8 // Subtract 8 from LR, see p.1214 of the ARMv7-A architecture manual. - srsfd sp!, #{abt_mode} // store return state to ABT stack - push {{ r12 }} // Save preserved register R12 - can now use it - and r12, sp, 7 // align SP down to eight byte boundary using R12 - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r4, r12 }} // push alignment amount, and preserved registers - can now use R0-R3 (R4 is just padding) + sub lr, lr, #8 // Make sure we jump back to the right place + srsfd sp!, #{abt_mode} // Store return state to ABT stack (1) + push {{ r12 }} // Push preserved register R12 (2) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (3) + push {{ r0-r4, r12 }} // Push alignment amount, and preserved registers (R4 is just padding) (4) "#, crate::fpu_context!("save"), r#" mov r0, lr // Pass the faulting instruction address to the handler. - bl _data_abort_handler // call C handler - mov lr, r0 // if we get back here, assume they returned a new LR in r0 + bl _data_abort_handler // Call C handler + mov lr, r0 // If we get back here, assume they returned a new LR in r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r4, r12 }} // restore preserved registers, dummy value, and alignment amount - add sp, r12 // restore SP alignment using R12 - pop {{ r12 }} // restore R12 - str lr, [sp] // overwrite the saved LR with the one from the C handler - rfefd sp! // return from exception + pop {{ r0-r4, r12 }} // Pop preserved registers, dummy value, and alignment amount to undo (4) + add sp, r12 // Restore SP alignment using R12 to undo (3) + pop {{ r12 }} // Pop R12 to undo (2) + str lr, [sp] // Overwrite the saved LR with the one from the C handler + rfefd sp! // Return from exception to undo (1) .size _asm_default_data_abort_handler, . - _asm_default_data_abort_handler .popsection "#, @@ -53,26 +52,26 @@ core::arch::global_asm!( .global _asm_default_prefetch_abort_handler .type _asm_default_prefetch_abort_handler, %function _asm_default_prefetch_abort_handler: - sub lr, lr, #4 // Subtract 8 from LR, see p.1212 of the ARMv7-A architecture manual. - srsfd sp!, #{abt_mode} // store return state to ABT stack - push {{ r12 }} // save R12 - can now use it - and r12, sp, 7 // align SP down to eight byte boundary using R12 - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r4, r12 }} // push alignment amount, and preserved registers - can now use R0-R3 (R4 is just padding) + sub lr, lr, #4 // Make sure we jump back to the right place + srsfd sp!, #{abt_mode} // Store return state to ABT stack (1) + push {{ r12 }} // Push preserved register R12 (2) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (3) + push {{ r0-r4, r12 }} // Push reserved registers and alignment amount (R4 is just padding) (4) "#, crate::fpu_context!("save"), r#" mov r0, lr // Pass the faulting instruction address to the handler. - bl _prefetch_abort_handler // call C handler - mov lr, r0 // if we get back here, assume they returned a new LR in r0 + bl _prefetch_abort_handler // Call C handler + mov lr, r0 // If we get back here, assume they returned a new LR in r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r4, r12 }} // restore preserved registers, dummy value, and alignment amount - add sp, r12 // restore SP alignment using R12 - pop {{ r12 }} // restore R12 - str lr, [sp] // overwrite the saved LR with the one from the C handler - rfefd sp! // return from exception + pop {{ r0-r4, r12 }} // Pop preserved registers, dummy value, and alignment amount to undo (4) + add sp, r12 // Restore SP alignment using R12 to undo (3) + pop {{ r12 }} // Pop R12 to undo (2) + str lr, [sp] // Overwrite the saved LR with the one from the C handler to undo (1) + rfefd sp! // Return from exception .size _asm_default_prefetch_abort_handler, . - _asm_default_prefetch_abort_handler .popsection "#, diff --git a/aarch32-rt/src/arch_v7/hvc.rs b/aarch32-rt/src/arch_v7/hvc.rs index 21b7dfe7..4c160c78 100644 --- a/aarch32-rt/src/arch_v7/hvc.rs +++ b/aarch32-rt/src/arch_v7/hvc.rs @@ -15,22 +15,22 @@ core::arch::global_asm!( .global _asm_default_hvc_handler .type _asm_default_hvc_handler, %function _asm_default_hvc_handler: - push {{ r12, lr }} // give us R12 and LR to work with - push {{ r0-r5 }} // push frame to stack - mov r12, sp // r12 = pointer to Frame + push {{ r12, lr }} // Push preserved registers R12 and LR (1) + push {{ r0-r5 }} // Push HVC frame to stack (2) + mov r12, sp // R12 = pointer to Frame "#, crate::fpu_context!("save"), r#" - mrc p15, 4, r0, c5, c2, 0 // r0 = HSR value - mov r1, r12 // r1 = frame pointer + mrc p15, 4, r0, c5, c2, 0 // R0 = HSR value + mov r1, r12 // R1 = frame pointer bl _hvc_handler mov r12, r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r5 }} // restore frame - mov r0, r12 // replace return value - pop {{ r12, lr }} // pop state from stack + pop {{ r0-r5 }} // Pop HVC frame (2) + mov r0, r12 // Replace return value + pop {{ r12, lr }} // Pop R12 and LR from stack to undo (1) eret // Return from the asm handler .size _asm_default_hvc_handler, . - _asm_default_hvc_handler .popsection diff --git a/aarch32-rt/src/arch_v7/interrupt.rs b/aarch32-rt/src/arch_v7/interrupt.rs index c894e8c8..3493eded 100644 --- a/aarch32-rt/src/arch_v7/interrupt.rs +++ b/aarch32-rt/src/arch_v7/interrupt.rs @@ -32,24 +32,24 @@ core::arch::global_asm!( .global _asm_default_irq_handler .type _asm_default_irq_handler, %function _asm_default_irq_handler: - sub lr, lr, 4 // make sure we jump back to the right place - srsfd sp!, #{handler_mode} // store return state to the handler stack (1) - cps #{handler_mode} // switch to handler mode (2) - push {{ lr }} // save adjusted LR to handler mode stack (3) - and lr, sp, 7 // align SP down to eight byte boundary using LR + sub lr, lr, 4 // Make sure we jump back to the right place + srsfd sp!, #{handler_mode} // Store return state to the handler stack (1) + cps #{handler_mode} // Switch to handler mode (2) + push {{ lr }} // Push adjusted LR to handler mode stack (3) + and lr, sp, 7 // Align SP down to eight byte boundary using LR sub sp, lr // SP now aligned - only push 64-bit values from here (4) - push {{ r0-r3, r12, lr }} // push alignment amount (in LR) and preserved registers (5) + push {{ r0-r3, r12, lr }} // Push alignment amount (in LR) and preserved registers (5) "#, crate::fpu_context!("save"), r#" - bl _irq_handler // call C handler (they may choose to re-enable interrupts) + bl _irq_handler // Call C handler (they may choose to re-enable interrupts) "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r3, r12, lr }} // restore alignment amount (in LR) and preserved registers to undo (5) - add sp, lr // restore SP alignment using LR to undo (4) - pop {{ lr }} // restore adjusted LR to undo (3) - rfefd sp! // return from exception to undo (2) and (1) together + pop {{ r0-r3, r12, lr }} // Pop alignment amount (in LR) and preserved registers to undo (5) + add sp, lr // Restore SP alignment using LR to undo (4) + pop {{ lr }} // Pop adjusted LR to undo (3) + rfefd sp! // Return from exception to undo (2) and (1) together .size _asm_default_irq_handler, . - _asm_default_irq_handler .popsection "#, diff --git a/aarch32-rt/src/arch_v7/svc.rs b/aarch32-rt/src/arch_v7/svc.rs index e61ff80b..ea863225 100644 --- a/aarch32-rt/src/arch_v7/svc.rs +++ b/aarch32-rt/src/arch_v7/svc.rs @@ -14,12 +14,12 @@ core::arch::global_asm!( .global _asm_default_svc_handler .type _asm_default_svc_handler, %function _asm_default_svc_handler: - srsfd sp!, #{svc_mode} // store return state to SVC stack - push {{ r12, lr }} // save LR and R12 - can now use R12 (but leave LR alone for SVC code lookup) - and r12, sp, 7 // align SP down to eight byte boundary using R12 - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r6, r12 }} // push alignment amount, and stacked SVC argument registers (must be even number of regs for alignment) - mov r12, sp // save SP for integer frame + srsfd sp!, #{svc_mode} // Store return state to the SVC stack (1) + push {{ r12, lr }} // Push preserved registers R12 and LR (2) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (3) + push {{ r0-r6, r12 }} // Push SVC frame registers and alignment amount (4) + mov r12, sp // Save SP for integer frame "#, crate::fpu_context!("save"), r#" @@ -28,17 +28,17 @@ core::arch::global_asm!( ldrbne r0, [lr,#-2] // Yes: Load 1-byte immediate ldreq r0, [lr,#-4] // No: Load word and... biceq r0, r0, #0xFF000000 // ...extract 3-byte immediate - mov r1, r12 // pass the stacked integer registers in r1 - bl _svc_handler - mov lr, r0 // move r0 out of the way - restore_fpu_context will trash it + mov r1, r12 // Pass the stacked integer registers in r1 + bl _svc_handler // Call C handler in SVC mode + mov lr, r0 // Move r0 out of the way - restore_fpu_context will trash it "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r6, r12 }} // restore stacked registers and alignment amount - mov r0, lr // replace R0 with return value from _svc_handler - add sp, r12 // restore SP alignment using R12 - pop {{ r12, lr }} // restore R12 and LR - rfefd sp! // return from exception + pop {{ r0-r6, r12 }} // Pop SVC frame registers and alignment amount to undo (4) + mov r0, lr // Replace R0 with return value from _svc_handler + add sp, r12 // Restore SP alignment using R12 to undo (3) + pop {{ r12, lr }} // Pop R12 and LR to undo (2) + rfefd sp! // Return from exception to undo (1) .size _asm_default_svc_handler, . - _asm_default_svc_handler .popsection "#, diff --git a/aarch32-rt/src/arch_v7/undefined.rs b/aarch32-rt/src/arch_v7/undefined.rs index 15f53013..9067a1bf 100644 --- a/aarch32-rt/src/arch_v7/undefined.rs +++ b/aarch32-rt/src/arch_v7/undefined.rs @@ -16,30 +16,30 @@ core::arch::global_asm!( .global _asm_default_undefined_handler .type _asm_default_undefined_handler, %function _asm_default_undefined_handler: - srsfd sp!, #{und_mode} // store return state to UND stack - push {{ r12 }} // Save preserved register R12 - can now use it - mrs r12, spsr // Read SPSR into R12 + srsfd sp!, #{und_mode} // Store return state to the UND stack (1) + push {{ r12 }} // Push preserved register R12 (2) + mrs r12, spsr // Grab SPSR so we can analyze it (it's been saved already) tst r12, {t_bit} // Was the code that triggered the exception in Thumb state? ite eq // Adjust LR to point to faulting instruction - see p.1206 of the ARMv7-A architecture manual. subeq lr, lr, #4 // Subtract 4 in Arm Mode subne lr, lr, #2 // Subtract 2 in Thumb Mode - and r12, sp, 7 // align SP down to eight byte boundary using R12 - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r4, r12 }} // push alignment amount, and preserved registers - can now use R0-R3 (R4 is just padding) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (3) + push {{ r0-r4, r12 }} // Push alignment amount, and preserved registers (R4 is just padding) (4) "#, crate::fpu_context!("save"), r#" mov r0, lr // Pass the faulting instruction address to the handler. - bl _undefined_handler // call C handler - mov lr, r0 // if we get back here, assume they returned a new LR in r0 + bl _undefined_handler // Call C handler + mov lr, r0 // If we get back here, assume they returned a new LR in r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r4, r12 }} // restore preserved registers, dummy value, and alignment amount - add sp, r12 // restore SP alignment using R12 - pop {{ r12 }} // restore R12 - str lr, [sp] // overwrite the saved LR with the one from the C handler - rfefd sp! // return from exception + pop {{ r0-r4, r12 }} // Pop preserved registers, dummy value, and alignment amount to undo (4) + add sp, r12 // Restore SP alignment using R12 to undo (3) + pop {{ r12 }} // Pop R12 to undo (2) + str lr, [sp] // Overwrite the saved LR with the one from the C handler + rfefd sp! // Return from exception to undo (1) .size _asm_default_undefined_handler, . - _asm_default_undefined_handler .popsection "#, diff --git a/aarch32-rt/src/arch_v8_hyp/abort.rs b/aarch32-rt/src/arch_v8_hyp/abort.rs index 5b5c9d0b..62ddf2f3 100644 --- a/aarch32-rt/src/arch_v8_hyp/abort.rs +++ b/aarch32-rt/src/arch_v8_hyp/abort.rs @@ -13,26 +13,24 @@ core::arch::global_asm!( .global _asm_default_data_abort_handler .type _asm_default_data_abort_handler, %function _asm_default_data_abort_handler: - push {{ r0-r3, r12, lr }} // preserve state that C function won't save - mrs r0, elr_hyp // grab ELR_hyp - mrs r1, spsr_hyp // grab SPSR_hyp - mov r12, sp // align SP down to eight byte boundary using R12 - and r12, r12, 7 // - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r2, r12 }} // save ELR, SPSR, padding and alignment amount + push {{ r0-r3, r12, lr }} // Push preserved registers (1) + mrs r0, spsr_hyp // Grab SPSR (2) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (3) + push {{ r0, r12 }} // Push SPSR and alignment amount (4) "#, crate::fpu_context!("save"), r#" mrs r0, elr_hyp // Pass the faulting instruction address to the handler. - bl _data_abort_handler // call C handler - msr elr_hyp, r0 // if we get back here, assume they returned a new LR in r0 + bl _data_abort_handler // Call C handler + msr elr_hyp, r0 // If we get back here, assume they returned a new LR in r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r2, r12 }} // restore ELR, SPSR, padding and alignment amount - add sp, r12 // restore SP alignment - msr spsr_hyp, r1 // restore SPSR - pop {{ r0-r3, r12, lr }} // restore state that C function didn't save + pop {{ r0, r12 }} // Pop SPSR and alignment amount to undo (4) + add sp, r12 // Restore SP alignment using R12 to undo (3) + msr spsr_hyp, r0 // Restore SPSR to undo (2) + pop {{ r0-r3, r12, lr }} // Pop state that C function didn't save to undo (1) eret // Return from the asm handler .size _asm_default_data_abort_handler, . - _asm_default_data_abort_handler "#, @@ -51,26 +49,24 @@ core::arch::global_asm!( .global _asm_default_prefetch_abort_handler .type _asm_default_prefetch_abort_handler, %function _asm_default_prefetch_abort_handler: - push {{ r0-r3, r12, lr }} // preserve state that C function won't save - mrs r0, elr_hyp // grab ELR_hyp - mrs r1, spsr_hyp // grab SPSR_hyp - mov r12, sp // align SP down to eight byte boundary using R12 - and r12, r12, 7 // - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r2, r12 }} // save ELR, SPSR, padding and alignment amount + push {{ r0-r3, r12, lr }} // Push preserved registers (1) + mrs r0, spsr_hyp // Grab SPSR (2) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (3) + push {{ r0, r12 }} // Push SPSR and alignment amount (4) "#, crate::fpu_context!("save"), r#" mrs r0, elr_hyp // Pass the faulting instruction address to the handler. - bl _prefetch_abort_handler // call C handler - msr elr_hyp, r0 // if we get back here, assume they returned a new LR in r0 + bl _prefetch_abort_handler // Call C handler + msr elr_hyp, r0 // If we get back here, assume they returned a new LR in r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r2, r12 }} // restore ELR, SPSR, padding and alignment amount - add sp, r12 // restore SP alignment - msr spsr_hyp, r1 // restore SPSR - pop {{ r0-r3, r12, lr }} // restore state that C function didn't save + pop {{ r0, r12 }} // Pop SPSR and alignment amount to undo (4) + add sp, r12 // Restore SP alignment using R12 to undo (3) + msr spsr_hyp, r0 // Restore SPSR to undo (2) + pop {{ r0-r3, r12, lr }} // Pop state that C function didn't save to undo (1) eret // Return from the asm handler .size _asm_default_prefetch_abort_handler, . - _asm_default_prefetch_abort_handler "#, diff --git a/aarch32-rt/src/arch_v8_hyp/hvc.rs b/aarch32-rt/src/arch_v8_hyp/hvc.rs index 8fc81638..3abfa280 100644 --- a/aarch32-rt/src/arch_v8_hyp/hvc.rs +++ b/aarch32-rt/src/arch_v8_hyp/hvc.rs @@ -14,32 +14,31 @@ core::arch::global_asm!( .global _asm_default_hvc_handler .type _asm_default_hvc_handler, %function _asm_default_hvc_handler: - push {{ r12, lr }} // give us R12 and LR to work with - mrs lr, elr_hyp // grab elr - mrs r12, spsr_hyp // grab spsr - push {{ r12, lr }} // push them to stack - mov r12, sp // align SP down to eight byte boundary using R12 - and r12, r12, 7 // - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r6, r12 }} // push frame and alignment amount to stack - mov r12, sp // r12 = pointer to Frame + push {{ r12, lr }} // Push preserved registers R12 and LR (1) + mrs lr, elr_hyp // Grab ELR (2) + mrs r12, spsr_hyp // Grab SPSR (3) + push {{ r12, lr }} // Push them to stack (4) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (5) + push {{ r0-r6, r12 }} // Push HVC frame and alignment amount to stack (6) + mov r12, sp // R12 = pointer to Frame "#, crate::fpu_context!("save"), r#" - mrc p15, 4, r0, c5, c2, 0 // r0 = HSR value - mov r1, r12 // r1 = frame pointer + mrc p15, 4, r0, c5, c2, 0 // R0 = HSR value + mov r1, r12 // R1 = frame pointer bl _hvc_handler - mov lr, r0 // copy return value into LR, because we're about to use r0 in the FPU restore + mov lr, r0 // Copy return value into LR, because we're about to use r0 in the FPU restore "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r6, r12 }} // restore frame and alignment - mov r0, lr // copy return value from lr back to r0, overwriting saved r0 - add sp, r12 // restore SP alignment using R12 - pop {{ r12, lr }} // pop elr and spsr from stack - msr elr_hyp, lr // restore elr - msr spsr_hyp, r12 // restore spsr - pop {{ r12, lr }} // pop R12 and LR from stack + pop {{ r0-r6, r12 }} // Pop HVC frame and alignment to undo (6) + mov r0, lr // Copy return value from LR back to R0, overwriting saved R0 + add sp, r12 // Restore SP alignment using R12 to undo (5) + pop {{ r12, lr }} // Pop ELR and SPSR values from stack to undo (4) + msr spsr_hyp, r12 // Restore SPSR to undo (3) + msr elr_hyp, lr // Restore ELR to undo (2) + pop {{ r12, lr }} // Pop R12 and LR from stack eret // Return from the asm handler .size _asm_default_hvc_handler, . - _asm_default_hvc_handler "#, diff --git a/aarch32-rt/src/arch_v8_hyp/interrupt.rs b/aarch32-rt/src/arch_v8_hyp/interrupt.rs index 189dcce4..0aff8722 100644 --- a/aarch32-rt/src/arch_v8_hyp/interrupt.rs +++ b/aarch32-rt/src/arch_v8_hyp/interrupt.rs @@ -14,25 +14,24 @@ core::arch::global_asm!( .global _asm_default_irq_handler .type _asm_default_irq_handler, %function _asm_default_irq_handler: - push {{ r0-r3, r12, lr }} // preserve state that C function won't save (1) - mrs r0, elr_hyp // grab ELR_hyp (2) - mrs r1, spsr_hyp // grab SPSR_hyp (3) - mov r12, sp // align SP down to eight byte boundary using R12 - and r12, r12, 7 // + push {{ r0-r3, r12, lr }} // Push preserved registers (1) + mrs r0, elr_hyp // Grab ELR (2) + mrs r1, spsr_hyp // Grab SPSR (3) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 sub sp, r12 // SP now aligned - only push 64-bit values from here (4) - push {{ r0-r2, r12 }} // save ELR, SPSR, padding and alignment amount (5) + push {{ r0-r2, r12 }} // Push ELR, SPSR, padding and alignment amount (5) "#, crate::fpu_context!("save"), r#" - bl _irq_handler // call C handler (they may choose to re-enable interrupts) + bl _irq_handler // Call C handler (they may choose to re-enable interrupts) "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r2, r12 }} // restore ELR, SPSR, padding and alignment amount to undo (5) - add sp, r12 // restore SP alignment to undo (4) - msr spsr_hyp, r1 // restore SPSR_hyp to undo (3) - msr elr_hyp, r0 // restore ELR_hyp to undo (2) - pop {{ r0-r3, r12, lr }} // restore state that C function didn't save to undo (1) + pop {{ r0-r2, r12 }} // Pop ELR, SPSR, padding and alignment amount to undo (5) + add sp, r12 // Restore SP alignment to undo (4) + msr spsr_hyp, r1 // Restore SPSR to undo (3) + msr elr_hyp, r0 // Restore ELR to undo (2) + pop {{ r0-r3, r12, lr }} // Pop preserved registers (1) eret // Return from the asm handler .size _asm_default_irq_handler, . - _asm_default_irq_handler "#, diff --git a/aarch32-rt/src/arch_v8_hyp/svc.rs b/aarch32-rt/src/arch_v8_hyp/svc.rs index f3168d67..56a5f184 100644 --- a/aarch32-rt/src/arch_v8_hyp/svc.rs +++ b/aarch32-rt/src/arch_v8_hyp/svc.rs @@ -20,32 +20,31 @@ core::arch::global_asm!( .global _asm_default_svc_handler .type _asm_default_svc_handler, %function _asm_default_svc_handler: - push {{ r12, lr }} // give us R12 and LR to work with - mrs lr, elr_hyp // grab elr - mrs r12, spsr_hyp // grab spsr - push {{ r12, lr }} // push them to stack - mov r12, sp // align SP down to eight byte boundary using R12 - and r12, r12, 7 // - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r6, r12 }} // push frame and alignment amount to stack - mov r12, sp // r12 = pointer to Frame + push {{ r12, lr }} // Push R12 and LR (1) + mrs lr, elr_hyp // Grab ELR (2) + mrs r12, spsr_hyp // Grab SPSR (3) + push {{ r12, lr }} // Push them to stack (4) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (5) + push {{ r0-r6, r12 }} // Push SVC frame and alignment amount to stack (6) + mov r12, sp // R12 = pointer to Frame "#, crate::fpu_context!("save"), r#" - mrc p15, 4, r0, c5, c2, 0 // r0 = HSR value - mov r1, r12 // r1 = frame pointer + mrc p15, 4, r0, c5, c2, 0 // R0 = HSR value + mov r1, r12 // R1 = frame pointer bl _hvc_handler - mov lr, r0 // copy return value into LR, because we're about to use r0 in the FPU restore + mov lr, r0 // Copy return value into LR, because we're about to use r0 in the FPU restore "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r6, r12 }} // restore frame and alignment - mov r0, lr // copy return value from lr back to r0, overwriting saved r0 - add sp, r12 // restore SP alignment using R12 - pop {{ r12, lr }} // pop elr and spsr from stack - msr elr_hyp, lr // restore elr - msr spsr_hyp, r12 // restore spsr - pop {{ r12, lr }} // pop R12 and LR from stack + pop {{ r0-r6, r12 }} // Pop SVC frame and alignment to undo (6) + mov r0, lr // Copy return value from LR back to R0, overwriting saved R0 + add sp, r12 // Restore SP alignment using R12 to undo (5) + pop {{ r12, lr }} // Pop ELR and SPSR from stack to undo (4) + msr spsr_hyp, r12 // Restore SPSR to undo (3) + msr elr_hyp, lr // Restore ELR to undo (2) + pop {{ r12, lr }} // Pop R12 and LR from stack to undo (1) eret // Return from the asm handler .size _asm_default_svc_handler, . - _asm_default_svc_handler "#, diff --git a/aarch32-rt/src/arch_v8_hyp/undefined.rs b/aarch32-rt/src/arch_v8_hyp/undefined.rs index a6bffc6e..3e49e990 100644 --- a/aarch32-rt/src/arch_v8_hyp/undefined.rs +++ b/aarch32-rt/src/arch_v8_hyp/undefined.rs @@ -15,26 +15,24 @@ core::arch::global_asm!( .global _asm_default_undefined_handler .type _asm_default_undefined_handler, %function _asm_default_undefined_handler: - push {{ r0-r3, r12, lr }} // preserve state that C function won't save - mrs r0, elr_hyp // grab ELR_hyp - mrs r1, spsr_hyp // grab SPSR_hyp - mov r12, sp // align SP down to eight byte boundary using R12 - and r12, r12, 7 // - sub sp, r12 // SP now aligned - only push 64-bit values from here - push {{ r0-r2, r12 }} // save ELR, SPSR, padding and alignment amount + push {{ r0-r3, r12, lr }} // Push preserved registers (1) + mrs r0, spsr_hyp // Grab SPSR (2) + and r12, sp, 7 // Align SP down to eight byte boundary using R12 + sub sp, r12 // SP now aligned - only push 64-bit values from here (3) + push {{ r0, r12 }} // Push SPSR and alignment amount (4) "#, crate::fpu_context!("save"), r#" mrs r0, elr_hyp // Pass the faulting instruction address to the handler. - bl _undefined_handler // call C handler - msr elr_hyp, r0 // if we get back here, assume they returned a new LR in r0 + bl _undefined_handler // Call C handler + msr elr_hyp, r0 // If we get back here, assume they returned a new LR in r0 "#, crate::fpu_context!("restore"), r#" - pop {{ r0-r2, r12 }} // restore ELR, SPSR, padding and alignment amount - add sp, r12 // restore SP alignment - msr spsr_hyp, r1 // restore SPSR - pop {{ r0-r3, r12, lr }} // restore state that C function didn't save + pop {{ r0, r12 }} // Pop SPSR and alignment amount to undo (4) + add sp, r12 // Restore SP alignment using R12 to undo (3) + msr spsr_hyp, r0 // Restore SPSR to undo (2) + pop {{ r0-r3, r12, lr }} // Pop preserved registers (1) eret // Return from the asm handler .size _asm_default_undefined_handler, . - _asm_default_undefined_handler "#,