4
4
use bootloader:: NvmInterface ;
5
5
use cortex_m_rt:: entry;
6
6
use crc:: { Crc , CRC_16_IBM_3740 } ;
7
+ use embedded_hal:: delay:: DelayNs ;
7
8
#[ cfg( not( feature = "rtt-panic" ) ) ]
8
9
use panic_halt as _;
9
10
#[ cfg( feature = "rtt-panic" ) ]
10
11
use panic_rtt_target as _;
11
12
use rtt_target:: { rprintln, rtt_init_print} ;
12
- use va108xx_hal:: { pac, time:: Hertz } ;
13
+ use va108xx_hal:: { pac, time:: Hertz , timer :: CountdownTimer } ;
13
14
use vorago_reb1:: m95m01:: M95M01 ;
14
15
15
16
// Useful for debugging and see what the bootloader is doing. Enabled currently, because
16
17
// the binary stays small enough.
17
18
const RTT_PRINTOUT : bool = true ;
18
- const DEBUG_PRINTOUTS : bool = false ;
19
+ const DEBUG_PRINTOUTS : bool = true ;
20
+ // Small delay, allows RTT printout to catch up.
21
+ const BOOT_DELAY_MS : u32 = 2000 ;
19
22
20
23
// Dangerous option! An image with this option set to true will flash itself from RAM directly
21
24
// into the NVM. This can be used as a recovery option from a direct RAM flash to fix the NVM
@@ -35,23 +38,32 @@ const CLOCK_FREQ: Hertz = Hertz::from_raw(50_000_000);
35
38
36
39
// Important bootloader addresses and offsets, vector table information.
37
40
41
+ const NVM_SIZE : u32 = 0x20000 ;
38
42
const BOOTLOADER_START_ADDR : u32 = 0x0 ;
39
43
const BOOTLOADER_CRC_ADDR : u32 = BOOTLOADER_END_ADDR - 2 ;
40
44
// This is also the maximum size of the bootloader.
41
45
const BOOTLOADER_END_ADDR : u32 = 0x3000 ;
42
- const APP_A_START_ADDR : u32 = 0x3000 ;
46
+ const APP_A_START_ADDR : u32 = BOOTLOADER_END_ADDR ;
47
+ // 0x117F8
43
48
const APP_A_SIZE_ADDR : u32 = APP_A_END_ADDR - 8 ;
44
49
// Four bytes reserved, even when only 2 byte CRC is used. Leaves flexibility to switch to CRC32.
50
+ // 0x117FC
45
51
const APP_A_CRC_ADDR : u32 = APP_A_END_ADDR - 4 ;
46
- pub const APP_A_END_ADDR : u32 = 0x11000 ;
52
+ // 0x11800
53
+ pub const APP_A_END_ADDR : u32 = APP_A_START_ADDR + APP_IMG_SZ ;
47
54
// The actual size of the image which is relevant for CRC calculation.
48
- const APP_B_START_ADDR : u32 = 0x11000 ;
55
+ const APP_B_START_ADDR : u32 = APP_A_END_ADDR ;
49
56
// The actual size of the image which is relevant for CRC calculation.
57
+ // 0x1FFF8
50
58
const APP_B_SIZE_ADDR : u32 = APP_B_END_ADDR - 8 ;
51
59
// Four bytes reserved, even when only 2 byte CRC is used. Leaves flexibility to switch to CRC32.
60
+ // 0x1FFFC
52
61
const APP_B_CRC_ADDR : u32 = APP_B_END_ADDR - 4 ;
53
- pub const APP_B_END_ADDR : u32 = 0x20000 ;
54
- pub const APP_IMG_SZ : u32 = 0xE800 ;
62
+ // 0x20000
63
+ pub const APP_B_END_ADDR : u32 = NVM_SIZE ;
64
+ pub const APP_IMG_SZ : u32 = ( APP_B_END_ADDR - APP_A_START_ADDR ) / 2 ;
65
+
66
+ static_assertions:: const_assert!( ( APP_B_END_ADDR - BOOTLOADER_END_ADDR ) % 2 == 0 ) ;
55
67
56
68
pub const VECTOR_TABLE_OFFSET : u32 = 0x0 ;
57
69
pub const VECTOR_TABLE_LEN : u32 = 0xC0 ;
@@ -69,15 +81,15 @@ pub struct NvmWrapper(pub M95M01);
69
81
70
82
// Newtype pattern. We could now more easily swap the used NVM type.
71
83
impl NvmInterface for NvmWrapper {
72
- fn write ( & mut self , address : u32 , data : & [ u8 ] ) -> Result < ( ) , core:: convert:: Infallible > {
84
+ fn write ( & mut self , address : usize , data : & [ u8 ] ) -> Result < ( ) , core:: convert:: Infallible > {
73
85
self . 0 . write ( address, data)
74
86
}
75
87
76
- fn read ( & mut self , address : u32 , buf : & mut [ u8 ] ) -> Result < ( ) , core:: convert:: Infallible > {
88
+ fn read ( & mut self , address : usize , buf : & mut [ u8 ] ) -> Result < ( ) , core:: convert:: Infallible > {
77
89
self . 0 . read ( address, buf)
78
90
}
79
91
80
- fn verify ( & mut self , address : u32 , data : & [ u8 ] ) -> Result < bool , core:: convert:: Infallible > {
92
+ fn verify ( & mut self , address : usize , data : & [ u8 ] ) -> Result < bool , core:: convert:: Infallible > {
81
93
self . 0 . verify ( address, data)
82
94
}
83
95
}
@@ -90,6 +102,7 @@ fn main() -> ! {
90
102
}
91
103
let mut dp = pac:: Peripherals :: take ( ) . unwrap ( ) ;
92
104
let cp = cortex_m:: Peripherals :: take ( ) . unwrap ( ) ;
105
+ let mut timer = CountdownTimer :: new ( & mut dp. sysconfig , CLOCK_FREQ , dp. tim0 ) ;
93
106
94
107
let mut nvm = M95M01 :: new ( & mut dp. sysconfig , CLOCK_FREQ , dp. spic ) ;
95
108
@@ -124,9 +137,9 @@ fn main() -> ! {
124
137
}
125
138
}
126
139
127
- nvm. write ( BOOTLOADER_CRC_ADDR , & bootloader_crc. to_be_bytes ( ) )
140
+ nvm. write ( BOOTLOADER_CRC_ADDR as usize , & bootloader_crc. to_be_bytes ( ) )
128
141
. expect ( "writing CRC failed" ) ;
129
- if let Err ( e) = nvm. verify ( BOOTLOADER_CRC_ADDR , & bootloader_crc. to_be_bytes ( ) ) {
142
+ if let Err ( e) = nvm. verify ( BOOTLOADER_CRC_ADDR as usize , & bootloader_crc. to_be_bytes ( ) ) {
130
143
if RTT_PRINTOUT {
131
144
rprintln ! (
132
145
"error: CRC verification for bootloader self-flash failed: {:?}" ,
@@ -139,23 +152,28 @@ fn main() -> ! {
139
152
let mut nvm = NvmWrapper ( nvm) ;
140
153
141
154
// Check bootloader's CRC (and write it if blank)
142
- check_own_crc ( & dp. sysconfig , & cp, & mut nvm) ;
155
+ check_own_crc ( & dp. sysconfig , & cp, & mut nvm, & mut timer ) ;
143
156
144
157
if check_app_crc ( AppSel :: A ) {
145
- boot_app ( & dp. sysconfig , & cp, AppSel :: A )
158
+ boot_app ( & dp. sysconfig , & cp, AppSel :: A , & mut timer )
146
159
} else if check_app_crc ( AppSel :: B ) {
147
- boot_app ( & dp. sysconfig , & cp, AppSel :: B )
160
+ boot_app ( & dp. sysconfig , & cp, AppSel :: B , & mut timer )
148
161
} else {
149
162
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
150
163
rprintln ! ( "both images corrupt! booting image A" ) ;
151
164
}
152
165
// TODO: Shift a CCSDS packet out to inform host/OBC about image corruption.
153
166
// Both images seem to be corrupt. Boot default image A.
154
- boot_app ( & dp. sysconfig , & cp, AppSel :: A )
167
+ boot_app ( & dp. sysconfig , & cp, AppSel :: A , & mut timer )
155
168
}
156
169
}
157
170
158
- fn check_own_crc ( sysconfig : & pac:: Sysconfig , cp : & cortex_m:: Peripherals , nvm : & mut NvmWrapper ) {
171
+ fn check_own_crc (
172
+ sysconfig : & pac:: Sysconfig ,
173
+ cp : & cortex_m:: Peripherals ,
174
+ nvm : & mut NvmWrapper ,
175
+ timer : & mut CountdownTimer < pac:: Tim0 > ,
176
+ ) {
159
177
let crc_exp = unsafe { ( BOOTLOADER_CRC_ADDR as * const u16 ) . read_unaligned ( ) . to_be ( ) } ;
160
178
// I'd prefer to use [core::slice::from_raw_parts], but that is problematic
161
179
// because the address of the bootloader is 0x0, so the NULL check fails and the functions
@@ -176,7 +194,7 @@ fn check_own_crc(sysconfig: &pac::Sysconfig, cp: &cortex_m::Peripherals, nvm: &m
176
194
rprintln ! ( "BL CRC blank - prog new CRC" ) ;
177
195
}
178
196
// Blank CRC, write it to NVM.
179
- nvm. write ( BOOTLOADER_CRC_ADDR , & crc_calc. to_be_bytes ( ) )
197
+ nvm. write ( BOOTLOADER_CRC_ADDR as usize , & crc_calc. to_be_bytes ( ) )
180
198
. expect ( "writing CRC failed" ) ;
181
199
// The Vorago bootloader resets here. I am not sure why this is done but I think it is
182
200
// necessary because somehow the boot will not work if we just continue as usual.
@@ -191,7 +209,7 @@ fn check_own_crc(sysconfig: &pac::Sysconfig, cp: &cortex_m::Peripherals, nvm: &m
191
209
) ;
192
210
}
193
211
// TODO: Shift out minimal CCSDS frame to notify about bootloader corruption.
194
- boot_app ( sysconfig, cp, AppSel :: A ) ;
212
+ boot_app ( sysconfig, cp, AppSel :: A , timer ) ;
195
213
}
196
214
}
197
215
@@ -240,43 +258,52 @@ fn check_app_given_addr(crc_addr: u32, start_addr: u32, image_size_addr: u32) ->
240
258
241
259
// The boot works by copying the interrupt vector table (IVT) of the respective app to the
242
260
// base address in code RAM (0x0) and then performing a soft reset.
243
- fn boot_app ( syscfg : & pac:: Sysconfig , cp : & cortex_m:: Peripherals , app_sel : AppSel ) -> ! {
261
+ fn boot_app (
262
+ syscfg : & pac:: Sysconfig ,
263
+ cp : & cortex_m:: Peripherals ,
264
+ app_sel : AppSel ,
265
+ timer : & mut CountdownTimer < pac:: Tim0 > ,
266
+ ) -> ! {
244
267
if DEBUG_PRINTOUTS && RTT_PRINTOUT {
245
268
rprintln ! ( "booting app {:?}" , app_sel) ;
246
269
}
270
+ timer. delay_ms ( BOOT_DELAY_MS ) ;
271
+
272
+ // Clear all interrupts set.
273
+ unsafe {
274
+ cp. NVIC . icer [ 0 ] . write ( 0xFFFFFFFF ) ;
275
+ cp. NVIC . icpr [ 0 ] . write ( 0xFFFFFFFF ) ;
276
+ }
247
277
// Disable ROM protection.
248
- syscfg. rom_prot ( ) . write ( |w| unsafe { w . bits ( 1 ) } ) ;
278
+ syscfg. rom_prot ( ) . write ( |w| w . wren ( ) . set_bit ( ) ) ;
249
279
let base_addr = if app_sel == AppSel :: A {
250
280
APP_A_START_ADDR
251
281
} else {
252
282
APP_B_START_ADDR
253
283
} ;
254
- // Clear all interrupts set.
255
284
unsafe {
256
- cp. NVIC . icer [ 0 ] . write ( 0xFFFFFFFF ) ;
257
- cp. NVIC . icpr [ 0 ] . write ( 0xFFFFFFFF ) ;
258
-
259
285
// First 4 bytes done with inline assembly, writing to the physical address 0x0 can not
260
286
// be done without it. See https://users.rust-lang.org/t/reading-from-physical-address-0x0/117408/2.
261
- core:: ptr:: read ( base_addr as * const u32 ) ;
287
+ let first_four_bytes = core:: ptr:: read ( base_addr as * const u32 ) ;
262
288
core:: arch:: asm!(
263
- "str {0}, [{1}]" , // Load 4 bytes from src into r0 register
264
- in( reg) base_addr , // Input: App vector table.
289
+ "str {0}, [{1}]" ,
290
+ in( reg) first_four_bytes , // Input: App vector table.
265
291
in( reg) BOOTLOADER_START_ADDR as * mut u32 , // Input: destination pointer
266
292
) ;
267
293
core:: slice:: from_raw_parts_mut (
268
- ( BOOTLOADER_START_ADDR + 4 ) as * mut u32 ,
294
+ ( BOOTLOADER_START_ADDR + 4 ) as * mut u8 ,
269
295
( VECTOR_TABLE_LEN - 4 ) as usize ,
270
296
)
271
297
. copy_from_slice ( core:: slice:: from_raw_parts (
272
- ( base_addr + 4 ) as * const u32 ,
298
+ ( base_addr + 4 ) as * const u8 ,
273
299
( VECTOR_TABLE_LEN - 4 ) as usize ,
274
300
) ) ;
275
301
}
276
- /* Disable re-loading from FRAM/code ROM on soft reset */
302
+ // Disable re-loading from FRAM/code ROM on soft reset
277
303
syscfg
278
304
. rst_cntl_rom ( )
279
305
. modify ( |_, w| w. sysrstreq ( ) . clear_bit ( ) ) ;
306
+
280
307
soft_reset ( cp) ;
281
308
}
282
309
@@ -292,5 +319,8 @@ fn soft_reset(cp: &cortex_m::Peripherals) -> ! {
292
319
// Ensure completion of memory access.
293
320
cortex_m:: asm:: dsb ( ) ;
294
321
295
- unreachable ! ( ) ;
322
+ // Loop until the reset occurs.
323
+ loop {
324
+ cortex_m:: asm:: nop ( ) ;
325
+ }
296
326
}
0 commit comments