Refactor parts of exception handling

pull/126/head
Andre Richter 3 years ago
parent ddb4f54e49
commit 920af57ab4
No known key found for this signature in database
GPG Key ID: 2116C1AB102F615E

@ -203,12 +203,14 @@ some hand-crafted assembly. Introducing `exception.s`:
stp x26, x27, [sp, #16 * 13] stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14] stp x28, x29, [sp, #16 * 14]
// Add the exception link register (ELR_EL1) and the saved program status (SPSR_EL1). // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
// syndrome register (ESR_EL1).
mrs x1, ELR_EL1 mrs x1, ELR_EL1
mrs x2, SPSR_EL1 mrs x2, SPSR_EL1
mrs x3, ESR_EL1
stp lr, x1, [sp, #16 * 15] stp lr, x1, [sp, #16 * 15]
str x2, [sp, #16 * 16] stp x2, x3, [sp, #16 * 16]
// x0 is the first argument for the function called through `\handler`. // x0 is the first argument for the function called through `\handler`.
mov x0, sp mov x0, sp
@ -224,10 +226,10 @@ some hand-crafted assembly. Introducing `exception.s`:
First, a macro for saving the context is defined. It eventually jumps to follow-up handler code, and First, a macro for saving the context is defined. It eventually jumps to follow-up handler code, and
finally restores the context. In advance, we reserve space on the stack for the context. That is, finally restores the context. In advance, we reserve space on the stack for the context. That is,
the 30 `GPRs`, the `link register`, the `saved program status` and the `exception link register` the 30 `GPRs`, the `link register`, the `exception link register` (holding the preferred return
(holding the preferred return address). Afterwards, we store those registers, save the current stack address), the `saved program status` and the `exception syndrome register`. Afterwards, we store
address in `x0` and branch off to follow-up handler-code, whose function name is supplied as an those registers, save the current stack address in `x0` and branch off to follow-up handler-code,
argument to the macro (`\handler`). whose function name is supplied as an argument to the macro (`\handler`).
The handler code will be written in Rust, but use the platform's `C` ABI. This way, we can define a The handler code will be written in Rust, but use the platform's `C` ABI. This way, we can define a
function signature that has a pointer to the context-data on the stack as its first argument, and function signature that has a pointer to the context-data on the stack as its first argument, and
@ -298,6 +300,9 @@ struct ExceptionContext {
/// Saved program status. /// Saved program status.
spsr_el1: SpsrEL1, spsr_el1: SpsrEL1,
// Exception syndrome register.
esr_el1: EsrEL1,
} }
``` ```
@ -305,16 +310,12 @@ The handlers take a `struct ExceptionContext` argument. Since we do not plan to
for each exception yet, a default handler is provided: for each exception yet, a default handler is provided:
```rust ```rust
/// Print verbose information about the exception and the panic. /// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) { fn default_exception_handler(exc: &ExceptionContext) {
panic!( panic!(
"\n\nCPU Exception!\n\ "\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\ {}",
{}\n\ exc
{}",
FAR_EL1.get(),
EsrEL1 {},
e
); );
} }
``` ```
@ -363,14 +364,16 @@ To survive this exception, the respective handler has a special demo case:
```rust ```rust
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
let far_el1 = FAR_EL1.get(); if e.fault_address_valid() {
let far_el1 = FAR_EL1.get();
// This catches the demo case for this tutorial. If the fault address happens to be 8 GiB, // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB,
// advance the exception link register for one instruction, so that execution can continue. // advance the exception link register for one instruction, so that execution can continue.
if far_el1 == 8 * 1024 * 1024 * 1024 { if far_el1 == 8 * 1024 * 1024 * 1024 {
e.elr_el1 += 4; e.elr_el1 += 4;
asm::eret() return;
}
} }
default_exception_handler(e); default_exception_handler(e);
@ -398,6 +401,7 @@ Minipush 1.0
[MP] ⏳ Waiting for /dev/ttyUSB0 [MP] ⏳ Waiting for /dev/ttyUSB0
[MP] ✅ Serial connected [MP] ✅ Serial connected
[MP] 🔌 Please power the target now [MP] 🔌 Please power the target now
__ __ _ _ _ _ __ __ _ _ _ _
| \/ (_)_ _ (_) | ___ __ _ __| | | \/ (_)_ _ (_) | ___ __ _ __| |
| |\/| | | ' \| | |__/ _ \/ _` / _` | | |\/| | | ' \| | |__/ _ \/ _` / _` |
@ -409,39 +413,38 @@ Minipush 1.0
[MP] ⏩ Pushing 64 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00 [MP] ⏩ Pushing 64 KiB =========================================🦀 100% 0 KiB/s Time: 00:00:00
[ML] Loaded! Executing the payload now [ML] Loaded! Executing the payload now
[ 0.980247] mingo version 0.11.0 [ 0.788994] mingo version 0.11.0
[ 0.980454] Booting on: Raspberry Pi 3 [ 0.789201] Booting on: Raspberry Pi 3
[ 0.980909] MMU online. Special regions: [ 0.789656] MMU online. Special regions:
[ 0.981386] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data [ 0.790133] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data
[ 0.982404] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO [ 0.791151] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO
[ 0.983293] Current privilege level: EL1 [ 0.792040] Current privilege level: EL1
[ 0.983769] Exception handling state: [ 0.792516] Exception handling state:
[ 0.984213] Debug: Masked [ 0.792960] Debug: Masked
[ 0.984604] SError: Masked [ 0.793350] SError: Masked
[ 0.984993] IRQ: Masked [ 0.793740] IRQ: Masked
[ 0.985383] FIQ: Masked [ 0.794130] FIQ: Masked
[ 0.985773] Architectural timer resolution: 52 ns [ 0.794520] Architectural timer resolution: 52 ns
[ 0.986347] Drivers loaded: [ 0.795094] Drivers loaded:
[ 0.986684] 1. BCM GPIO [ 0.795430] 1. BCM GPIO
[ 0.987041] 2. BCM PL011 UART [ 0.795788] 2. BCM PL011 UART
[ 0.987463] Timer test, spinning for 1 second [ 0.796210] Timer test, spinning for 1 second
[ 1.987994] [ 1.796741]
[ 1.987998] Trying to read from address 8 GiB... [ 1.796745] Trying to read from address 8 GiB...
[ 1.988547] ************************************************ [ 1.797295] ************************************************
[ 1.989240] Whoa! We recovered from a synchronous exception! [ 1.797987] Whoa! We recovered from a synchronous exception!
[ 1.989933] ************************************************ [ 1.798680] ************************************************
[ 1.990627] [ 1.799373]
[ 1.990800] Let's try again [ 1.799547] Let's try again
[ 1.991136] Trying to read from address 9 GiB... [ 1.799883] Trying to read from address 9 GiB...
Kernel panic: Kernel panic:
CPU Exception! CPU Exception!
FAR_EL1: 0x0000000240000000
ESR_EL1: 0x96000004 ESR_EL1: 0x96000004
Exception Class (EC) : 0x25 - Data Abort, current EL Exception Class (EC) : 0x25 - Data Abort, current EL
Instr Specific Syndrome (ISS): 0x4 Instr Specific Syndrome (ISS): 0x4
ELR_EL1: 0x0000000000082578 FAR_EL1: 0x0000000240000000
SPSR_EL1: 0x600003c5 SPSR_EL1: 0x600003c5
Flags: Flags:
Negative (N): Not set Negative (N): Not set
@ -454,24 +457,25 @@ SPSR_EL1: 0x600003c5
IRQ (I): Masked IRQ (I): Masked
FIQ (F): Masked FIQ (F): Masked
Illegal Execution State (IL): Not set Illegal Execution State (IL): Not set
ELR_EL1: 0x0000000000082580
General purpose register: General purpose register:
x0 : 0x0000000000000000 x1 : 0x00000000000858c7 x0 : 0x0000000000000000 x1 : 0x00000000000859b7
x2 : 0x0000000000000027 x3 : 0x0000000000084cc4 x2 : 0x0000000000000027 x3 : 0x0000000000084d3c
x4 : 0x0000000000000003 x5 : 0x3f27329400000000 x4 : 0x0000000000000003 x5 : 0x3f26329c00000000
x6 : 0x0000000000000000 x7 : 0xd3d0b80800000000 x6 : 0x0000000000000000 x7 : 0xd3d18800228d0241
x8 : 0x0000000240000000 x9 : 0x000000003f201000 x8 : 0x0000000240000000 x9 : 0x00000000000859b7
x10: 0x0000000000000019 x11: 0x0000000000000000 x10: 0x0000000000000443 x11: 0x000000003f201000
x12: 0x0000000000000001 x13: 0x0000000000000036 x12: 0x0000000000000019 x13: 0x0000000000000033
x14: 0x000000000007fc2d x15: 0x0000000000000000 x14: 0x000000000007fd3d x15: 0x0000000000000058
x16: 0x0000000000000040 x17: 0xfd39702255e846c0 x16: 0x0000000000000078 x17: 0xfd29f02255a847c0
x18: 0x9cd47880832f1200 x19: 0x0000000000090008 x18: 0x9cd4788000000008 x19: 0x0000000000090008
x20: 0x00000000000856b0 x21: 0x000000003b9aca00 x20: 0x00000000000857a0 x21: 0x000000003b9aca00
x22: 0x000000000008274c x23: 0x00000000000833d8 x22: 0x000000000008271c x23: 0x0000000000083314
x24: 0x00000000000003e8 x25: 0xffffffffc4653600 x24: 0x00000000000003e8 x25: 0xffffffffc4653600
x26: 0x00000000000f4240 x27: 0x0000000000085790 x26: 0x00000000000f4240 x27: 0x0000000000085880
x28: 0x0000000000086a50 x29: 0x00000000000867ed x28: 0x0000000000085170 x29: 0x0000000000086c10
lr : 0x000000000008256c lr : 0x0000000000082574
``` ```
## Diff to previous ## Diff to previous
@ -492,14 +496,14 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/Cargo.toml 11_exceptions_part1_g
diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs
--- 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs --- 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs
+++ 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs +++ 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs
@@ -11,8 +11,227 @@ @@ -11,8 +11,263 @@
//! //!
//! crate::exception::arch_exception //! crate::exception::arch_exception
-use cortex_a::registers::*; -use cortex_a::registers::*;
-use tock_registers::interfaces::Readable; -use tock_registers::interfaces::Readable;
+use core::{cell::UnsafeCell, fmt}; +use core::{cell::UnsafeCell, fmt};
+use cortex_a::{asm, asm::barrier, registers::*}; +use cortex_a::{asm::barrier, registers::*};
+use tock_registers::{ +use tock_registers::{
+ interfaces::{Readable, Writeable}, + interfaces::{Readable, Writeable},
+ registers::InMemoryRegister, + registers::InMemoryRegister,
@ -512,9 +516,10 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+// Private Definitions +// Private Definitions
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+ +
+/// Wrapper struct for memory copy of SPSR_EL1. +/// Wrapper structs for memory copies of registers.
+#[repr(transparent)] +#[repr(transparent)]
+struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>); +struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>);
+struct EsrEL1(InMemoryRegister<u64, ESR_EL1::Register>);
+ +
+/// The exception context as it is stored on the stack on exception entry. +/// The exception context as it is stored on the stack on exception entry.
+#[repr(C)] +#[repr(C)]
@ -530,25 +535,21 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+ +
+ /// Saved program status. + /// Saved program status.
+ spsr_el1: SpsrEL1, + spsr_el1: SpsrEL1,
+}
+ +
+/// Wrapper struct for pretty printing ESR_EL1. + // Exception syndrome register.
+struct EsrEL1; + esr_el1: EsrEL1,
+}
+ +
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+// Private Code +// Private Code
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+ +
+/// Prints verbose information about the exception and then panics. +/// Prints verbose information about the exception and then panics.
+fn default_exception_handler(e: &ExceptionContext) { +fn default_exception_handler(exc: &ExceptionContext) {
+ panic!( + panic!(
+ "\n\nCPU Exception!\n\ + "\n\nCPU Exception!\n\
+ FAR_EL1: {:#018x}\n\ + {}",
+ {}\n\ + exc
+ {}",
+ FAR_EL1.get(),
+ EsrEL1 {},
+ e
+ ); + );
+} +}
+ +
@ -577,14 +578,16 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+ +
+#[no_mangle] +#[no_mangle]
+unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { +unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
+ let far_el1 = FAR_EL1.get(); + if e.fault_address_valid() {
+ let far_el1 = FAR_EL1.get();
+ +
+ // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB, + // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB,
+ // advance the exception link register for one instruction, so that execution can continue. + // advance the exception link register for one instruction, so that execution can continue.
+ if far_el1 == 8 * 1024 * 1024 * 1024 { + if far_el1 == 8 * 1024 * 1024 * 1024 {
+ e.elr_el1 += 4; + e.elr_el1 += 4;
+ +
+ asm::eret() + return;
+ }
+ } + }
+ +
+ default_exception_handler(e); + default_exception_handler(e);
@ -639,33 +642,9 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+} +}
+ +
+//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------
+// Pretty printing +// Misc
+//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------
+ +
+/// Human readable ESR_EL1.
+#[rustfmt::skip]
+impl fmt::Display for EsrEL1 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let esr_el1 = ESR_EL1.extract();
+
+ // Raw print of whole register.
+ writeln!(f, "ESR_EL1: {:#010x}", esr_el1.get())?;
+
+ // Raw print of exception class.
+ write!(f, " Exception Class (EC) : {:#x}", esr_el1.read(ESR_EL1::EC))?;
+
+ // Exception class, translation.
+ let ec_translation = match esr_el1.read_as_enum(ESR_EL1::EC) {
+ Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
+ _ => "N/A",
+ };
+ writeln!(f, " - {}", ec_translation)?;
+
+ // Raw print of instruction specific syndrome.
+ write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))
+ }
+}
+
+/// Human readable SPSR_EL1. +/// Human readable SPSR_EL1.
+#[rustfmt::skip] +#[rustfmt::skip]
+impl fmt::Display for SpsrEL1 { +impl fmt::Display for SpsrEL1 {
@ -699,11 +678,72 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+ } + }
+} +}
+ +
+impl EsrEL1 {
+ #[inline(always)]
+ fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
+ self.0.read_as_enum(ESR_EL1::EC)
+ }
+}
+
+/// Human readable ESR_EL1.
+#[rustfmt::skip]
+impl fmt::Display for EsrEL1 {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // Raw print of whole register.
+ writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?;
+
+ // Raw print of exception class.
+ write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?;
+
+ // Exception class.
+ let ec_translation = match self.exception_class() {
+ Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
+ _ => "N/A",
+ };
+ writeln!(f, " - {}", ec_translation)?;
+
+ // Raw print of instruction specific syndrome.
+ write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS))
+ }
+}
+
+impl ExceptionContext {
+ #[inline(always)]
+ fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
+ self.esr_el1.exception_class()
+ }
+
+ #[inline(always)]
+ fn fault_address_valid(&self) -> bool {
+ use ESR_EL1::EC::Value::*;
+
+ match self.exception_class() {
+ None => false,
+ Some(ec) => matches!(
+ ec,
+ InstrAbortLowerEL
+ | InstrAbortCurrentEL
+ | PCAlignmentFault
+ | DataAbortLowerEL
+ | DataAbortCurrentEL
+ | WatchpointLowerEL
+ | WatchpointCurrentEL
+ ),
+ }
+ }
+}
+
+/// Human readable print of the exception context. +/// Human readable print of the exception context.
+impl fmt::Display for ExceptionContext { +impl fmt::Display for ExceptionContext {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; + writeln!(f, "{}", self.esr_el1)?;
+
+ if self.fault_address_valid() {
+ writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?;
+ }
+
+ writeln!(f, "{}", self.spsr_el1)?; + writeln!(f, "{}", self.spsr_el1)?;
+ writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?;
+ writeln!(f)?; + writeln!(f)?;
+ writeln!(f, "General purpose register:")?; + writeln!(f, "General purpose register:")?;
+ +
@ -722,7 +762,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Public Code // Public Code
@@ -29,3 +248,23 @@ @@ -29,3 +284,23 @@
_ => (PrivilegeLevel::Unknown, "Unknown"), _ => (PrivilegeLevel::Unknown, "Unknown"),
} }
} }
@ -750,7 +790,7 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s
--- 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s --- 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s
+++ 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s +++ 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s
@@ -0,0 +1,148 @@ @@ -0,0 +1,150 @@
+// SPDX-License-Identifier: MIT OR Apache-2.0 +// SPDX-License-Identifier: MIT OR Apache-2.0
+// +//
+// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com> +// Copyright (c) 2018-2021 Andre Richter <andre.o.richter@gmail.com>
@ -782,12 +822,14 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.s 11
+ stp x26, x27, [sp, #16 * 13] + stp x26, x27, [sp, #16 * 13]
+ stp x28, x29, [sp, #16 * 14] + stp x28, x29, [sp, #16 * 14]
+ +
+ // Add the exception link register (ELR_EL1) and the saved program status (SPSR_EL1). + // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
+ // syndrome register (ESR_EL1).
+ mrs x1, ELR_EL1 + mrs x1, ELR_EL1
+ mrs x2, SPSR_EL1 + mrs x2, SPSR_EL1
+ mrs x3, ESR_EL1
+ +
+ stp lr, x1, [sp, #16 * 15] + stp lr, x1, [sp, #16 * 15]
+ str x2, [sp, #16 * 16] + stp x2, x3, [sp, #16 * 16]
+ +
+ // x0 is the first argument for the function called through `\handler`. + // x0 is the first argument for the function called through `\handler`.
+ mov x0, sp + mov x0, sp

@ -12,7 +12,7 @@
//! crate::exception::arch_exception //! crate::exception::arch_exception
use core::{cell::UnsafeCell, fmt}; use core::{cell::UnsafeCell, fmt};
use cortex_a::{asm, asm::barrier, registers::*}; use cortex_a::{asm::barrier, registers::*};
use tock_registers::{ use tock_registers::{
interfaces::{Readable, Writeable}, interfaces::{Readable, Writeable},
registers::InMemoryRegister, registers::InMemoryRegister,
@ -25,9 +25,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1. /// Wrapper structs for memory copies of registers.
#[repr(transparent)] #[repr(transparent)]
struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>); struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>);
struct EsrEL1(InMemoryRegister<u64, ESR_EL1::Register>);
/// The exception context as it is stored on the stack on exception entry. /// The exception context as it is stored on the stack on exception entry.
#[repr(C)] #[repr(C)]
@ -43,25 +44,21 @@ struct ExceptionContext {
/// Saved program status. /// Saved program status.
spsr_el1: SpsrEL1, spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1. // Exception syndrome register.
struct EsrEL1; esr_el1: EsrEL1,
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Prints verbose information about the exception and then panics. /// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) { fn default_exception_handler(exc: &ExceptionContext) {
panic!( panic!(
"\n\nCPU Exception!\n\ "\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\ {}",
{}\n\ exc
{}",
FAR_EL1.get(),
EsrEL1 {},
e
); );
} }
@ -90,14 +87,16 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
let far_el1 = FAR_EL1.get(); if e.fault_address_valid() {
let far_el1 = FAR_EL1.get();
// This catches the demo case for this tutorial. If the fault address happens to be 8 GiB, // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB,
// advance the exception link register for one instruction, so that execution can continue. // advance the exception link register for one instruction, so that execution can continue.
if far_el1 == 8 * 1024 * 1024 * 1024 { if far_el1 == 8 * 1024 * 1024 * 1024 {
e.elr_el1 += 4; e.elr_el1 += 4;
asm::eret() return;
}
} }
default_exception_handler(e); default_exception_handler(e);
@ -152,33 +151,9 @@ unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Pretty printing // Misc
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let esr_el1 = ESR_EL1.extract();
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", esr_el1.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", esr_el1.read(ESR_EL1::EC))?;
// Exception class, translation.
let ec_translation = match esr_el1.read_as_enum(ESR_EL1::EC) {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))
}
}
/// Human readable SPSR_EL1. /// Human readable SPSR_EL1.
#[rustfmt::skip] #[rustfmt::skip]
impl fmt::Display for SpsrEL1 { impl fmt::Display for SpsrEL1 {
@ -212,11 +187,72 @@ impl fmt::Display for SpsrEL1 {
} }
} }
impl EsrEL1 {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
}
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?;
// Exception class.
let ec_translation = match self.exception_class() {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS))
}
}
impl ExceptionContext {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.esr_el1.exception_class()
}
#[inline(always)]
fn fault_address_valid(&self) -> bool {
use ESR_EL1::EC::Value::*;
match self.exception_class() {
None => false,
Some(ec) => matches!(
ec,
InstrAbortLowerEL
| InstrAbortCurrentEL
| PCAlignmentFault
| DataAbortLowerEL
| DataAbortCurrentEL
| WatchpointLowerEL
| WatchpointCurrentEL
),
}
}
}
/// Human readable print of the exception context. /// Human readable print of the exception context.
impl fmt::Display for ExceptionContext { impl fmt::Display for ExceptionContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; writeln!(f, "{}", self.esr_el1)?;
if self.fault_address_valid() {
writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?;
}
writeln!(f, "{}", self.spsr_el1)?; writeln!(f, "{}", self.spsr_el1)?;
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?; writeln!(f)?;
writeln!(f, "General purpose register:")?; writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13] stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14] stp x28, x29, [sp, #16 * 14]
// Add the exception link register (ELR_EL1) and the saved program status (SPSR_EL1). // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
// syndrome register (ESR_EL1).
mrs x1, ELR_EL1 mrs x1, ELR_EL1
mrs x2, SPSR_EL1 mrs x2, SPSR_EL1
mrs x3, ESR_EL1
stp lr, x1, [sp, #16 * 15] stp lr, x1, [sp, #16 * 15]
str x2, [sp, #16 * 16] stp x2, x3, [sp, #16 * 16]
// x0 is the first argument for the function called through `\handler`. // x0 is the first argument for the function called through `\handler`.
mov x0, sp mov x0, sp

@ -853,8 +853,8 @@ Compiling integration test(s) - rpi3
Kernel panic: Kernel panic:
CPU Exception! CPU Exception!
FAR_EL1: 0x0000000240000000
ESR_EL1: 0x96000004 ESR_EL1: 0x96000004
Exception Class (EC) : 0x25 - Data Abort, current EL
[...] [...]
------------------------------------------------------------------- -------------------------------------------------------------------
@ -1070,27 +1070,20 @@ diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs 12_integrated_
diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs 12_integrated_testing/src/_arch/aarch64/exception.rs diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs 12_integrated_testing/src/_arch/aarch64/exception.rs
--- 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs --- 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs
+++ 12_integrated_testing/src/_arch/aarch64/exception.rs +++ 12_integrated_testing/src/_arch/aarch64/exception.rs
@@ -12,7 +12,7 @@ @@ -87,18 +87,6 @@
//! crate::exception::arch_exception
use core::{cell::UnsafeCell, fmt};
-use cortex_a::{asm, asm::barrier, registers::*};
+use cortex_a::{asm::barrier, registers::*};
use tock_registers::{
interfaces::{Readable, Writeable},
registers::InMemoryRegister,
@@ -90,16 +90,6 @@
#[no_mangle] #[no_mangle]
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) { unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
- let far_el1 = FAR_EL1.get(); - if e.fault_address_valid() {
- let far_el1 = FAR_EL1.get();
- -
- // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB, - // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB,
- // advance the exception link register for one instruction, so that execution can continue. - // advance the exception link register for one instruction, so that execution can continue.
- if far_el1 == 8 * 1024 * 1024 * 1024 { - if far_el1 == 8 * 1024 * 1024 * 1024 {
- e.elr_el1 += 4; - e.elr_el1 += 4;
- -
- asm::eret() - return;
- }
- } - }
- -
default_exception_handler(e); default_exception_handler(e);

@ -25,9 +25,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1. /// Wrapper structs for memory copies of registers.
#[repr(transparent)] #[repr(transparent)]
struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>); struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>);
struct EsrEL1(InMemoryRegister<u64, ESR_EL1::Register>);
/// The exception context as it is stored on the stack on exception entry. /// The exception context as it is stored on the stack on exception entry.
#[repr(C)] #[repr(C)]
@ -43,25 +44,21 @@ struct ExceptionContext {
/// Saved program status. /// Saved program status.
spsr_el1: SpsrEL1, spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1. // Exception syndrome register.
struct EsrEL1; esr_el1: EsrEL1,
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Prints verbose information about the exception and then panics. /// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) { fn default_exception_handler(exc: &ExceptionContext) {
panic!( panic!(
"\n\nCPU Exception!\n\ "\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\ {}",
{}\n\ exc
{}",
FAR_EL1.get(),
EsrEL1 {},
e
); );
} }
@ -142,33 +139,9 @@ unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Pretty printing // Misc
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let esr_el1 = ESR_EL1.extract();
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", esr_el1.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", esr_el1.read(ESR_EL1::EC))?;
// Exception class, translation.
let ec_translation = match esr_el1.read_as_enum(ESR_EL1::EC) {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))
}
}
/// Human readable SPSR_EL1. /// Human readable SPSR_EL1.
#[rustfmt::skip] #[rustfmt::skip]
impl fmt::Display for SpsrEL1 { impl fmt::Display for SpsrEL1 {
@ -202,11 +175,72 @@ impl fmt::Display for SpsrEL1 {
} }
} }
impl EsrEL1 {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
}
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?;
// Exception class.
let ec_translation = match self.exception_class() {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS))
}
}
impl ExceptionContext {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.esr_el1.exception_class()
}
#[inline(always)]
fn fault_address_valid(&self) -> bool {
use ESR_EL1::EC::Value::*;
match self.exception_class() {
None => false,
Some(ec) => matches!(
ec,
InstrAbortLowerEL
| InstrAbortCurrentEL
| PCAlignmentFault
| DataAbortLowerEL
| DataAbortCurrentEL
| WatchpointLowerEL
| WatchpointCurrentEL
),
}
}
}
/// Human readable print of the exception context. /// Human readable print of the exception context.
impl fmt::Display for ExceptionContext { impl fmt::Display for ExceptionContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; writeln!(f, "{}", self.esr_el1)?;
if self.fault_address_valid() {
writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?;
}
writeln!(f, "{}", self.spsr_el1)?; writeln!(f, "{}", self.spsr_el1)?;
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?; writeln!(f)?;
writeln!(f, "General purpose register:")?; writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13] stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14] stp x28, x29, [sp, #16 * 14]
// Add the exception link register (ELR_EL1) and the saved program status (SPSR_EL1). // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
// syndrome register (ESR_EL1).
mrs x1, ELR_EL1 mrs x1, ELR_EL1
mrs x2, SPSR_EL1 mrs x2, SPSR_EL1
mrs x3, ESR_EL1
stp lr, x1, [sp, #16 * 15] stp lr, x1, [sp, #16 * 15]
str x2, [sp, #16 * 16] stp x2, x3, [sp, #16 * 16]
// x0 is the first argument for the function called through `\handler`. // x0 is the first argument for the function called through `\handler`.
mov x0, sp mov x0, sp

@ -911,7 +911,7 @@ diff -uNr 12_integrated_testing/src/_arch/aarch64/exception.rs 13_exceptions_par
use core::{cell::UnsafeCell, fmt}; use core::{cell::UnsafeCell, fmt};
use cortex_a::{asm::barrier, registers::*}; use cortex_a::{asm::barrier, registers::*};
use tock_registers::{ use tock_registers::{
@@ -94,8 +95,11 @@ @@ -91,8 +92,11 @@
} }
#[no_mangle] #[no_mangle]

@ -26,9 +26,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1. /// Wrapper structs for memory copies of registers.
#[repr(transparent)] #[repr(transparent)]
struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>); struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>);
struct EsrEL1(InMemoryRegister<u64, ESR_EL1::Register>);
/// The exception context as it is stored on the stack on exception entry. /// The exception context as it is stored on the stack on exception entry.
#[repr(C)] #[repr(C)]
@ -44,25 +45,21 @@ struct ExceptionContext {
/// Saved program status. /// Saved program status.
spsr_el1: SpsrEL1, spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1. // Exception syndrome register.
struct EsrEL1; esr_el1: EsrEL1,
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Prints verbose information about the exception and then panics. /// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) { fn default_exception_handler(exc: &ExceptionContext) {
panic!( panic!(
"\n\nCPU Exception!\n\ "\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\ {}",
{}\n\ exc
{}",
FAR_EL1.get(),
EsrEL1 {},
e
); );
} }
@ -146,33 +143,9 @@ unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Pretty printing // Misc
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let esr_el1 = ESR_EL1.extract();
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", esr_el1.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", esr_el1.read(ESR_EL1::EC))?;
// Exception class, translation.
let ec_translation = match esr_el1.read_as_enum(ESR_EL1::EC) {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))
}
}
/// Human readable SPSR_EL1. /// Human readable SPSR_EL1.
#[rustfmt::skip] #[rustfmt::skip]
impl fmt::Display for SpsrEL1 { impl fmt::Display for SpsrEL1 {
@ -206,11 +179,72 @@ impl fmt::Display for SpsrEL1 {
} }
} }
impl EsrEL1 {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
}
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?;
// Exception class.
let ec_translation = match self.exception_class() {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS))
}
}
impl ExceptionContext {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.esr_el1.exception_class()
}
#[inline(always)]
fn fault_address_valid(&self) -> bool {
use ESR_EL1::EC::Value::*;
match self.exception_class() {
None => false,
Some(ec) => matches!(
ec,
InstrAbortLowerEL
| InstrAbortCurrentEL
| PCAlignmentFault
| DataAbortLowerEL
| DataAbortCurrentEL
| WatchpointLowerEL
| WatchpointCurrentEL
),
}
}
}
/// Human readable print of the exception context. /// Human readable print of the exception context.
impl fmt::Display for ExceptionContext { impl fmt::Display for ExceptionContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; writeln!(f, "{}", self.esr_el1)?;
if self.fault_address_valid() {
writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?;
}
writeln!(f, "{}", self.spsr_el1)?; writeln!(f, "{}", self.spsr_el1)?;
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?; writeln!(f)?;
writeln!(f, "General purpose register:")?; writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13] stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14] stp x28, x29, [sp, #16 * 14]
// Add the exception link register (ELR_EL1) and the saved program status (SPSR_EL1). // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
// syndrome register (ESR_EL1).
mrs x1, ELR_EL1 mrs x1, ELR_EL1
mrs x2, SPSR_EL1 mrs x2, SPSR_EL1
mrs x3, ESR_EL1
stp lr, x1, [sp, #16 * 15] stp lr, x1, [sp, #16 * 15]
str x2, [sp, #16 * 16] stp x2, x3, [sp, #16 * 16]
// x0 is the first argument for the function called through `\handler`. // x0 is the first argument for the function called through `\handler`.
mov x0, sp mov x0, sp

@ -279,10 +279,6 @@ through them:
- [`src/bsp/raspberrypi/memory.rs`](src/bsp/raspberrypi/memory.rs) and - [`src/bsp/raspberrypi/memory.rs`](src/bsp/raspberrypi/memory.rs) and
[`src/bsp/raspberrypi/link.ld`](src/bsp/raspberrypi/link.ld) changed the location of the boot [`src/bsp/raspberrypi/link.ld`](src/bsp/raspberrypi/link.ld) changed the location of the boot
core's stack. It is now located after the data segment, and separated by an unmapped `guard page`. core's stack. It is now located after the data segment, and separated by an unmapped `guard page`.
There is also supporting code in
[`src/_arch/aarch64/exception.rs`](src/_arch/aarch64/exception.rs) that runs on data aborts and
checks if the fault address lies within the `stack guard page`. This can be an indication that a
kernel stack overflow happened.
- [`src/memory/mmu/types.rs`](src/memory/mmu/types.rs) introduces a couple of supporting types, like - [`src/memory/mmu/types.rs`](src/memory/mmu/types.rs) introduces a couple of supporting types, like
`Page<ATYPE>`. `Page<ATYPE>`.
- [`src/memory/mmu/mapping_record.rs`](src/memory/mmu/mapping_record.rs) provides the generic kernel - [`src/memory/mmu/mapping_record.rs`](src/memory/mmu/mapping_record.rs) provides the generic kernel
@ -383,55 +379,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/Cargo.toml 14_virtual_mem_part2_mm
edition = "2021" edition = "2021"
diff -uNr 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs
--- 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs
+++ 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs
@@ -11,7 +11,11 @@
//!
//! crate::exception::arch_exception
-use crate::{bsp, exception};
+use crate::{
+ bsp::{self},
+ exception,
+ memory::Address,
+};
use core::{cell::UnsafeCell, fmt};
use cortex_a::{asm::barrier, registers::*};
use tock_registers::{
@@ -53,6 +57,20 @@
// Private Code
//--------------------------------------------------------------------------------------------------
+/// Check if additional context can be derived from a data abort.
+fn inspect_data_abort(f: &mut fmt::Formatter) -> fmt::Result {
+ let fault_addr = Address::new(FAR_EL1.get() as usize);
+
+ if bsp::memory::mmu::virt_boot_core_stack_guard_page_desc().contains(fault_addr) {
+ writeln!(
+ f,
+ "\n\n >> Attempted to access the guard page of the kernel's boot core stack <<"
+ )?;
+ }
+
+ Ok(())
+}
+
/// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) {
panic!(
@@ -169,7 +187,9 @@
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
- write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))
+ write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?;
+
+ inspect_data_abort(f)
}
}
diff -uNr 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs diff -uNr 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs
--- 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs --- 13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/memory/mmu/translation_table.rs
+++ 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs +++ 14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/memory/mmu/translation_table.rs
@ -1495,7 +1442,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld 14_vir
.data : { *(.data*) } :segment_rw .data : { *(.data*) } :segment_rw
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */ /* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
@@ -54,4 +50,23 @@ @@ -54,4 +50,21 @@
. = ALIGN(16); . = ALIGN(16);
__bss_end_exclusive = .; __bss_end_exclusive = .;
} :NONE } :NONE
@ -1506,9 +1453,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld 14_vir
+ /*********************************************************************************************** + /***********************************************************************************************
+ * Guard Page between boot core stack and data + * Guard Page between boot core stack and data
+ ***********************************************************************************************/ + ***********************************************************************************************/
+ __boot_core_stack_guard_page_start = .;
+ . += 64K; + . += 64K;
+ __boot_core_stack_guard_page_end_exclusive = .;
+ +
+ /*********************************************************************************************** + /***********************************************************************************************
+ * Boot Core Stack + * Boot Core Stack
@ -1523,7 +1468,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld 14_vir
diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs
--- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs --- 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
+++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs +++ 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs
@@ -4,70 +4,164 @@ @@ -4,70 +4,157 @@
//! BSP Memory Management Unit. //! BSP Memory Management Unit.
@ -1559,16 +1504,16 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
+/// The translation granule chosen by this BSP. This will be used everywhere else in the kernel to +/// The translation granule chosen by this BSP. This will be used everywhere else in the kernel to
+/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`. +/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`.
+pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>; +pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>;
+
-const NUM_MEM_RANGES: usize = 2;
+/// The kernel's virtual address space defined by this BSP. +/// The kernel's virtual address space defined by this BSP.
+pub type KernelVirtAddrSpace = AddressSpace<{ 8 * 1024 * 1024 * 1024 }>; +pub type KernelVirtAddrSpace = AddressSpace<{ 8 * 1024 * 1024 * 1024 }>;
-/// The virtual memory layout. -const NUM_MEM_RANGES: usize = 2;
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+// Global instances +// Global instances
+//-------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------
+
-/// The virtual memory layout.
+/// The kernel translation tables. +/// The kernel translation tables.
/// ///
-/// The layout must contain only special ranges, aka anything that is _not_ normal cacheable DRAM. -/// The layout must contain only special ranges, aka anything that is _not_ normal cacheable DRAM.
@ -1647,15 +1592,15 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
+/// The Read+Execute (RX) pages of the kernel binary. +/// The Read+Execute (RX) pages of the kernel binary.
+fn phys_rx_page_desc() -> PageSliceDescriptor<Physical> { +fn phys_rx_page_desc() -> PageSliceDescriptor<Physical> {
+ virt_rx_page_desc().into() + virt_rx_page_desc().into()
+}
+
+/// The Read+Write (RW) pages of the kernel binary.
+fn phys_rw_page_desc() -> PageSliceDescriptor<Physical> {
+ virt_rw_page_desc().into()
} }
-fn mmio_range_inclusive() -> RangeInclusive<usize> { -fn mmio_range_inclusive() -> RangeInclusive<usize> {
- RangeInclusive::new(memory_map::mmio::START, memory_map::mmio::END_INCLUSIVE) - RangeInclusive::new(memory_map::mmio::START, memory_map::mmio::END_INCLUSIVE)
+/// The Read+Write (RW) pages of the kernel binary.
+fn phys_rw_page_desc() -> PageSliceDescriptor<Physical> {
+ virt_rw_page_desc().into()
+}
+
+/// The boot core's stack. +/// The boot core's stack.
+fn phys_boot_core_stack_page_desc() -> PageSliceDescriptor<Physical> { +fn phys_boot_core_stack_page_desc() -> PageSliceDescriptor<Physical> {
+ virt_boot_core_stack_page_desc().into() + virt_boot_core_stack_page_desc().into()
@ -1673,13 +1618,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
+ &KERNEL_TABLES + &KERNEL_TABLES
+} +}
+ +
+/// The boot core's stack guard page.
+pub fn virt_boot_core_stack_guard_page_desc() -> PageSliceDescriptor<Virtual> {
+ let num_pages = size_to_num_pages(super::boot_core_stack_guard_page_size());
+
+ PageSliceDescriptor::from_addr(super::virt_boot_core_stack_guard_page_start(), num_pages)
+}
+
+/// Pointer to the last page of the physical address space. +/// Pointer to the last page of the physical address space.
+pub fn phys_addr_space_end_page() -> *const Page<Physical> { +pub fn phys_addr_space_end_page() -> *const Page<Physical> {
+ common::align_down( + common::align_down(
@ -1731,7 +1669,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -77,19 +171,24 @@ @@ -77,19 +164,24 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -1742,6 +1680,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
#[kernel_test] #[kernel_test]
fn virt_mem_layout_sections_are_64KiB_aligned() { fn virt_mem_layout_sections_are_64KiB_aligned() {
- const SIXTYFOUR_KIB: usize = 65536; - const SIXTYFOUR_KIB: usize = 65536;
-
- for i in LAYOUT.inner().iter() {
- let start: usize = *(i.virtual_range)().start();
- let end: usize = *(i.virtual_range)().end() + 1;
+ for i in [ + for i in [
+ virt_rx_page_desc, + virt_rx_page_desc,
+ virt_rw_page_desc, + virt_rw_page_desc,
@ -1752,10 +1694,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
+ let start: usize = i().start_addr().into_usize(); + let start: usize = i().start_addr().into_usize();
+ let end: usize = i().end_addr().into_usize(); + let end: usize = i().end_addr().into_usize();
- for i in LAYOUT.inner().iter() {
- let start: usize = *(i.virtual_range)().start();
- let end: usize = *(i.virtual_range)().end() + 1;
-
- assert_eq!(start modulo SIXTYFOUR_KIB, 0); - assert_eq!(start modulo SIXTYFOUR_KIB, 0);
- assert_eq!(end modulo SIXTYFOUR_KIB, 0); - assert_eq!(end modulo SIXTYFOUR_KIB, 0);
+ assert_eq!(start modulo KernelGranule::SIZE, 0); + assert_eq!(start modulo KernelGranule::SIZE, 0);
@ -1763,7 +1701,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
assert!(end >= start); assert!(end >= start);
} }
} }
@@ -97,18 +196,38 @@ @@ -97,18 +189,38 @@
/// Ensure the kernel's virtual memory layout is free of overlaps. /// Ensure the kernel's virtual memory layout is free of overlaps.
#[kernel_test] #[kernel_test]
fn virt_mem_layout_has_no_overlaps() { fn virt_mem_layout_has_no_overlaps() {
@ -1953,7 +1891,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 14_v
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -80,16 +120,67 @@ @@ -80,16 +120,52 @@
/// ///
/// - Value is provided by the linker script and must be trusted as-is. /// - Value is provided by the linker script and must be trusted as-is.
#[inline(always)] #[inline(always)]
@ -1961,26 +1899,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 14_v
- unsafe { __rx_start.get() as usize } - unsafe { __rx_start.get() as usize }
+fn virt_rx_start() -> Address<Virtual> { +fn virt_rx_start() -> Address<Virtual> {
+ Address::new(unsafe { __rx_start.get() as usize }) + Address::new(unsafe { __rx_start.get() as usize })
+}
+
+/// Size of the Read+Execute (RX) range.
+///
+/// # Safety
+///
+/// - Value is provided by the linker script and must be trusted as-is.
+#[inline(always)]
+fn rx_size() -> usize {
+ unsafe { (__rx_end_exclusive.get() as usize) - (__rx_start.get() as usize) }
} }
-/// Exclusive end address of the Read+Execute (RX) range. -/// Exclusive end address of the Read+Execute (RX) range.
+/// Start address of the Read+Write (RW) range. +/// Size of the Read+Execute (RX) range.
+#[inline(always)]
+fn virt_rw_start() -> Address<Virtual> {
+ Address::new(unsafe { __rw_start.get() as usize })
+}
+
+/// Size of the Read+Write (RW) range.
/// ///
/// # Safety /// # Safety
/// ///
@ -1988,6 +1910,22 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 14_v
#[inline(always)] #[inline(always)]
-fn rx_end_exclusive() -> usize { -fn rx_end_exclusive() -> usize {
- unsafe { __rx_end_exclusive.get() as usize } - unsafe { __rx_end_exclusive.get() as usize }
+fn rx_size() -> usize {
+ unsafe { (__rx_end_exclusive.get() as usize) - (__rx_start.get() as usize) }
+}
+
+/// Start address of the Read+Write (RW) range.
+#[inline(always)]
+fn virt_rw_start() -> Address<Virtual> {
+ Address::new(unsafe { __rw_start.get() as usize })
+}
+
+/// Size of the Read+Write (RW) range.
+///
+/// # Safety
+///
+/// - Value is provided by the linker script and must be trusted as-is.
+#[inline(always)]
+fn rw_size() -> usize { +fn rw_size() -> usize {
+ unsafe { (__rw_end_exclusive.get() as usize) - (__rw_start.get() as usize) } + unsafe { (__rw_end_exclusive.get() as usize) - (__rw_start.get() as usize) }
+} +}
@ -2006,21 +1944,6 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 14_v
+ } + }
+} +}
+ +
+/// Start address of the boot core's stack guard page.
+#[inline(always)]
+fn virt_boot_core_stack_guard_page_start() -> Address<Virtual> {
+ Address::new(unsafe { __boot_core_stack_guard_page_start.get() as usize })
+}
+
+/// Size of the boot core's stack guard page.
+#[inline(always)]
+fn boot_core_stack_guard_page_size() -> usize {
+ unsafe {
+ (__boot_core_stack_guard_page_end_exclusive.get() as usize)
+ - (__boot_core_stack_guard_page_start.get() as usize)
+ }
+}
+
+/// Exclusive end address of the physical address space. +/// Exclusive end address of the physical address space.
+#[inline(always)] +#[inline(always)]
+fn phys_addr_space_end() -> Address<Physical> { +fn phys_addr_space_end() -> Address<Physical> {

@ -11,11 +11,7 @@
//! //!
//! crate::exception::arch_exception //! crate::exception::arch_exception
use crate::{ use crate::{bsp, exception};
bsp::{self},
exception,
memory::Address,
};
use core::{cell::UnsafeCell, fmt}; use core::{cell::UnsafeCell, fmt};
use cortex_a::{asm::barrier, registers::*}; use cortex_a::{asm::barrier, registers::*};
use tock_registers::{ use tock_registers::{
@ -30,9 +26,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1. /// Wrapper structs for memory copies of registers.
#[repr(transparent)] #[repr(transparent)]
struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>); struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>);
struct EsrEL1(InMemoryRegister<u64, ESR_EL1::Register>);
/// The exception context as it is stored on the stack on exception entry. /// The exception context as it is stored on the stack on exception entry.
#[repr(C)] #[repr(C)]
@ -48,39 +45,21 @@ struct ExceptionContext {
/// Saved program status. /// Saved program status.
spsr_el1: SpsrEL1, spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1. // Exception syndrome register.
struct EsrEL1; esr_el1: EsrEL1,
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Check if additional context can be derived from a data abort.
fn inspect_data_abort(f: &mut fmt::Formatter) -> fmt::Result {
let fault_addr = Address::new(FAR_EL1.get() as usize);
if bsp::memory::mmu::virt_boot_core_stack_guard_page_desc().contains(fault_addr) {
writeln!(
f,
"\n\n >> Attempted to access the guard page of the kernel's boot core stack <<"
)?;
}
Ok(())
}
/// Prints verbose information about the exception and then panics. /// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) { fn default_exception_handler(exc: &ExceptionContext) {
panic!( panic!(
"\n\nCPU Exception!\n\ "\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\ {}",
{}\n\ exc
{}",
FAR_EL1.get(),
EsrEL1 {},
e
); );
} }
@ -164,35 +143,9 @@ unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Pretty printing // Misc
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let esr_el1 = ESR_EL1.extract();
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", esr_el1.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", esr_el1.read(ESR_EL1::EC))?;
// Exception class, translation.
let ec_translation = match esr_el1.read_as_enum(ESR_EL1::EC) {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?;
inspect_data_abort(f)
}
}
/// Human readable SPSR_EL1. /// Human readable SPSR_EL1.
#[rustfmt::skip] #[rustfmt::skip]
impl fmt::Display for SpsrEL1 { impl fmt::Display for SpsrEL1 {
@ -226,11 +179,72 @@ impl fmt::Display for SpsrEL1 {
} }
} }
impl EsrEL1 {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
}
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?;
// Exception class.
let ec_translation = match self.exception_class() {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS))
}
}
impl ExceptionContext {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.esr_el1.exception_class()
}
#[inline(always)]
fn fault_address_valid(&self) -> bool {
use ESR_EL1::EC::Value::*;
match self.exception_class() {
None => false,
Some(ec) => matches!(
ec,
InstrAbortLowerEL
| InstrAbortCurrentEL
| PCAlignmentFault
| DataAbortLowerEL
| DataAbortCurrentEL
| WatchpointLowerEL
| WatchpointCurrentEL
),
}
}
}
/// Human readable print of the exception context. /// Human readable print of the exception context.
impl fmt::Display for ExceptionContext { impl fmt::Display for ExceptionContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; writeln!(f, "{}", self.esr_el1)?;
if self.fault_address_valid() {
writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?;
}
writeln!(f, "{}", self.spsr_el1)?; writeln!(f, "{}", self.spsr_el1)?;
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?; writeln!(f)?;
writeln!(f, "General purpose register:")?; writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13] stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14] stp x28, x29, [sp, #16 * 14]
// Add the exception link register (ELR_EL1) and the saved program status (SPSR_EL1). // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
// syndrome register (ESR_EL1).
mrs x1, ELR_EL1 mrs x1, ELR_EL1
mrs x2, SPSR_EL1 mrs x2, SPSR_EL1
mrs x3, ESR_EL1
stp lr, x1, [sp, #16 * 15] stp lr, x1, [sp, #16 * 15]
str x2, [sp, #16 * 16] stp x2, x3, [sp, #16 * 16]
// x0 is the first argument for the function called through `\handler`. // x0 is the first argument for the function called through `\handler`.
mov x0, sp mov x0, sp

@ -57,9 +57,7 @@ SECTIONS
/*********************************************************************************************** /***********************************************************************************************
* Guard Page between boot core stack and data * Guard Page between boot core stack and data
***********************************************************************************************/ ***********************************************************************************************/
__boot_core_stack_guard_page_start = .;
. += 64K; . += 64K;
__boot_core_stack_guard_page_end_exclusive = .;
/*********************************************************************************************** /***********************************************************************************************
* Boot Core Stack * Boot Core Stack

@ -164,21 +164,6 @@ fn boot_core_stack_size() -> usize {
} }
} }
/// Start address of the boot core's stack guard page.
#[inline(always)]
fn virt_boot_core_stack_guard_page_start() -> Address<Virtual> {
Address::new(unsafe { __boot_core_stack_guard_page_start.get() as usize })
}
/// Size of the boot core's stack guard page.
#[inline(always)]
fn boot_core_stack_guard_page_size() -> usize {
unsafe {
(__boot_core_stack_guard_page_end_exclusive.get() as usize)
- (__boot_core_stack_guard_page_start.get() as usize)
}
}
/// Exclusive end address of the physical address space. /// Exclusive end address of the physical address space.
#[inline(always)] #[inline(always)]
fn phys_addr_space_end() -> Address<Physical> { fn phys_addr_space_end() -> Address<Physical> {

@ -107,13 +107,6 @@ pub fn kernel_translation_tables() -> &'static InitStateLock<KernelTranslationTa
&KERNEL_TABLES &KERNEL_TABLES
} }
/// The boot core's stack guard page.
pub fn virt_boot_core_stack_guard_page_desc() -> PageSliceDescriptor<Virtual> {
let num_pages = size_to_num_pages(super::boot_core_stack_guard_page_size());
PageSliceDescriptor::from_addr(super::virt_boot_core_stack_guard_page_start(), num_pages)
}
/// Pointer to the last page of the physical address space. /// Pointer to the last page of the physical address space.
pub fn phys_addr_space_end_page() -> *const Page<Physical> { pub fn phys_addr_space_end_page() -> *const Page<Physical> {
common::align_down( common::align_down(

@ -1166,7 +1166,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs 15_v
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -122,13 +144,15 @@ @@ -115,13 +137,15 @@
) as *const Page<_> ) as *const Page<_>
} }
@ -1187,7 +1187,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs 15_v
"Kernel code and RO data", "Kernel code and RO data",
&virt_rx_page_desc(), &virt_rx_page_desc(),
&phys_rx_page_desc(), &phys_rx_page_desc(),
@@ -137,9 +161,9 @@ @@ -130,9 +154,9 @@
acc_perms: AccessPermissions::ReadOnly, acc_perms: AccessPermissions::ReadOnly,
execute_never: false, execute_never: false,
}, },
@ -1199,7 +1199,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs 15_v
"Kernel data and bss", "Kernel data and bss",
&virt_rw_page_desc(), &virt_rw_page_desc(),
&phys_rw_page_desc(), &phys_rw_page_desc(),
@@ -148,9 +172,9 @@ @@ -141,9 +165,9 @@
acc_perms: AccessPermissions::ReadWrite, acc_perms: AccessPermissions::ReadWrite,
execute_never: true, execute_never: true,
}, },
@ -1211,7 +1211,7 @@ diff -uNr 14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs 15_v
"Kernel boot-core stack", "Kernel boot-core stack",
&virt_boot_core_stack_page_desc(), &virt_boot_core_stack_page_desc(),
&phys_boot_core_stack_page_desc(), &phys_boot_core_stack_page_desc(),
@@ -159,75 +183,5 @@ @@ -152,75 +176,5 @@
acc_perms: AccessPermissions::ReadWrite, acc_perms: AccessPermissions::ReadWrite,
execute_never: true, execute_never: true,
}, },

@ -11,11 +11,7 @@
//! //!
//! crate::exception::arch_exception //! crate::exception::arch_exception
use crate::{ use crate::{bsp, exception};
bsp::{self},
exception,
memory::Address,
};
use core::{cell::UnsafeCell, fmt}; use core::{cell::UnsafeCell, fmt};
use cortex_a::{asm::barrier, registers::*}; use cortex_a::{asm::barrier, registers::*};
use tock_registers::{ use tock_registers::{
@ -30,9 +26,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1. /// Wrapper structs for memory copies of registers.
#[repr(transparent)] #[repr(transparent)]
struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>); struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>);
struct EsrEL1(InMemoryRegister<u64, ESR_EL1::Register>);
/// The exception context as it is stored on the stack on exception entry. /// The exception context as it is stored on the stack on exception entry.
#[repr(C)] #[repr(C)]
@ -48,39 +45,21 @@ struct ExceptionContext {
/// Saved program status. /// Saved program status.
spsr_el1: SpsrEL1, spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1. // Exception syndrome register.
struct EsrEL1; esr_el1: EsrEL1,
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Check if additional context can be derived from a data abort.
fn inspect_data_abort(f: &mut fmt::Formatter) -> fmt::Result {
let fault_addr = Address::new(FAR_EL1.get() as usize);
if bsp::memory::mmu::virt_boot_core_stack_guard_page_desc().contains(fault_addr) {
writeln!(
f,
"\n\n >> Attempted to access the guard page of the kernel's boot core stack <<"
)?;
}
Ok(())
}
/// Prints verbose information about the exception and then panics. /// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) { fn default_exception_handler(exc: &ExceptionContext) {
panic!( panic!(
"\n\nCPU Exception!\n\ "\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\ {}",
{}\n\ exc
{}",
FAR_EL1.get(),
EsrEL1 {},
e
); );
} }
@ -164,35 +143,9 @@ unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Pretty printing // Misc
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let esr_el1 = ESR_EL1.extract();
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", esr_el1.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", esr_el1.read(ESR_EL1::EC))?;
// Exception class, translation.
let ec_translation = match esr_el1.read_as_enum(ESR_EL1::EC) {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?;
inspect_data_abort(f)
}
}
/// Human readable SPSR_EL1. /// Human readable SPSR_EL1.
#[rustfmt::skip] #[rustfmt::skip]
impl fmt::Display for SpsrEL1 { impl fmt::Display for SpsrEL1 {
@ -226,11 +179,72 @@ impl fmt::Display for SpsrEL1 {
} }
} }
impl EsrEL1 {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
}
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?;
// Exception class.
let ec_translation = match self.exception_class() {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS))
}
}
impl ExceptionContext {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.esr_el1.exception_class()
}
#[inline(always)]
fn fault_address_valid(&self) -> bool {
use ESR_EL1::EC::Value::*;
match self.exception_class() {
None => false,
Some(ec) => matches!(
ec,
InstrAbortLowerEL
| InstrAbortCurrentEL
| PCAlignmentFault
| DataAbortLowerEL
| DataAbortCurrentEL
| WatchpointLowerEL
| WatchpointCurrentEL
),
}
}
}
/// Human readable print of the exception context. /// Human readable print of the exception context.
impl fmt::Display for ExceptionContext { impl fmt::Display for ExceptionContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; writeln!(f, "{}", self.esr_el1)?;
if self.fault_address_valid() {
writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?;
}
writeln!(f, "{}", self.spsr_el1)?; writeln!(f, "{}", self.spsr_el1)?;
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?; writeln!(f)?;
writeln!(f, "General purpose register:")?; writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13] stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14] stp x28, x29, [sp, #16 * 14]
// Add the exception link register (ELR_EL1) and the saved program status (SPSR_EL1). // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
// syndrome register (ESR_EL1).
mrs x1, ELR_EL1 mrs x1, ELR_EL1
mrs x2, SPSR_EL1 mrs x2, SPSR_EL1
mrs x3, ESR_EL1
stp lr, x1, [sp, #16 * 15] stp lr, x1, [sp, #16 * 15]
str x2, [sp, #16 * 16] stp x2, x3, [sp, #16 * 16]
// x0 is the first argument for the function called through `\handler`. // x0 is the first argument for the function called through `\handler`.
mov x0, sp mov x0, sp

@ -60,9 +60,7 @@ SECTIONS
/*********************************************************************************************** /***********************************************************************************************
* Guard Page between boot core stack and data * Guard Page between boot core stack and data
***********************************************************************************************/ ***********************************************************************************************/
__boot_core_stack_guard_page_start = .;
. += 64K; . += 64K;
__boot_core_stack_guard_page_end_exclusive = .;
/*********************************************************************************************** /***********************************************************************************************
* Boot Core Stack * Boot Core Stack

@ -164,21 +164,6 @@ fn boot_core_stack_size() -> usize {
} }
} }
/// Start address of the boot core's stack guard page.
#[inline(always)]
fn virt_boot_core_stack_guard_page_start() -> Address<Virtual> {
Address::new(unsafe { __boot_core_stack_guard_page_start.get() as usize })
}
/// Size of the boot core's stack guard page.
#[inline(always)]
fn boot_core_stack_guard_page_size() -> usize {
unsafe {
(__boot_core_stack_guard_page_end_exclusive.get() as usize)
- (__boot_core_stack_guard_page_start.get() as usize)
}
}
/// Exclusive end address of the physical address space. /// Exclusive end address of the physical address space.
#[inline(always)] #[inline(always)]
fn phys_addr_space_end() -> Address<Physical> { fn phys_addr_space_end() -> Address<Physical> {

@ -129,13 +129,6 @@ pub fn kernel_translation_tables() -> &'static InitStateLock<KernelTranslationTa
&KERNEL_TABLES &KERNEL_TABLES
} }
/// The boot core's stack guard page.
pub fn virt_boot_core_stack_guard_page_desc() -> PageSliceDescriptor<Virtual> {
let num_pages = size_to_num_pages(super::boot_core_stack_guard_page_size());
PageSliceDescriptor::from_addr(super::virt_boot_core_stack_guard_page_start(), num_pages)
}
/// Pointer to the last page of the physical address space. /// Pointer to the last page of the physical address space.
pub fn phys_addr_space_end_page() -> *const Page<Physical> { pub fn phys_addr_space_end_page() -> *const Page<Physical> {
common::align_down( common::align_down(

@ -11,11 +11,7 @@
//! //!
//! crate::exception::arch_exception //! crate::exception::arch_exception
use crate::{ use crate::{bsp, exception};
bsp::{self},
exception,
memory::Address,
};
use core::{cell::UnsafeCell, fmt}; use core::{cell::UnsafeCell, fmt};
use cortex_a::{asm::barrier, registers::*}; use cortex_a::{asm::barrier, registers::*};
use tock_registers::{ use tock_registers::{
@ -30,9 +26,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions // Private Definitions
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1. /// Wrapper structs for memory copies of registers.
#[repr(transparent)] #[repr(transparent)]
struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>); struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>);
struct EsrEL1(InMemoryRegister<u64, ESR_EL1::Register>);
/// The exception context as it is stored on the stack on exception entry. /// The exception context as it is stored on the stack on exception entry.
#[repr(C)] #[repr(C)]
@ -48,39 +45,21 @@ struct ExceptionContext {
/// Saved program status. /// Saved program status.
spsr_el1: SpsrEL1, spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1. // Exception syndrome register.
struct EsrEL1; esr_el1: EsrEL1,
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
// Private Code // Private Code
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Check if additional context can be derived from a data abort.
fn inspect_data_abort(f: &mut fmt::Formatter) -> fmt::Result {
let fault_addr = Address::new(FAR_EL1.get() as usize);
if bsp::memory::mmu::virt_boot_core_stack_guard_page_desc().contains(fault_addr) {
writeln!(
f,
"\n\n >> Attempted to access the guard page of the kernel's boot core stack <<"
)?;
}
Ok(())
}
/// Prints verbose information about the exception and then panics. /// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) { fn default_exception_handler(exc: &ExceptionContext) {
panic!( panic!(
"\n\nCPU Exception!\n\ "\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\ {}",
{}\n\ exc
{}",
FAR_EL1.get(),
EsrEL1 {},
e
); );
} }
@ -164,35 +143,9 @@ unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Pretty printing // Misc
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let esr_el1 = ESR_EL1.extract();
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", esr_el1.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", esr_el1.read(ESR_EL1::EC))?;
// Exception class, translation.
let ec_translation = match esr_el1.read_as_enum(ESR_EL1::EC) {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))?;
inspect_data_abort(f)
}
}
/// Human readable SPSR_EL1. /// Human readable SPSR_EL1.
#[rustfmt::skip] #[rustfmt::skip]
impl fmt::Display for SpsrEL1 { impl fmt::Display for SpsrEL1 {
@ -226,11 +179,72 @@ impl fmt::Display for SpsrEL1 {
} }
} }
impl EsrEL1 {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.0.read_as_enum(ESR_EL1::EC)
}
}
/// Human readable ESR_EL1.
#[rustfmt::skip]
impl fmt::Display for EsrEL1 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Raw print of whole register.
writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?;
// Raw print of exception class.
write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?;
// Exception class.
let ec_translation = match self.exception_class() {
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
_ => "N/A",
};
writeln!(f, " - {}", ec_translation)?;
// Raw print of instruction specific syndrome.
write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS))
}
}
impl ExceptionContext {
#[inline(always)]
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
self.esr_el1.exception_class()
}
#[inline(always)]
fn fault_address_valid(&self) -> bool {
use ESR_EL1::EC::Value::*;
match self.exception_class() {
None => false,
Some(ec) => matches!(
ec,
InstrAbortLowerEL
| InstrAbortCurrentEL
| PCAlignmentFault
| DataAbortLowerEL
| DataAbortCurrentEL
| WatchpointLowerEL
| WatchpointCurrentEL
),
}
}
}
/// Human readable print of the exception context. /// Human readable print of the exception context.
impl fmt::Display for ExceptionContext { impl fmt::Display for ExceptionContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?; writeln!(f, "{}", self.esr_el1)?;
if self.fault_address_valid() {
writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?;
}
writeln!(f, "{}", self.spsr_el1)?; writeln!(f, "{}", self.spsr_el1)?;
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?; writeln!(f)?;
writeln!(f, "General purpose register:")?; writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13] stp x26, x27, [sp, #16 * 13]
stp x28, x29, [sp, #16 * 14] stp x28, x29, [sp, #16 * 14]
// Add the exception link register (ELR_EL1) and the saved program status (SPSR_EL1). // Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
// syndrome register (ESR_EL1).
mrs x1, ELR_EL1 mrs x1, ELR_EL1
mrs x2, SPSR_EL1 mrs x2, SPSR_EL1
mrs x3, ESR_EL1
stp lr, x1, [sp, #16 * 15] stp lr, x1, [sp, #16 * 15]
str x2, [sp, #16 * 16] stp x2, x3, [sp, #16 * 16]
// x0 is the first argument for the function called through `\handler`. // x0 is the first argument for the function called through `\handler`.
mov x0, sp mov x0, sp

@ -70,9 +70,7 @@ SECTIONS
/*********************************************************************************************** /***********************************************************************************************
* Guard Page between boot core stack and data * Guard Page between boot core stack and data
***********************************************************************************************/ ***********************************************************************************************/
__boot_core_stack_guard_page_start = .;
. += 64K; . += 64K;
__boot_core_stack_guard_page_end_exclusive = .;
/*********************************************************************************************** /***********************************************************************************************
* Boot Core Stack * Boot Core Stack

@ -164,21 +164,6 @@ fn boot_core_stack_size() -> usize {
} }
} }
/// Start address of the boot core's stack guard page.
#[inline(always)]
fn virt_boot_core_stack_guard_page_start() -> Address<Virtual> {
Address::new(unsafe { __boot_core_stack_guard_page_start.get() as usize })
}
/// Size of the boot core's stack guard page.
#[inline(always)]
fn boot_core_stack_guard_page_size() -> usize {
unsafe {
(__boot_core_stack_guard_page_end_exclusive.get() as usize)
- (__boot_core_stack_guard_page_start.get() as usize)
}
}
/// Exclusive end address of the physical address space. /// Exclusive end address of the physical address space.
#[inline(always)] #[inline(always)]
fn phys_addr_space_end() -> Address<Physical> { fn phys_addr_space_end() -> Address<Physical> {

@ -129,13 +129,6 @@ pub fn kernel_translation_tables() -> &'static InitStateLock<KernelTranslationTa
&KERNEL_TABLES &KERNEL_TABLES
} }
/// The boot core's stack guard page.
pub fn virt_boot_core_stack_guard_page_desc() -> PageSliceDescriptor<Virtual> {
let num_pages = size_to_num_pages(super::boot_core_stack_guard_page_size());
PageSliceDescriptor::from_addr(super::virt_boot_core_stack_guard_page_start(), num_pages)
}
/// Pointer to the last page of the physical address space. /// Pointer to the last page of the physical address space.
pub fn phys_addr_space_end_page() -> *const Page<Physical> { pub fn phys_addr_space_end_page() -> *const Page<Physical> {
common::align_down( common::align_down(

Loading…
Cancel
Save