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 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 x2, SPSR_EL1
mrs x3, ESR_EL1
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`.
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
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`
(holding the preferred return address). Afterwards, we store those registers, save the current stack
address in `x0` and branch off to follow-up handler-code, whose function name is supplied as an
argument to the macro (`\handler`).
the 30 `GPRs`, the `link register`, the `exception link register` (holding the preferred return
address), the `saved program status` and the `exception syndrome register`. Afterwards, we store
those registers, save the current stack address in `x0` and branch off to follow-up handler-code,
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
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.
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:
```rust
/// Print verbose information about the exception and the panic.
fn default_exception_handler(e: &ExceptionContext) {
/// Prints verbose information about the exception and then panics.
fn default_exception_handler(exc: &ExceptionContext) {
panic!(
"\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\
{}\n\
{}",
FAR_EL1.get(),
EsrEL1 {},
e
{}",
exc
);
}
```
@ -363,14 +364,16 @@ To survive this exception, the respective handler has a special demo case:
```rust
#[no_mangle]
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,
// advance the exception link register for one instruction, so that execution can continue.
if far_el1 == 8 * 1024 * 1024 * 1024 {
e.elr_el1 += 4;
// 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.
if far_el1 == 8 * 1024 * 1024 * 1024 {
e.elr_el1 += 4;
asm::eret()
return;
}
}
default_exception_handler(e);
@ -398,6 +401,7 @@ Minipush 1.0
[MP] ⏳ Waiting for /dev/ttyUSB0
[MP] ✅ Serial connected
[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
[ML] Loaded! Executing the payload now
[ 0.980247] mingo version 0.11.0
[ 0.980454] Booting on: Raspberry Pi 3
[ 0.980909] MMU online. Special regions:
[ 0.981386] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data
[ 0.982404] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO
[ 0.983293] Current privilege level: EL1
[ 0.983769] Exception handling state:
[ 0.984213] Debug: Masked
[ 0.984604] SError: Masked
[ 0.984993] IRQ: Masked
[ 0.985383] FIQ: Masked
[ 0.985773] Architectural timer resolution: 52 ns
[ 0.986347] Drivers loaded:
[ 0.986684] 1. BCM GPIO
[ 0.987041] 2. BCM PL011 UART
[ 0.987463] Timer test, spinning for 1 second
[ 1.987994]
[ 1.987998] Trying to read from address 8 GiB...
[ 1.988547] ************************************************
[ 1.989240] Whoa! We recovered from a synchronous exception!
[ 1.989933] ************************************************
[ 1.990627]
[ 1.990800] Let's try again
[ 1.991136] Trying to read from address 9 GiB...
[ 0.788994] mingo version 0.11.0
[ 0.789201] Booting on: Raspberry Pi 3
[ 0.789656] MMU online. Special regions:
[ 0.790133] 0x00080000 - 0x0008ffff | 64 KiB | C RO PX | Kernel code and RO data
[ 0.791151] 0x3f000000 - 0x4000ffff | 16 MiB | Dev RW PXN | Device MMIO
[ 0.792040] Current privilege level: EL1
[ 0.792516] Exception handling state:
[ 0.792960] Debug: Masked
[ 0.793350] SError: Masked
[ 0.793740] IRQ: Masked
[ 0.794130] FIQ: Masked
[ 0.794520] Architectural timer resolution: 52 ns
[ 0.795094] Drivers loaded:
[ 0.795430] 1. BCM GPIO
[ 0.795788] 2. BCM PL011 UART
[ 0.796210] Timer test, spinning for 1 second
[ 1.796741]
[ 1.796745] Trying to read from address 8 GiB...
[ 1.797295] ************************************************
[ 1.797987] Whoa! We recovered from a synchronous exception!
[ 1.798680] ************************************************
[ 1.799373]
[ 1.799547] Let's try again
[ 1.799883] Trying to read from address 9 GiB...
Kernel panic:
CPU Exception!
FAR_EL1: 0x0000000240000000
ESR_EL1: 0x96000004
Exception Class (EC) : 0x25 - Data Abort, current EL
Instr Specific Syndrome (ISS): 0x4
ELR_EL1: 0x0000000000082578
FAR_EL1: 0x0000000240000000
SPSR_EL1: 0x600003c5
Flags:
Negative (N): Not set
@ -454,24 +457,25 @@ SPSR_EL1: 0x600003c5
IRQ (I): Masked
FIQ (F): Masked
Illegal Execution State (IL): Not set
ELR_EL1: 0x0000000000082580
General purpose register:
x0 : 0x0000000000000000 x1 : 0x00000000000858c7
x2 : 0x0000000000000027 x3 : 0x0000000000084cc4
x4 : 0x0000000000000003 x5 : 0x3f27329400000000
x6 : 0x0000000000000000 x7 : 0xd3d0b80800000000
x8 : 0x0000000240000000 x9 : 0x000000003f201000
x10: 0x0000000000000019 x11: 0x0000000000000000
x12: 0x0000000000000001 x13: 0x0000000000000036
x14: 0x000000000007fc2d x15: 0x0000000000000000
x16: 0x0000000000000040 x17: 0xfd39702255e846c0
x18: 0x9cd47880832f1200 x19: 0x0000000000090008
x20: 0x00000000000856b0 x21: 0x000000003b9aca00
x22: 0x000000000008274c x23: 0x00000000000833d8
x0 : 0x0000000000000000 x1 : 0x00000000000859b7
x2 : 0x0000000000000027 x3 : 0x0000000000084d3c
x4 : 0x0000000000000003 x5 : 0x3f26329c00000000
x6 : 0x0000000000000000 x7 : 0xd3d18800228d0241
x8 : 0x0000000240000000 x9 : 0x00000000000859b7
x10: 0x0000000000000443 x11: 0x000000003f201000
x12: 0x0000000000000019 x13: 0x0000000000000033
x14: 0x000000000007fd3d x15: 0x0000000000000058
x16: 0x0000000000000078 x17: 0xfd29f02255a847c0
x18: 0x9cd4788000000008 x19: 0x0000000000090008
x20: 0x00000000000857a0 x21: 0x000000003b9aca00
x22: 0x000000000008271c x23: 0x0000000000083314
x24: 0x00000000000003e8 x25: 0xffffffffc4653600
x26: 0x00000000000f4240 x27: 0x0000000000085790
x28: 0x0000000000086a50 x29: 0x00000000000867ed
lr : 0x000000000008256c
x26: 0x00000000000f4240 x27: 0x0000000000085880
x28: 0x0000000000085170 x29: 0x0000000000086c10
lr : 0x0000000000082574
```
## 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
--- 10_virtual_mem_part1_identity_mapping/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
-use cortex_a::registers::*;
-use tock_registers::interfaces::Readable;
+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,
@ -512,9 +516,10 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+// Private Definitions
+//--------------------------------------------------------------------------------------------------
+
+/// Wrapper struct for memory copy of SPSR_EL1.
+/// Wrapper structs for memory copies of registers.
+#[repr(transparent)]
+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.
+#[repr(C)]
@ -530,25 +535,21 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+
+ /// Saved program status.
+ spsr_el1: SpsrEL1,
+}
+
+/// Wrapper struct for pretty printing ESR_EL1.
+struct EsrEL1;
+ // Exception syndrome register.
+ esr_el1: EsrEL1,
+}
+
+//--------------------------------------------------------------------------------------------------
+// Private Code
+//--------------------------------------------------------------------------------------------------
+
+/// Prints verbose information about the exception and then panics.
+fn default_exception_handler(e: &ExceptionContext) {
+fn default_exception_handler(exc: &ExceptionContext) {
+ panic!(
+ "\n\nCPU Exception!\n\
+ FAR_EL1: {:#018x}\n\
+ {}\n\
+ {}",
+ FAR_EL1.get(),
+ EsrEL1 {},
+ e
+ {}",
+ exc
+ );
+}
+
@ -577,14 +578,16 @@ diff -uNr 10_virtual_mem_part1_identity_mapping/src/_arch/aarch64/exception.rs 1
+
+#[no_mangle]
+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,
+ // advance the exception link register for one instruction, so that execution can continue.
+ if far_el1 == 8 * 1024 * 1024 * 1024 {
+ e.elr_el1 += 4;
+ // 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.
+ if far_el1 == 8 * 1024 * 1024 * 1024 {
+ e.elr_el1 += 4;
+
+ asm::eret()
+ return;
+ }
+ }
+
+ 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.
+#[rustfmt::skip]
+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.
+impl fmt::Display for ExceptionContext {
+ 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, "ELR_EL1: {:#018x}", self.elr_el1)?;
+ writeln!(f)?;
+ 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
@@ -29,3 +248,23 @@
@@ -29,3 +284,23 @@
_ => (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
--- 10_virtual_mem_part1_identity_mapping/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
+//
+// 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 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 x2, SPSR_EL1
+ mrs x3, ESR_EL1
+
+ 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`.
+ mov x0, sp

@ -12,7 +12,7 @@
//! 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,
@ -25,9 +25,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions
//--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1.
/// Wrapper structs for memory copies of registers.
#[repr(transparent)]
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.
#[repr(C)]
@ -43,25 +44,21 @@ struct ExceptionContext {
/// Saved program status.
spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1.
struct EsrEL1;
// Exception syndrome register.
esr_el1: EsrEL1,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
/// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) {
fn default_exception_handler(exc: &ExceptionContext) {
panic!(
"\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\
{}\n\
{}",
FAR_EL1.get(),
EsrEL1 {},
e
{}",
exc
);
}
@ -90,14 +87,16 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
#[no_mangle]
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,
// advance the exception link register for one instruction, so that execution can continue.
if far_el1 == 8 * 1024 * 1024 * 1024 {
e.elr_el1 += 4;
// 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.
if far_el1 == 8 * 1024 * 1024 * 1024 {
e.elr_el1 += 4;
asm::eret()
return;
}
}
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.
#[rustfmt::skip]
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.
impl fmt::Display for ExceptionContext {
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, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?;
writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13]
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 x2, SPSR_EL1
mrs x3, ESR_EL1
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`.
mov x0, sp

@ -853,8 +853,8 @@ Compiling integration test(s) - rpi3
Kernel panic:
CPU Exception!
FAR_EL1: 0x0000000240000000
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
--- 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs
+++ 12_integrated_testing/src/_arch/aarch64/exception.rs
@@ -12,7 +12,7 @@
//! 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 @@
@@ -87,18 +87,6 @@
#[no_mangle]
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,
- // advance the exception link register for one instruction, so that execution can continue.
- if far_el1 == 8 * 1024 * 1024 * 1024 {
- e.elr_el1 += 4;
- // 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.
- if far_el1 == 8 * 1024 * 1024 * 1024 {
- e.elr_el1 += 4;
-
- asm::eret()
- return;
- }
- }
-
default_exception_handler(e);

@ -25,9 +25,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions
//--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1.
/// Wrapper structs for memory copies of registers.
#[repr(transparent)]
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.
#[repr(C)]
@ -43,25 +44,21 @@ struct ExceptionContext {
/// Saved program status.
spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1.
struct EsrEL1;
// Exception syndrome register.
esr_el1: EsrEL1,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
/// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) {
fn default_exception_handler(exc: &ExceptionContext) {
panic!(
"\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\
{}\n\
{}",
FAR_EL1.get(),
EsrEL1 {},
e
{}",
exc
);
}
@ -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.
#[rustfmt::skip]
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.
impl fmt::Display for ExceptionContext {
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, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?;
writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13]
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 x2, SPSR_EL1
mrs x3, ESR_EL1
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`.
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 cortex_a::{asm::barrier, registers::*};
use tock_registers::{
@@ -94,8 +95,11 @@
@@ -91,8 +92,11 @@
}
#[no_mangle]

@ -26,9 +26,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions
//--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1.
/// Wrapper structs for memory copies of registers.
#[repr(transparent)]
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.
#[repr(C)]
@ -44,25 +45,21 @@ struct ExceptionContext {
/// Saved program status.
spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1.
struct EsrEL1;
// Exception syndrome register.
esr_el1: EsrEL1,
}
//--------------------------------------------------------------------------------------------------
// Private Code
//--------------------------------------------------------------------------------------------------
/// Prints verbose information about the exception and then panics.
fn default_exception_handler(e: &ExceptionContext) {
fn default_exception_handler(exc: &ExceptionContext) {
panic!(
"\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\
{}\n\
{}",
FAR_EL1.get(),
EsrEL1 {},
e
{}",
exc
);
}
@ -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.
#[rustfmt::skip]
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.
impl fmt::Display for ExceptionContext {
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, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?;
writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13]
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 x2, SPSR_EL1
mrs x3, ESR_EL1
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`.
mov x0, sp

@ -279,10 +279,6 @@ through them:
- [`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
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
`Page<ATYPE>`.
- [`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"
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
--- 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
@ -1495,7 +1442,7 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/link.ld 14_vir
.data : { *(.data*) } :segment_rw
/* Section is zeroed in pairs of u64. Align start and end to 16 bytes */
@@ -54,4 +50,23 @@
@@ -54,4 +50,21 @@
. = ALIGN(16);
__bss_end_exclusive = .;
} :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
+ ***********************************************************************************************/
+ __boot_core_stack_guard_page_start = .;
+ . += 64K;
+ __boot_core_stack_guard_page_end_exclusive = .;
+
+ /***********************************************************************************************
+ * 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
--- 13_exceptions_part2_peripheral_IRQs/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.
@ -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
+/// derive respective data structures and their sizes. For example, the `crate::memory::mmu::Page`.
+pub type KernelGranule = TranslationGranule<{ 64 * 1024 }>;
-const NUM_MEM_RANGES: usize = 2;
+
+/// The kernel's virtual address space defined by this BSP.
+pub type KernelVirtAddrSpace = AddressSpace<{ 8 * 1024 * 1024 * 1024 }>;
-/// The virtual memory layout.
-const NUM_MEM_RANGES: usize = 2;
+//--------------------------------------------------------------------------------------------------
+// Global instances
+//--------------------------------------------------------------------------------------------------
+
-/// The virtual memory layout.
+/// The kernel translation tables.
///
-/// 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.
+fn phys_rx_page_desc() -> PageSliceDescriptor<Physical> {
+ 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> {
- 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.
+fn phys_boot_core_stack_page_desc() -> PageSliceDescriptor<Physical> {
+ 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
+}
+
+/// 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.
+pub fn phys_addr_space_end_page() -> *const Page<Physical> {
+ 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)]
mod tests {
use super::*;
@ -1742,6 +1680,10 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory/mmu.rs
#[kernel_test]
fn virt_mem_layout_sections_are_64KiB_aligned() {
- 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 [
+ virt_rx_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 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!(end modulo SIXTYFOUR_KIB, 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);
}
}
@@ -97,18 +196,38 @@
@@ -97,18 +189,38 @@
/// Ensure the kernel's virtual memory layout is free of overlaps.
#[kernel_test]
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.
#[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 }
+fn virt_rx_start() -> Address<Virtual> {
+ 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.
+/// 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.
+/// Size of the Read+Execute (RX) range.
///
/// # Safety
///
@ -1988,6 +1910,22 @@ diff -uNr 13_exceptions_part2_peripheral_IRQs/src/bsp/raspberrypi/memory.rs 14_v
#[inline(always)]
-fn rx_end_exclusive() -> 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 {
+ 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.
+#[inline(always)]
+fn phys_addr_space_end() -> Address<Physical> {

@ -11,11 +11,7 @@
//!
//! crate::exception::arch_exception
use crate::{
bsp::{self},
exception,
memory::Address,
};
use crate::{bsp, exception};
use core::{cell::UnsafeCell, fmt};
use cortex_a::{asm::barrier, registers::*};
use tock_registers::{
@ -30,9 +26,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions
//--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1.
/// Wrapper structs for memory copies of registers.
#[repr(transparent)]
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.
#[repr(C)]
@ -48,39 +45,21 @@ struct ExceptionContext {
/// Saved program status.
spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1.
struct EsrEL1;
// Exception syndrome register.
esr_el1: EsrEL1,
}
//--------------------------------------------------------------------------------------------------
// 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) {
fn default_exception_handler(exc: &ExceptionContext) {
panic!(
"\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\
{}\n\
{}",
FAR_EL1.get(),
EsrEL1 {},
e
{}",
exc
);
}
@ -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.
#[rustfmt::skip]
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.
impl fmt::Display for ExceptionContext {
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, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?;
writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13]
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 x2, SPSR_EL1
mrs x3, ESR_EL1
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`.
mov x0, sp

@ -57,9 +57,7 @@ SECTIONS
/***********************************************************************************************
* Guard Page between boot core stack and data
***********************************************************************************************/
__boot_core_stack_guard_page_start = .;
. += 64K;
__boot_core_stack_guard_page_end_exclusive = .;
/***********************************************************************************************
* 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.
#[inline(always)]
fn phys_addr_space_end() -> Address<Physical> {

@ -107,13 +107,6 @@ pub fn kernel_translation_tables() -> &'static InitStateLock<KernelTranslationTa
&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.
pub fn phys_addr_space_end_page() -> *const Page<Physical> {
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<_>
}
@ -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",
&virt_rx_page_desc(),
&phys_rx_page_desc(),
@@ -137,9 +161,9 @@
@@ -130,9 +154,9 @@
acc_perms: AccessPermissions::ReadOnly,
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",
&virt_rw_page_desc(),
&phys_rw_page_desc(),
@@ -148,9 +172,9 @@
@@ -141,9 +165,9 @@
acc_perms: AccessPermissions::ReadWrite,
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",
&virt_boot_core_stack_page_desc(),
&phys_boot_core_stack_page_desc(),
@@ -159,75 +183,5 @@
@@ -152,75 +176,5 @@
acc_perms: AccessPermissions::ReadWrite,
execute_never: true,
},

@ -11,11 +11,7 @@
//!
//! crate::exception::arch_exception
use crate::{
bsp::{self},
exception,
memory::Address,
};
use crate::{bsp, exception};
use core::{cell::UnsafeCell, fmt};
use cortex_a::{asm::barrier, registers::*};
use tock_registers::{
@ -30,9 +26,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions
//--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1.
/// Wrapper structs for memory copies of registers.
#[repr(transparent)]
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.
#[repr(C)]
@ -48,39 +45,21 @@ struct ExceptionContext {
/// Saved program status.
spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1.
struct EsrEL1;
// Exception syndrome register.
esr_el1: EsrEL1,
}
//--------------------------------------------------------------------------------------------------
// 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) {
fn default_exception_handler(exc: &ExceptionContext) {
panic!(
"\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\
{}\n\
{}",
FAR_EL1.get(),
EsrEL1 {},
e
{}",
exc
);
}
@ -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.
#[rustfmt::skip]
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.
impl fmt::Display for ExceptionContext {
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, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?;
writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13]
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 x2, SPSR_EL1
mrs x3, ESR_EL1
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`.
mov x0, sp

@ -60,9 +60,7 @@ SECTIONS
/***********************************************************************************************
* Guard Page between boot core stack and data
***********************************************************************************************/
__boot_core_stack_guard_page_start = .;
. += 64K;
__boot_core_stack_guard_page_end_exclusive = .;
/***********************************************************************************************
* 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.
#[inline(always)]
fn phys_addr_space_end() -> Address<Physical> {

@ -129,13 +129,6 @@ pub fn kernel_translation_tables() -> &'static InitStateLock<KernelTranslationTa
&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.
pub fn phys_addr_space_end_page() -> *const Page<Physical> {
common::align_down(

@ -11,11 +11,7 @@
//!
//! crate::exception::arch_exception
use crate::{
bsp::{self},
exception,
memory::Address,
};
use crate::{bsp, exception};
use core::{cell::UnsafeCell, fmt};
use cortex_a::{asm::barrier, registers::*};
use tock_registers::{
@ -30,9 +26,10 @@ global_asm!(include_str!("exception.s"));
// Private Definitions
//--------------------------------------------------------------------------------------------------
/// Wrapper struct for memory copy of SPSR_EL1.
/// Wrapper structs for memory copies of registers.
#[repr(transparent)]
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.
#[repr(C)]
@ -48,39 +45,21 @@ struct ExceptionContext {
/// Saved program status.
spsr_el1: SpsrEL1,
}
/// Wrapper struct for pretty printing ESR_EL1.
struct EsrEL1;
// Exception syndrome register.
esr_el1: EsrEL1,
}
//--------------------------------------------------------------------------------------------------
// 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) {
fn default_exception_handler(exc: &ExceptionContext) {
panic!(
"\n\nCPU Exception!\n\
FAR_EL1: {:#018x}\n\
{}\n\
{}",
FAR_EL1.get(),
EsrEL1 {},
e
{}",
exc
);
}
@ -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.
#[rustfmt::skip]
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.
impl fmt::Display for ExceptionContext {
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, "ELR_EL1: {:#018x}", self.elr_el1)?;
writeln!(f)?;
writeln!(f, "General purpose register:")?;

@ -29,12 +29,14 @@
stp x26, x27, [sp, #16 * 13]
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 x2, SPSR_EL1
mrs x3, ESR_EL1
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`.
mov x0, sp

@ -70,9 +70,7 @@ SECTIONS
/***********************************************************************************************
* Guard Page between boot core stack and data
***********************************************************************************************/
__boot_core_stack_guard_page_start = .;
. += 64K;
__boot_core_stack_guard_page_end_exclusive = .;
/***********************************************************************************************
* 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.
#[inline(always)]
fn phys_addr_space_end() -> Address<Physical> {

@ -129,13 +129,6 @@ pub fn kernel_translation_tables() -> &'static InitStateLock<KernelTranslationTa
&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.
pub fn phys_addr_space_end_page() -> *const Page<Physical> {
common::align_down(

Loading…
Cancel
Save