diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 51e5c3c2a932..5ec2c5c6b05e 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -368,6 +368,7 @@ - [Using It](bare-metal/aps/logging/using.md) - [Exceptions](bare-metal/aps/exceptions.md) - [aarch64-rt](bare-metal/aps/aarch64-rt.md) + - [Exceptions](bare-metal/aps/aarch64-rt/exceptions.md) - [Other Projects](bare-metal/aps/other-projects.md) - [Useful Crates](bare-metal/useful-crates.md) - [`zerocopy`](bare-metal/useful-crates/zerocopy.md) diff --git a/src/bare-metal/aps/aarch64-rt/exceptions.md b/src/bare-metal/aps/aarch64-rt/exceptions.md new file mode 100644 index 000000000000..8af2eb752667 --- /dev/null +++ b/src/bare-metal/aps/aarch64-rt/exceptions.md @@ -0,0 +1,25 @@ +# Exceptions + +`aarch64-rt` provides a trait to define exception handlers, and a macro to +generate the assembly code for the exception vector to call them. + +The trait has default implementations for each method which simply panic, so we +can omit methods for exceptions we don't expect to happen. + + + +```rust,editable,compile_fail +{{#include ../examples/src/exceptions_rt.rs:exceptions}} +``` + +
+ +- The `exception_handlers` macro generates a `global_asm!` block with the + exception vector to call into the Rust code, similar to the `exceptions.S` we + had before. +- `RegisterStateRef` wraps a reference to the stack frame where the register + values were saved by the assembly code when the exception happed. This can be + used for example to extract the parameters for an SMC or HVC call from a lower + EL, and update the values to be restored when the exception handler returns. + +
diff --git a/src/bare-metal/aps/examples/Cargo.lock b/src/bare-metal/aps/examples/Cargo.lock index fa4428d765e0..c60977ff86cb 100644 --- a/src/bare-metal/aps/examples/Cargo.lock +++ b/src/bare-metal/aps/examples/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "aarch64-rt" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21dc662bf8045ff4a57989d927607b71654b902f0a1976ec3e7fbb30a1477aa" +checksum = "4969245b57b2aef286e6f507cd3fd1b9be7c6df1f0341141ab42226e3e6c52ae" dependencies = [ "smccc", ] diff --git a/src/bare-metal/aps/examples/Cargo.toml b/src/bare-metal/aps/examples/Cargo.toml index 10a53ffd200a..34464650a24d 100644 --- a/src/bare-metal/aps/examples/Cargo.toml +++ b/src/bare-metal/aps/examples/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] aarch64-paging = { version = "0.11.0", default-features = false } -aarch64-rt = "0.3.1" +aarch64-rt = "0.4.2" arm-pl011-uart = "0.4.0" bitflags = "2.10.0" log = "0.4.29" diff --git a/src/bare-metal/aps/examples/Makefile b/src/bare-metal/aps/examples/Makefile index 8f91d594836a..74390b616428 100644 --- a/src/bare-metal/aps/examples/Makefile +++ b/src/bare-metal/aps/examples/Makefile @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: build qemu qemu_logger qemu_minimal qemu_psci +.PHONY: build qemu qemu_logger qemu_minimal qemu_psci qemu_rt qemu_safemmio -all: minimal.bin improved.bin logger.bin +all: improved.bin logger.bin minimal.bin psci.bin rt.bin safemmio.bin build: cargo build diff --git a/src/bare-metal/aps/examples/src/exceptions.S b/src/bare-metal/aps/examples/src/exceptions.S index bd86eebbdfc7..59122a0fdb1e 100644 --- a/src/bare-metal/aps/examples/src/exceptions.S +++ b/src/bare-metal/aps/examples/src/exceptions.S @@ -14,6 +14,7 @@ * limitations under the License. */ +// ANCHOR: exceptions /** * Saves the volatile registers onto the stack. This currently takes * 14 instructions, so it can be used in exception handlers with 18 @@ -77,39 +78,18 @@ .endm /** - * This is a generic handler for exceptions taken at the current EL - * while using SP0. It behaves similarly to the SPx case by first - * switching to SPx, doing the work, then switching back to SP0 before - * returning. + * This is a generic handler for exceptions taken at the current EL. It saves + * volatile registers to the stack, calls the Rust handler, restores volatile + * registers, then returns. * - * Switching to SPx and calling the Rust handler takes 16 - * instructions. To restore and return we need an additional 16 - * instructions, so we can implement the whole handler within the - * allotted 32 instructions. + * This also works for exceptions taken from lower ELs, if we don't care about + * non-volatile registers. * + * Saving state and jumping to the Rust handler takes 15 instructions, and + * restoring and returning also takes 15 instructions, so we can fit the whole + * handler in 30 instructions, under the limit of 32. */ -.macro current_exception_sp0 handler:req - msr spsel, #1 - save_volatile_to_stack - bl \handler - restore_volatile_from_stack - msr spsel, #0 - eret -.endm - -/** - * This is a generic handler for exceptions taken at the current EL - * while using SPx. It saves volatile registers, calls the Rust - * handler, restores volatile registers, then returns. - * - * This also works for exceptions taken from EL0, if we don't care - * about non-volatile registers. - * - * Saving state and jumping to the Rust handler takes 15 instructions, - * and restoring and returning also takes 15 instructions, so we can - * fit the whole handler in 30 instructions, under the limit of 32. - */ -.macro current_exception_spx handler:req +.macro current_exception handler:req save_volatile_to_stack bl \handler restore_volatile_from_stack @@ -121,64 +101,64 @@ .balign 0x800 vector_table_el1: sync_cur_sp0: - current_exception_sp0 sync_exception_current + current_exception sync_current .balign 0x80 irq_cur_sp0: - current_exception_sp0 irq_current + current_exception irq_current .balign 0x80 fiq_cur_sp0: - current_exception_sp0 fiq_current + current_exception fiq_current .balign 0x80 serr_cur_sp0: - current_exception_sp0 serr_current + current_exception serror_current .balign 0x80 sync_cur_spx: - current_exception_spx sync_exception_current + current_exception sync_current .balign 0x80 irq_cur_spx: - current_exception_spx irq_current + current_exception irq_current .balign 0x80 fiq_cur_spx: - current_exception_spx fiq_current + current_exception fiq_current .balign 0x80 serr_cur_spx: - current_exception_spx serr_current + current_exception serror_current .balign 0x80 sync_lower_64: - current_exception_spx sync_lower + current_exception sync_lower .balign 0x80 irq_lower_64: - current_exception_spx irq_lower + current_exception irq_lower .balign 0x80 fiq_lower_64: - current_exception_spx fiq_lower + current_exception fiq_lower .balign 0x80 serr_lower_64: - current_exception_spx serr_lower + current_exception serror_lower .balign 0x80 sync_lower_32: - current_exception_spx sync_lower + current_exception sync_lower .balign 0x80 irq_lower_32: - current_exception_spx irq_lower + current_exception irq_lower .balign 0x80 fiq_lower_32: - current_exception_spx fiq_lower + current_exception fiq_lower .balign 0x80 serr_lower_32: - current_exception_spx serr_lower + current_exception serror_lower diff --git a/src/bare-metal/aps/examples/src/exceptions.rs b/src/bare-metal/aps/examples/src/exceptions.rs index cc52a1fe3379..07b2185b78de 100644 --- a/src/bare-metal/aps/examples/src/exceptions.rs +++ b/src/bare-metal/aps/examples/src/exceptions.rs @@ -19,8 +19,8 @@ use smccc::psci::system_off; // SAFETY: There is no other global function of this name. #[unsafe(no_mangle)] -extern "C" fn sync_exception_current(_elr: u64, _spsr: u64) { - error!("sync_exception_current"); +extern "C" fn sync_current(_elr: u64, _spsr: u64) { + error!("sync_current"); system_off::().unwrap(); } @@ -40,8 +40,8 @@ extern "C" fn fiq_current(_elr: u64, _spsr: u64) { // SAFETY: There is no other global function of this name. #[unsafe(no_mangle)] -extern "C" fn serr_current(_elr: u64, _spsr: u64) { - error!("serr_current"); +extern "C" fn serror_current(_elr: u64, _spsr: u64) { + error!("serror_current"); system_off::().unwrap(); } @@ -68,7 +68,7 @@ extern "C" fn fiq_lower(_elr: u64, _spsr: u64) { // SAFETY: There is no other global function of this name. #[unsafe(no_mangle)] -extern "C" fn serr_lower(_elr: u64, _spsr: u64) { - error!("serr_lower"); +extern "C" fn serror_lower(_elr: u64, _spsr: u64) { + error!("serror_lower"); system_off::().unwrap(); } diff --git a/src/bare-metal/aps/examples/src/exceptions_rt.rs b/src/bare-metal/aps/examples/src/exceptions_rt.rs new file mode 100644 index 000000000000..aad0a8149f76 --- /dev/null +++ b/src/bare-metal/aps/examples/src/exceptions_rt.rs @@ -0,0 +1,45 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// ANCHOR: exceptions +use aarch64_rt::{ExceptionHandlers, RegisterStateRef, exception_handlers}; +use log::error; +use smccc::Hvc; +use smccc::psci::system_off; + +struct Handlers; + +impl ExceptionHandlers for Handlers { + extern "C" fn sync_current(_state: RegisterStateRef) { + error!("sync_current"); + system_off::().unwrap(); + } + + extern "C" fn irq_current(_state: RegisterStateRef) { + error!("irq_current"); + system_off::().unwrap(); + } + + extern "C" fn fiq_current(_state: RegisterStateRef) { + error!("fiq_current"); + system_off::().unwrap(); + } + + extern "C" fn serror_current(_state: RegisterStateRef) { + error!("serror_current"); + system_off::().unwrap(); + } +} + +exception_handlers!(Handlers); diff --git a/src/bare-metal/aps/examples/src/main_rt.rs b/src/bare-metal/aps/examples/src/main_rt.rs index e18129cdc23a..4d6a4375bef9 100644 --- a/src/bare-metal/aps/examples/src/main_rt.rs +++ b/src/bare-metal/aps/examples/src/main_rt.rs @@ -16,7 +16,7 @@ #![no_main] #![no_std] -mod exceptions; +mod exceptions_rt; use aarch64_paging::descriptor::Attributes; use aarch64_rt::{InitialPagetable, entry, initial_pagetable}; diff --git a/src/bare-metal/aps/exceptions.md b/src/bare-metal/aps/exceptions.md index 916d952fbc6b..719924c4c75f 100644 --- a/src/bare-metal/aps/exceptions.md +++ b/src/bare-metal/aps/exceptions.md @@ -26,6 +26,14 @@ calling into Rust code: but not `Sync`, then we'll need to wrap it in something like a `Mutex` and put it in a static. +The assembly code for the exception vector: + + + +```armasm +{{#include examples/src/exceptions.S:exceptions}} +``` + [1]: ../../concurrency/send-sync.md diff --git a/src/exercises/bare-metal/rtc/src/exceptions.rs b/src/exercises/bare-metal/rtc/src/exceptions.rs index 6c8132fdf4ff..ac5c99e07f49 100644 --- a/src/exercises/bare-metal/rtc/src/exceptions.rs +++ b/src/exercises/bare-metal/rtc/src/exceptions.rs @@ -22,7 +22,7 @@ struct Handlers; impl ExceptionHandlers for Handlers { extern "C" fn sync_current(_state: RegisterStateRef) { - error!("sync_exception_current"); + error!("sync_current"); system_off::().unwrap(); } @@ -40,7 +40,7 @@ impl ExceptionHandlers for Handlers { } extern "C" fn serror_current(_state: RegisterStateRef) { - error!("serr_current"); + error!("serror_current"); system_off::().unwrap(); } @@ -60,7 +60,7 @@ impl ExceptionHandlers for Handlers { } extern "C" fn serror_lower(_state: RegisterStateRef) { - error!("serr_lower"); + error!("serror_lower"); system_off::().unwrap(); } }