Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
25 changes: 25 additions & 0 deletions src/bare-metal/aps/aarch64-rt/exceptions.md
Original file line number Diff line number Diff line change
@@ -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.

<!-- mdbook-xgettext: skip -->

```rust,editable,compile_fail
{{#include ../examples/src/exceptions_rt.rs:exceptions}}
```

<details>

- 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.

</details>
4 changes: 2 additions & 2 deletions src/bare-metal/aps/examples/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/bare-metal/aps/examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions src/bare-metal/aps/examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
72 changes: 26 additions & 46 deletions src/bare-metal/aps/examples/src/exceptions.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
12 changes: 6 additions & 6 deletions src/bare-metal/aps/examples/src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Hvc>().unwrap();
}

Expand All @@ -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::<Hvc>().unwrap();
}

Expand All @@ -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::<Hvc>().unwrap();
}
45 changes: 45 additions & 0 deletions src/bare-metal/aps/examples/src/exceptions_rt.rs
Original file line number Diff line number Diff line change
@@ -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::<Hvc>().unwrap();
}

extern "C" fn irq_current(_state: RegisterStateRef) {
error!("irq_current");
system_off::<Hvc>().unwrap();
}

extern "C" fn fiq_current(_state: RegisterStateRef) {
error!("fiq_current");
system_off::<Hvc>().unwrap();
}

extern "C" fn serror_current(_state: RegisterStateRef) {
error!("serror_current");
system_off::<Hvc>().unwrap();
}
}

exception_handlers!(Handlers);
2 changes: 1 addition & 1 deletion src/bare-metal/aps/examples/src/main_rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
8 changes: 8 additions & 0 deletions src/bare-metal/aps/exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

<!-- mdbook-xgettext: skip -->

```armasm
{{#include examples/src/exceptions.S:exceptions}}
```

</details>

[1]: ../../concurrency/send-sync.md
6 changes: 3 additions & 3 deletions src/exercises/bare-metal/rtc/src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Hvc>().unwrap();
}

Expand All @@ -40,7 +40,7 @@ impl ExceptionHandlers for Handlers {
}

extern "C" fn serror_current(_state: RegisterStateRef) {
error!("serr_current");
error!("serror_current");
system_off::<Hvc>().unwrap();
}

Expand All @@ -60,7 +60,7 @@ impl ExceptionHandlers for Handlers {
}

extern "C" fn serror_lower(_state: RegisterStateRef) {
error!("serr_lower");
error!("serror_lower");
system_off::<Hvc>().unwrap();
}
}
Expand Down
Loading