Skip to content

Commit 920af57

Browse files
committed
Refactor parts of exception handling
1 parent ddb4f54 commit 920af57

File tree

26 files changed

+664
-620
lines changed

26 files changed

+664
-620
lines changed

11_exceptions_part1_groundwork/README.md

Lines changed: 152 additions & 110 deletions
Large diffs are not rendered by default.

11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs

Lines changed: 80 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//! crate::exception::arch_exception
1313
1414
use core::{cell::UnsafeCell, fmt};
15-
use cortex_a::{asm, asm::barrier, registers::*};
15+
use cortex_a::{asm::barrier, registers::*};
1616
use tock_registers::{
1717
interfaces::{Readable, Writeable},
1818
registers::InMemoryRegister,
@@ -25,9 +25,10 @@ global_asm!(include_str!("exception.s"));
2525
// Private Definitions
2626
//--------------------------------------------------------------------------------------------------
2727

28-
/// Wrapper struct for memory copy of SPSR_EL1.
28+
/// Wrapper structs for memory copies of registers.
2929
#[repr(transparent)]
3030
struct SpsrEL1(InMemoryRegister<u64, SPSR_EL1::Register>);
31+
struct EsrEL1(InMemoryRegister<u64, ESR_EL1::Register>);
3132

3233
/// The exception context as it is stored on the stack on exception entry.
3334
#[repr(C)]
@@ -43,25 +44,21 @@ struct ExceptionContext {
4344

4445
/// Saved program status.
4546
spsr_el1: SpsrEL1,
46-
}
4747

48-
/// Wrapper struct for pretty printing ESR_EL1.
49-
struct EsrEL1;
48+
// Exception syndrome register.
49+
esr_el1: EsrEL1,
50+
}
5051

5152
//--------------------------------------------------------------------------------------------------
5253
// Private Code
5354
//--------------------------------------------------------------------------------------------------
5455

5556
/// Prints verbose information about the exception and then panics.
56-
fn default_exception_handler(e: &ExceptionContext) {
57+
fn default_exception_handler(exc: &ExceptionContext) {
5758
panic!(
5859
"\n\nCPU Exception!\n\
59-
FAR_EL1: {:#018x}\n\
60-
{}\n\
61-
{}",
62-
FAR_EL1.get(),
63-
EsrEL1 {},
64-
e
60+
{}",
61+
exc
6562
);
6663
}
6764

@@ -90,14 +87,16 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
9087

9188
#[no_mangle]
9289
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
93-
let far_el1 = FAR_EL1.get();
90+
if e.fault_address_valid() {
91+
let far_el1 = FAR_EL1.get();
9492

95-
// This catches the demo case for this tutorial. If the fault address happens to be 8 GiB,
96-
// advance the exception link register for one instruction, so that execution can continue.
97-
if far_el1 == 8 * 1024 * 1024 * 1024 {
98-
e.elr_el1 += 4;
93+
// This catches the demo case for this tutorial. If the fault address happens to be 8 GiB,
94+
// advance the exception link register for one instruction, so that execution can continue.
95+
if far_el1 == 8 * 1024 * 1024 * 1024 {
96+
e.elr_el1 += 4;
9997

100-
asm::eret()
98+
return;
99+
}
101100
}
102101

103102
default_exception_handler(e);
@@ -152,33 +151,9 @@ unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) {
152151
}
153152

154153
//------------------------------------------------------------------------------
155-
// Pretty printing
154+
// Misc
156155
//------------------------------------------------------------------------------
157156

158-
/// Human readable ESR_EL1.
159-
#[rustfmt::skip]
160-
impl fmt::Display for EsrEL1 {
161-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162-
let esr_el1 = ESR_EL1.extract();
163-
164-
// Raw print of whole register.
165-
writeln!(f, "ESR_EL1: {:#010x}", esr_el1.get())?;
166-
167-
// Raw print of exception class.
168-
write!(f, " Exception Class (EC) : {:#x}", esr_el1.read(ESR_EL1::EC))?;
169-
170-
// Exception class, translation.
171-
let ec_translation = match esr_el1.read_as_enum(ESR_EL1::EC) {
172-
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
173-
_ => "N/A",
174-
};
175-
writeln!(f, " - {}", ec_translation)?;
176-
177-
// Raw print of instruction specific syndrome.
178-
write!(f, " Instr Specific Syndrome (ISS): {:#x}", esr_el1.read(ESR_EL1::ISS))
179-
}
180-
}
181-
182157
/// Human readable SPSR_EL1.
183158
#[rustfmt::skip]
184159
impl fmt::Display for SpsrEL1 {
@@ -212,11 +187,72 @@ impl fmt::Display for SpsrEL1 {
212187
}
213188
}
214189

190+
impl EsrEL1 {
191+
#[inline(always)]
192+
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
193+
self.0.read_as_enum(ESR_EL1::EC)
194+
}
195+
}
196+
197+
/// Human readable ESR_EL1.
198+
#[rustfmt::skip]
199+
impl fmt::Display for EsrEL1 {
200+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201+
// Raw print of whole register.
202+
writeln!(f, "ESR_EL1: {:#010x}", self.0.get())?;
203+
204+
// Raw print of exception class.
205+
write!(f, " Exception Class (EC) : {:#x}", self.0.read(ESR_EL1::EC))?;
206+
207+
// Exception class.
208+
let ec_translation = match self.exception_class() {
209+
Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => "Data Abort, current EL",
210+
_ => "N/A",
211+
};
212+
writeln!(f, " - {}", ec_translation)?;
213+
214+
// Raw print of instruction specific syndrome.
215+
write!(f, " Instr Specific Syndrome (ISS): {:#x}", self.0.read(ESR_EL1::ISS))
216+
}
217+
}
218+
219+
impl ExceptionContext {
220+
#[inline(always)]
221+
fn exception_class(&self) -> Option<ESR_EL1::EC::Value> {
222+
self.esr_el1.exception_class()
223+
}
224+
225+
#[inline(always)]
226+
fn fault_address_valid(&self) -> bool {
227+
use ESR_EL1::EC::Value::*;
228+
229+
match self.exception_class() {
230+
None => false,
231+
Some(ec) => matches!(
232+
ec,
233+
InstrAbortLowerEL
234+
| InstrAbortCurrentEL
235+
| PCAlignmentFault
236+
| DataAbortLowerEL
237+
| DataAbortCurrentEL
238+
| WatchpointLowerEL
239+
| WatchpointCurrentEL
240+
),
241+
}
242+
}
243+
}
244+
215245
/// Human readable print of the exception context.
216246
impl fmt::Display for ExceptionContext {
217247
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218-
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?;
248+
writeln!(f, "{}", self.esr_el1)?;
249+
250+
if self.fault_address_valid() {
251+
writeln!(f, "FAR_EL1: {:#018x}", FAR_EL1.get() as usize)?;
252+
}
253+
219254
writeln!(f, "{}", self.spsr_el1)?;
255+
writeln!(f, "ELR_EL1: {:#018x}", self.elr_el1)?;
220256
writeln!(f)?;
221257
writeln!(f, "General purpose register:")?;
222258

11_exceptions_part1_groundwork/src/_arch/aarch64/exception.s

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@
2929
stp x26, x27, [sp, #16 * 13]
3030
stp x28, x29, [sp, #16 * 14]
3131

32-
// Add the exception link register (ELR_EL1) and the saved program status (SPSR_EL1).
32+
// Add the exception link register (ELR_EL1), saved program status (SPSR_EL1) and exception
33+
// syndrome register (ESR_EL1).
3334
mrs x1, ELR_EL1
3435
mrs x2, SPSR_EL1
36+
mrs x3, ESR_EL1
3537

3638
stp lr, x1, [sp, #16 * 15]
37-
str x2, [sp, #16 * 16]
39+
stp x2, x3, [sp, #16 * 16]
3840

3941
// x0 is the first argument for the function called through `\handler`.
4042
mov x0, sp

12_integrated_testing/README.md

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -853,8 +853,8 @@ Compiling integration test(s) - rpi3
853853
Kernel panic:
854854

855855
CPU Exception!
856-
FAR_EL1: 0x0000000240000000
857856
ESR_EL1: 0x96000004
857+
Exception Class (EC) : 0x25 - Data Abort, current EL
858858
[...]
859859

860860
-------------------------------------------------------------------
@@ -1070,27 +1070,20 @@ diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/cpu.rs 12_integrated_
10701070
diff -uNr 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs 12_integrated_testing/src/_arch/aarch64/exception.rs
10711071
--- 11_exceptions_part1_groundwork/src/_arch/aarch64/exception.rs
10721072
+++ 12_integrated_testing/src/_arch/aarch64/exception.rs
1073-
@@ -12,7 +12,7 @@
1074-
//! crate::exception::arch_exception
1075-
1076-
use core::{cell::UnsafeCell, fmt};
1077-
-use cortex_a::{asm, asm::barrier, registers::*};
1078-
+use cortex_a::{asm::barrier, registers::*};
1079-
use tock_registers::{
1080-
interfaces::{Readable, Writeable},
1081-
registers::InMemoryRegister,
1082-
@@ -90,16 +90,6 @@
1073+
@@ -87,18 +87,6 @@
10831074

10841075
#[no_mangle]
10851076
unsafe extern "C" fn current_elx_synchronous(e: &mut ExceptionContext) {
1086-
- let far_el1 = FAR_EL1.get();
1077+
- if e.fault_address_valid() {
1078+
- let far_el1 = FAR_EL1.get();
10871079
-
1088-
- // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB,
1089-
- // advance the exception link register for one instruction, so that execution can continue.
1090-
- if far_el1 == 8 * 1024 * 1024 * 1024 {
1091-
- e.elr_el1 += 4;
1080+
- // This catches the demo case for this tutorial. If the fault address happens to be 8 GiB,
1081+
- // advance the exception link register for one instruction, so that execution can continue.
1082+
- if far_el1 == 8 * 1024 * 1024 * 1024 {
1083+
- e.elr_el1 += 4;
10921084
-
1093-
- asm::eret()
1085+
- return;
1086+
- }
10941087
- }
10951088
-
10961089
default_exception_handler(e);

0 commit comments

Comments
 (0)