From 920af57ab40f5b474ab48039c2501f68d4ba4c70 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Wed, 27 Oct 2021 20:40:38 +0200 Subject: [PATCH] Refactor parts of exception handling --- 11_exceptions_part1_groundwork/README.md | 262 ++++++++++-------- .../src/_arch/aarch64/exception.rs | 124 ++++++--- .../src/_arch/aarch64/exception.s | 6 +- 12_integrated_testing/README.md | 27 +- .../src/_arch/aarch64/exception.rs | 108 +++++--- .../src/_arch/aarch64/exception.s | 6 +- 13_exceptions_part2_peripheral_IRQs/README.md | 2 +- .../src/_arch/aarch64/exception.rs | 108 +++++--- .../src/_arch/aarch64/exception.s | 6 +- 14_virtual_mem_part2_mmio_remap/README.md | 147 +++------- .../src/_arch/aarch64/exception.rs | 130 +++++---- .../src/_arch/aarch64/exception.s | 6 +- .../src/bsp/raspberrypi/link.ld | 2 - .../src/bsp/raspberrypi/memory.rs | 15 - .../src/bsp/raspberrypi/memory/mmu.rs | 7 - .../README.md | 8 +- .../src/_arch/aarch64/exception.rs | 130 +++++---- .../src/_arch/aarch64/exception.s | 6 +- .../src/bsp/raspberrypi/link.ld | 2 - .../src/bsp/raspberrypi/memory.rs | 15 - .../src/bsp/raspberrypi/memory/mmu.rs | 7 - .../src/_arch/aarch64/exception.rs | 130 +++++---- .../src/_arch/aarch64/exception.s | 6 +- .../src/bsp/raspberrypi/link.ld | 2 - .../src/bsp/raspberrypi/memory.rs | 15 - .../src/bsp/raspberrypi/memory/mmu.rs | 7 - 26 files changed, 664 insertions(+), 620 deletions(-) diff --git a/11_exceptions_part1_groundwork/README.md b/11_exceptions_part1_groundwork/README.md index afb6130b..566b8b86 100644 --- a/11_exceptions_part1_groundwork/README.md +++ b/11_exceptions_part1_groundwork/README.md @@ -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); ++struct EsrEL1(InMemoryRegister); + +/// 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 { ++ 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 { ++ 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 @@ -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 diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs index d51d7f01..2db1741c 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs +++ b/11_exceptions_part1_groundwork/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, @@ -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); +struct EsrEL1(InMemoryRegister); /// 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 { + 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 { + 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:")?; diff --git a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s index ffb1875c..cb6bfb15 100644 --- a/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s +++ b/11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s @@ -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 diff --git a/12_integrated_testing/README.md b/12_integrated_testing/README.md index 9567aa54..a7fc3969 100644 --- a/12_integrated_testing/README.md +++ b/12_integrated_testing/README.md @@ -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); diff --git a/12_integrated_testing/src/_arch/aarch64/exception.rs b/12_integrated_testing/src/_arch/aarch64/exception.rs index 6ba47300..6e8485b7 100644 --- a/12_integrated_testing/src/_arch/aarch64/exception.rs +++ b/12_integrated_testing/src/_arch/aarch64/exception.rs @@ -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); +struct EsrEL1(InMemoryRegister); /// 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 { + 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 { + 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:")?; diff --git a/12_integrated_testing/src/_arch/aarch64/exception.s b/12_integrated_testing/src/_arch/aarch64/exception.s index ffb1875c..cb6bfb15 100644 --- a/12_integrated_testing/src/_arch/aarch64/exception.s +++ b/12_integrated_testing/src/_arch/aarch64/exception.s @@ -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 diff --git a/13_exceptions_part2_peripheral_IRQs/README.md b/13_exceptions_part2_peripheral_IRQs/README.md index f2403903..cf0ba692 100644 --- a/13_exceptions_part2_peripheral_IRQs/README.md +++ b/13_exceptions_part2_peripheral_IRQs/README.md @@ -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] diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs b/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs index d755c51d..880cc92b 100644 --- a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs +++ b/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.rs @@ -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); +struct EsrEL1(InMemoryRegister); /// 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 { + 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 { + 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:")?; diff --git a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.s b/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.s index ffb1875c..cb6bfb15 100644 --- a/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.s +++ b/13_exceptions_part2_peripheral_IRQs/src/_arch/aarch64/exception.s @@ -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 diff --git a/14_virtual_mem_part2_mmio_remap/README.md b/14_virtual_mem_part2_mmio_remap/README.md index dad01e70..9d861bf6 100644 --- a/14_virtual_mem_part2_mmio_remap/README.md +++ b/14_virtual_mem_part2_mmio_remap/README.md @@ -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`. - [`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 { + virt_rx_page_desc().into() -+} -+ -+/// The Read+Write (RW) pages of the kernel binary. -+fn phys_rw_page_desc() -> PageSliceDescriptor { -+ virt_rw_page_desc().into() } -fn mmio_range_inclusive() -> RangeInclusive { - 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 { ++ virt_rw_page_desc().into() ++} ++ +/// The boot core's stack. +fn phys_boot_core_stack_page_desc() -> PageSliceDescriptor { + 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 { -+ 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 { + 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 { + 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 { -+ 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 { ++ 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 { -+ 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 { diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs b/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs index 1aac6545..880cc92b 100644 --- a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs +++ b/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.rs @@ -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); +struct EsrEL1(InMemoryRegister); /// 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 { + 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 { + 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:")?; diff --git a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.s b/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.s index ffb1875c..cb6bfb15 100644 --- a/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.s +++ b/14_virtual_mem_part2_mmio_remap/src/_arch/aarch64/exception.s @@ -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 diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld b/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld index 698ad85d..bdab23fc 100644 --- a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld +++ b/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/link.ld @@ -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 diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs b/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs index e51b00fa..2675633a 100644 --- a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs +++ b/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory.rs @@ -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 { - 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 { diff --git a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs b/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs index 813fa0b4..5bd2fdbd 100644 --- a/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs +++ b/14_virtual_mem_part2_mmio_remap/src/bsp/raspberrypi/memory/mmu.rs @@ -107,13 +107,6 @@ pub fn kernel_translation_tables() -> &'static InitStateLock PageSliceDescriptor { - 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 { common::align_down( diff --git a/15_virtual_mem_part3_precomputed_tables/README.md b/15_virtual_mem_part3_precomputed_tables/README.md index ee01279e..c564a1b5 100644 --- a/15_virtual_mem_part3_precomputed_tables/README.md +++ b/15_virtual_mem_part3_precomputed_tables/README.md @@ -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, }, diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.rs b/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.rs index 1aac6545..880cc92b 100644 --- a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.rs +++ b/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.rs @@ -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); +struct EsrEL1(InMemoryRegister); /// 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 { + 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 { + 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:")?; diff --git a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.s b/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.s index ffb1875c..cb6bfb15 100644 --- a/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.s +++ b/15_virtual_mem_part3_precomputed_tables/src/_arch/aarch64/exception.s @@ -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 diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld b/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld index aa127cc0..99ca627b 100644 --- a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld +++ b/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/link.ld @@ -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 diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory.rs b/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory.rs index e51b00fa..2675633a 100644 --- a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory.rs +++ b/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory.rs @@ -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 { - 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 { diff --git a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs b/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs index 4ff01e43..ab2f60ac 100644 --- a/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs +++ b/15_virtual_mem_part3_precomputed_tables/src/bsp/raspberrypi/memory/mmu.rs @@ -129,13 +129,6 @@ pub fn kernel_translation_tables() -> &'static InitStateLock PageSliceDescriptor { - 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 { common::align_down( diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.rs b/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.rs index 1aac6545..880cc92b 100644 --- a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.rs +++ b/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.rs @@ -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); +struct EsrEL1(InMemoryRegister); /// 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 { + 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 { + 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:")?; diff --git a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.s b/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.s index ffb1875c..cb6bfb15 100644 --- a/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.s +++ b/16_virtual_mem_part4_higher_half_kernel/src/_arch/aarch64/exception.s @@ -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 diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/link.ld b/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/link.ld index a3179f1a..f12fa29f 100644 --- a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/link.ld +++ b/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/link.ld @@ -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 diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory.rs b/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory.rs index e51b00fa..2675633a 100644 --- a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory.rs +++ b/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory.rs @@ -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 { - 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 { diff --git a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory/mmu.rs b/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory/mmu.rs index dbb97020..34d220f0 100644 --- a/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory/mmu.rs +++ b/16_virtual_mem_part4_higher_half_kernel/src/bsp/raspberrypi/memory/mmu.rs @@ -129,13 +129,6 @@ pub fn kernel_translation_tables() -> &'static InitStateLock PageSliceDescriptor { - 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 { common::align_down(