12
12
//! crate::exception::arch_exception
13
13
14
14
use core:: { cell:: UnsafeCell , fmt} ;
15
- use cortex_a:: { asm, asm :: barrier, registers:: * } ;
15
+ use cortex_a:: { asm:: barrier, registers:: * } ;
16
16
use tock_registers:: {
17
17
interfaces:: { Readable , Writeable } ,
18
18
registers:: InMemoryRegister ,
@@ -25,9 +25,10 @@ global_asm!(include_str!("exception.s"));
25
25
// Private Definitions
26
26
//--------------------------------------------------------------------------------------------------
27
27
28
- /// Wrapper struct for memory copy of SPSR_EL1 .
28
+ /// Wrapper structs for memory copies of registers .
29
29
#[ repr( transparent) ]
30
30
struct SpsrEL1 ( InMemoryRegister < u64 , SPSR_EL1 :: Register > ) ;
31
+ struct EsrEL1 ( InMemoryRegister < u64 , ESR_EL1 :: Register > ) ;
31
32
32
33
/// The exception context as it is stored on the stack on exception entry.
33
34
#[ repr( C ) ]
@@ -43,25 +44,21 @@ struct ExceptionContext {
43
44
44
45
/// Saved program status.
45
46
spsr_el1 : SpsrEL1 ,
46
- }
47
47
48
- /// Wrapper struct for pretty printing ESR_EL1.
49
- struct EsrEL1 ;
48
+ // Exception syndrome register.
49
+ esr_el1 : EsrEL1 ,
50
+ }
50
51
51
52
//--------------------------------------------------------------------------------------------------
52
53
// Private Code
53
54
//--------------------------------------------------------------------------------------------------
54
55
55
56
/// Prints verbose information about the exception and then panics.
56
- fn default_exception_handler ( e : & ExceptionContext ) {
57
+ fn default_exception_handler ( exc : & ExceptionContext ) {
57
58
panic ! (
58
59
"\n \n CPU Exception!\n \
59
- FAR_EL1: {:#018x}\n \
60
- {}\n \
61
- {}",
62
- FAR_EL1 . get( ) ,
63
- EsrEL1 { } ,
64
- e
60
+ {}",
61
+ exc
65
62
) ;
66
63
}
67
64
@@ -90,14 +87,16 @@ unsafe extern "C" fn current_el0_serror(_e: &mut ExceptionContext) {
90
87
91
88
#[ no_mangle]
92
89
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 ( ) ;
94
92
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 ;
99
97
100
- asm:: eret ( )
98
+ return ;
99
+ }
101
100
}
102
101
103
102
default_exception_handler ( e) ;
@@ -152,33 +151,9 @@ unsafe extern "C" fn lower_aarch32_serror(e: &mut ExceptionContext) {
152
151
}
153
152
154
153
//------------------------------------------------------------------------------
155
- // Pretty printing
154
+ // Misc
156
155
//------------------------------------------------------------------------------
157
156
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
-
182
157
/// Human readable SPSR_EL1.
183
158
#[ rustfmt:: skip]
184
159
impl fmt:: Display for SpsrEL1 {
@@ -212,11 +187,72 @@ impl fmt::Display for SpsrEL1 {
212
187
}
213
188
}
214
189
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
+
215
245
/// Human readable print of the exception context.
216
246
impl fmt:: Display for ExceptionContext {
217
247
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
+
219
254
writeln ! ( f, "{}" , self . spsr_el1) ?;
255
+ writeln ! ( f, "ELR_EL1: {:#018x}" , self . elr_el1) ?;
220
256
writeln ! ( f) ?;
221
257
writeln ! ( f, "General purpose register:" ) ?;
222
258
0 commit comments