@@ -16,6 +16,10 @@ fn main() -> ! {
16
16
// being uniquely held. The first part we can ensure by putting this at the
17
17
// top of `main`, which `entry` makes hard to reentrantly call in safe code.
18
18
// The second one is architectural but holds due to our design.
19
+ //
20
+ // You're probably wondering why this is `steal` and not `take`. It's
21
+ // because `take` winds up needing an `unwrap` that is relatively expensive
22
+ // in code size, to check a property that should not be able to fail.
19
23
let p = unsafe { lpc55_pac:: Peripherals :: steal ( ) } ;
20
24
21
25
// Make the USER button a digital input.
@@ -80,8 +84,22 @@ fn boot_into(
80
84
@ From the perspective of this program, we're never leaving
81
85
@ this asm block. This means we can trash Rust invariants.
82
86
83
- @ Scribble our memory. Note that this destroys our stack! We
84
- @ can't refer to any stack-allocated anything from here on.
87
+ @ Usage of registers established by the parameters to asm!
88
+ @ below:
89
+ @ r0 = target program reset vector
90
+ @ r1 = target program initial stack pointer
91
+ @ r2 = target program vector table address
92
+ @
93
+ @ All other registers are available as temporaries, and we'll
94
+ @ wind up trashing them all one way or another.
95
+
96
+ @ Write zeros over our RAM. Note that this destroys our stack!
97
+ @ We can't refer to any stack-allocated anything from here on.
98
+ @ (...not that we were going to.)
99
+ @
100
+ @ r3 = current address
101
+ @ r4 = end address
102
+ @ r5 = zero
85
103
movw r3, #:lower16:__start_of_ram
86
104
movt r3, #:upper16:__start_of_ram
87
105
movw r4, #:lower16:__end_of_ram
@@ -92,25 +110,35 @@ fn boot_into(
92
110
cmp r3, r4
93
111
bne 1b
94
112
95
- @ Move the vector table location to the image's table.
113
+ @ Update the VTOR register to place the vector table in the
114
+ @ target program image.
115
+ @
96
116
@ Note that this means we can't do anything that might
97
117
@ fault (other than the jump into the image) from here
98
118
@ on.
99
- movw r3, #:lower16:0xE000ED08
119
+ movw r3, #:lower16:0xE000ED08 @ Get VTOR address into r3
100
120
movt r3, #:upper16:0xE000ED08
101
121
102
122
str r2, [r3]
103
123
104
- @ Clear our registers except the ones containing data
105
- @ controlled by the image. Disclosing that data is fine.
124
+ @ The target program should not assume anything about the
125
+ @ initial contents of its registers except for PC and SP.
126
+ @ Just in case, we'll clear our registers except the ones
127
+ @ that hold values controlled by the target program. Since
128
+ @ it already knows where its reset vector and stack pointer
129
+ @ are, disclosing them is not a problem.
130
+ @
131
+ @ (You may be wondering why we don't clear _all_ registers.
132
+ @ The answer is space: we can save a few bytes by skipping
133
+ @ the image-controlled registers r0-r2.)
106
134
@
107
135
@ We can move an immediate zero into any of r0-r7 using a
108
136
@ simple MOV-immediate instruction (2 bytes), but accessing
109
137
@ r8+ in this manner costs 4 bytes instead of 2. However,
110
138
@ moving a value from a low register to high is still 2
111
139
@ bytes. And so:
112
- movs r3, #0
113
- movs r4, #0
140
+ movs r3, #0 @ note: the S in MOVS is required for the
141
+ movs r4, #0 @ 2-byte encoding to be chosen.
114
142
movs r5, #0
115
143
movs r6, #0
116
144
movs r7, #0
@@ -124,7 +152,11 @@ fn boot_into(
124
152
mov r14, r7 @ LR
125
153
126
154
@ Set the stack pointer to the location the image wants.
127
- msr MSP, r1
155
+ @ Strictly speaking we want to set the Main Stack Pointer or
156
+ @ MSP. However, by default SP is an alias of MSP, and we
157
+ @ haven't changed this. MOV SP is two bytes shorter than
158
+ @ MSR MSP.
159
+ mov SP, r1
128
160
129
161
@ Jump into the image. We're using a simple BX here so that
130
162
@ we remain in secure mode.
0 commit comments