1212//! crate::exception::arch_exception
1313
1414use core:: { cell:: UnsafeCell , fmt} ;
15- use cortex_a:: { asm, asm :: barrier, registers:: * } ;
15+ use cortex_a:: { asm:: barrier, registers:: * } ;
1616use 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) ]
3030struct 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 \n CPU 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]
9289unsafe 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]
184159impl 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.
216246impl 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
0 commit comments