1
1
# Exception handling
2
2
3
- During the "Memory layout" section we decided to start out simple and leave out handling of
4
- exceptions. In this section we'll add support for handling exceptions ; this serves as an example of
3
+ During the "Memory layout" section, we decided to start out simple and leave out handling of
4
+ exceptions. In this section, we'll add support for handling them ; this serves as an example of
5
5
how to achieve compile time overridable behavior in stable Rust (i.e. without relying on the
6
6
unstable ` #[linkage = "weak"] ` attribute, which makes a symbol weak).
7
7
8
8
## Background information
9
9
10
10
In a nutshell, * exceptions* are a mechanism the Cortex-M and other architectures provide to let
11
- applications respond to asynchronous, usually external, events. The exception mechanism works like
12
- this: when the processor receives a signal or event associated to a type of exception it suspends
11
+ applications respond to asynchronous, usually external, events. The most prominent type of exception,
12
+ that most people will know, is the classical (hardware) interrupt.
13
+
14
+ The Cortex-M exception mechanism works like this:
15
+ When the processor receives a signal or event associated to a type of exception, it suspends
13
16
the execution of the current subroutine (by stashing the state in the call stack) and then proceeds
14
17
to execute the corresponding exception handler, another subroutine, in a new stack frame. After
15
- finishing the execution of the exception handler (i.e. returning from it) the processor resumes the
18
+ finishing the execution of the exception handler (i.e. returning from it), the processor resumes the
16
19
execution of the suspended subroutine.
17
20
18
21
The processor uses the vector table to decide what handler to execute. Each entry in the table
19
22
contains a pointer to a handler, and each entry corresponds to a different exception type. For
20
23
example, the second entry is the reset handler, the third entry is the NMI (Non Maskable Interrupt)
21
24
handler, and so on.
22
25
23
- As mentioned before the processor expects the vector table to be at some specific location and each
24
- entry in it can potentially be used by the processor at runtime so they must always contain valid
25
- values. Furthermore, we want the ` rt ` crate to be flexible so the end user can customize the
26
+ As mentioned before, the processor expects the vector table to be at some specific location in memory,
27
+ and each entry in it can potentially be used by the processor at runtime. Hence, the entries must always
28
+ contain valid values. Furthermore, we want the ` rt ` crate to be flexible so the end user can customize the
26
29
behavior of each exception handler. Finally, the vector table is read only memory, or rather in not
27
30
easily modified memory, so the user has to register the handler statically, rather than at runtime.
28
31
29
- To satisfy all these constraints we'll assign a * default* value to all the entries of the vector
30
- table in the ` rt ` crate but make these values kind of * weak* to let the end user override them
32
+ To satisfy all these constraints, we'll assign a * default* value to all the entries of the vector
33
+ table in the ` rt ` crate, but make these values kind of * weak* to let the end user override them
31
34
at compile time.
32
35
33
36
## Rust side
@@ -36,8 +39,8 @@ Let's see how all this can be implemented. For simplicity, we'll only work with
36
39
of the vector table; these entries are not device specific so they have the same function on any
37
40
kind of Cortex-M microcontroller.
38
41
39
- The first thing we'll do is create an array of vectors (pointers to exception handlers) in the Rust
40
- code:
42
+ The first thing we'll do is create an array of vectors (pointers to exception handlers) in the
43
+ ` rt ` crate's code:
41
44
42
45
``` rust
43
46
pub union Vector {
@@ -63,9 +66,7 @@ pub static EXCEPTIONS: [Vector; 14] = [
63
66
Vector { handler : HardFault },
64
67
Vector { handler : MemManage },
65
68
Vector { handler : BusFault },
66
- Vector {
67
- handler : UsageFault ,
68
- },
69
+ Vector { handler : UsageFault },
69
70
Vector { reserved : 0 },
70
71
Vector { reserved : 0 },
71
72
Vector { reserved : 0 },
@@ -83,7 +84,7 @@ should be assigned the value `0` so we use a union to do exactly that. The entri
83
84
to a handler make use of * external* functions; this is important because it lets the end user
84
85
* provide* the actual function definition.
85
86
86
- Next we define a default exception handler in the Rust code. Exceptions that have not been assigned
87
+ Next, we define a default exception handler in the Rust code. Exceptions that have not been assigned
87
88
a handler by the end user will make use of this default handler.
88
89
89
90
``` rust
@@ -130,8 +131,8 @@ PROVIDE(PendSV = DefaultExceptionHandler);
130
131
PROVIDE(SysTick = DefaultExceptionHandler);
131
132
```
132
133
133
- ` PROVIDE ` only takes effect when symbol on the RHS is still undefined after inspecting all the input
134
- object files. This is the scenario where the user didn't assign a handler to the exception.
134
+ ` PROVIDE ` only takes effect when a symbol on the RHS is still undefined after inspecting all the input
135
+ object files. This is the scenario where the user didn't implement the handler for the respective exception.
135
136
136
137
## Testing it
137
138
@@ -216,7 +217,7 @@ Contents of section .vector_table:
216
217
217
218
## Overriding a handler
218
219
219
- To override an exception handler the user has to provide a function whose symbol name exactly
220
+ To override an exception handler, the user has to provide a function whose symbol name exactly
220
221
matches the name we used in ` EXCEPTIONS ` .
221
222
222
223
``` rust
@@ -262,9 +263,9 @@ Process 1 stopped
262
263
The program now executes the user defined ` HardFault ` function instead of the
263
264
` DefaultExceptionHandler ` in the ` rt ` crate.
264
265
265
- Like our first attempt at a ` main ` interface this first implementation has the problem of having no
266
+ Like our first attempt at a ` main ` interface, this first implementation has the problem of having no
266
267
type safety. It's also easy to mistype the name of the exception, but that doesn't produce an error
267
- or warning instead the user defined handler is simply ignored. Those problems can be fixed using a
268
+ or warning. Instead the user defined handler is simply ignored. Those problems can be fixed using a
268
269
macro like the [ ` exception! ` ] macro defined in ` cortex-m-rt ` .
269
270
270
271
[ `exception!` ] : https://github.com/japaric/cortex-m-rt/blob/v0.5.1/src/lib.rs#L79
0 commit comments