Skip to content

Commit 9eb5f47

Browse files
committed
Restored self-update code
1 parent 9882580 commit 9eb5f47

1 file changed

Lines changed: 331 additions & 0 deletions

File tree

src/loader.c

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,337 @@
2525
#include "spi_flash.h"
2626
#include "wolfboot/wolfboot.h"
2727

28+
#ifdef RAM_CODE
29+
extern unsigned int _start_text;
30+
static volatile const uint32_t __attribute__((used)) wolfboot_version = WOLFBOOT_VERSION;
31+
extern void (** const IV_RAM)(void);
32+
#endif
33+
34+
#define FLASHBUFFER_SIZE 256
35+
36+
#ifndef DUALBANK_SWAP
37+
static int wolfBoot_copy_sector(struct wolfBoot_image *src, struct wolfBoot_image *dst, uint32_t sector)
38+
{
39+
uint32_t pos = 0;
40+
uint32_t src_sector_offset = (sector * WOLFBOOT_SECTOR_SIZE);
41+
uint32_t dst_sector_offset = (sector * WOLFBOOT_SECTOR_SIZE);
42+
if (src == dst)
43+
return 0;
44+
45+
if (src->part == PART_SWAP)
46+
src_sector_offset = 0;
47+
if (dst->part == PART_SWAP)
48+
dst_sector_offset = 0;
49+
#ifdef EXT_FLASH
50+
if (PART_IS_EXT(src)) {
51+
uint8_t buffer[FLASHBUFFER_SIZE];
52+
wb_flash_erase(dst, dst_sector_offset, WOLFBOOT_SECTOR_SIZE);
53+
while (pos < WOLFBOOT_SECTOR_SIZE) {
54+
if (src_sector_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
55+
ext_flash_read((uint32_t)(src->hdr) + src_sector_offset + pos, (void *)buffer, FLASHBUFFER_SIZE);
56+
wb_flash_write(dst, dst_sector_offset + pos, buffer, FLASHBUFFER_SIZE);
57+
}
58+
pos += FLASHBUFFER_SIZE;
59+
}
60+
return pos;
61+
}
62+
#endif
63+
wb_flash_erase(dst, dst_sector_offset, WOLFBOOT_SECTOR_SIZE);
64+
while (pos < WOLFBOOT_SECTOR_SIZE) {
65+
if (src_sector_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
66+
uint8_t *orig = (uint8_t*)(src->hdr + src_sector_offset + pos);
67+
wb_flash_write(dst, dst_sector_offset + pos, orig, FLASHBUFFER_SIZE);
68+
}
69+
pos += FLASHBUFFER_SIZE;
70+
}
71+
return pos;
72+
}
73+
74+
static int wolfBoot_update(int fallback_allowed)
75+
{
76+
uint32_t total_size = 0;
77+
const uint32_t sector_size = WOLFBOOT_SECTOR_SIZE;
78+
uint32_t sector = 0;
79+
uint8_t flag, st;
80+
struct wolfBoot_image boot, update, swap;
81+
82+
/* No Safety check on open: we might be in the middle of a broken update */
83+
wolfBoot_open_image(&update, PART_UPDATE);
84+
wolfBoot_open_image(&boot, PART_BOOT);
85+
wolfBoot_open_image(&swap, PART_SWAP);
86+
87+
/* Use biggest size for the swap */
88+
total_size = boot.fw_size + IMAGE_HEADER_SIZE;
89+
if ((update.fw_size + IMAGE_HEADER_SIZE) > total_size)
90+
total_size = update.fw_size + IMAGE_HEADER_SIZE;
91+
92+
if (total_size <= IMAGE_HEADER_SIZE)
93+
return -1;
94+
95+
/* Check the first sector to detect interrupted update */
96+
if ((wolfBoot_get_sector_flag(PART_UPDATE, 0, &flag) < 0) || (flag == SECT_FLAG_NEW))
97+
{
98+
uint16_t update_type;
99+
/* In case this is a new update, do the required
100+
* checks on the firmware update
101+
* before starting the swap
102+
*/
103+
104+
update_type = wolfBoot_get_image_type(PART_UPDATE);
105+
if (((update_type & 0x00FF) != HDR_IMG_TYPE_APP) || ((update_type & 0xFF00) != HDR_IMG_TYPE_AUTH))
106+
return -1;
107+
if (!update.hdr_ok || (wolfBoot_verify_integrity(&update) < 0)
108+
|| (wolfBoot_verify_authenticity(&update) < 0)) {
109+
return -1;
110+
}
111+
#ifndef ALLOW_DOWNGRADE
112+
if ( !fallback_allowed &&
113+
(wolfBoot_update_firmware_version() <= wolfBoot_current_firmware_version()) )
114+
return -1;
115+
#endif
116+
}
117+
118+
hal_flash_unlock();
119+
#ifdef EXT_FLASH
120+
ext_flash_unlock();
121+
#endif
122+
123+
/* Interruptible swap
124+
* The status is saved in the sector flags of the update partition.
125+
* If something goes wrong, the operation will be resumed upon reboot.
126+
*/
127+
while ((sector * sector_size) < total_size) {
128+
if ((wolfBoot_get_sector_flag(PART_UPDATE, sector, &flag) != 0) || (flag == SECT_FLAG_NEW)) {
129+
flag = SECT_FLAG_SWAPPING;
130+
wolfBoot_copy_sector(&update, &swap, sector);
131+
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
132+
wolfBoot_set_sector_flag(PART_UPDATE, sector, flag);
133+
}
134+
if (flag == SECT_FLAG_SWAPPING) {
135+
uint32_t size = total_size - (sector * sector_size);
136+
if (size > sector_size)
137+
size = sector_size;
138+
flag = SECT_FLAG_BACKUP;
139+
wolfBoot_copy_sector(&boot, &update, sector);
140+
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
141+
wolfBoot_set_sector_flag(PART_UPDATE, sector, flag);
142+
}
143+
if (flag == SECT_FLAG_BACKUP) {
144+
uint32_t size = total_size - (sector * sector_size);
145+
if (size > sector_size)
146+
size = sector_size;
147+
flag = SECT_FLAG_UPDATED;
148+
wolfBoot_copy_sector(&swap, &boot, sector);
149+
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
150+
wolfBoot_set_sector_flag(PART_UPDATE, sector, flag);
151+
}
152+
sector++;
153+
}
154+
while((sector * sector_size) < WOLFBOOT_PARTITION_SIZE) {
155+
wb_flash_erase(&boot, sector * sector_size, sector_size);
156+
wb_flash_erase(&update, sector * sector_size, sector_size);
157+
sector++;
158+
}
159+
wb_flash_erase(&swap, 0, WOLFBOOT_SECTOR_SIZE);
160+
st = IMG_STATE_TESTING;
161+
wolfBoot_set_partition_state(PART_BOOT, st);
162+
#ifdef EXT_FLASH
163+
ext_flash_lock();
164+
#endif
165+
hal_flash_lock();
166+
return 0;
167+
}
168+
169+
#else /* DUALBANK_SWAP */
170+
171+
static inline void boot_panic(void)
172+
{
173+
while(1)
174+
;
175+
}
176+
177+
static void RAMFUNCTION wolfBoot_start(void)
178+
{
179+
int ret;
180+
struct wolfBoot_image fw_image, boot_image;
181+
uint8_t p_state;
182+
uint32_t boot_v, update_v;
183+
int candidate = PART_BOOT;
184+
int fallback_is_possible = 0;
185+
186+
/* Find the candidate */
187+
boot_v = wolfBoot_current_firmware_version();
188+
update_v = wolfBoot_update_firmware_version();
189+
190+
/* panic if no images available */
191+
if ((boot_v == 0) && (update_v == 0))
192+
boot_panic();
193+
194+
else if (boot_v == 0) /* No primary image */
195+
{
196+
candidate = PART_UPDATE;
197+
}
198+
else if ((boot_v > 0) && (update_v > 0)) {
199+
fallback_is_possible = 1;
200+
if (update_v > boot_v)
201+
candidate = PART_UPDATE;
202+
}
203+
204+
/* Check current status for failure (still in TESTING), and fall-back
205+
* if an alternative is available
206+
*/
207+
if (fallback_is_possible &&
208+
(wolfBoot_get_partition_state(candidate, &p_state) == 0) &&
209+
(p_state == IMG_STATE_TESTING))
210+
{
211+
candidate ^= 1; /* switch to other partition if available */
212+
}
213+
214+
for (;;) {
215+
if ((wolfBoot_open_image(&fw_image, candidate) < 0) ||
216+
(wolfBoot_verify_integrity(&fw_image) < 0) ||
217+
(wolfBoot_verify_authenticity(&fw_image) < 0)) {
218+
219+
/* panic if authentication fails and no backup */
220+
if (!fallback_is_possible)
221+
boot_panic();
222+
else {
223+
/* Invalidate failing image and switch to the
224+
* other partition
225+
*/
226+
fallback_is_possible = 0;
227+
wolfBoot_erase_partition(candidate);
228+
candidate ^= 1;
229+
}
230+
} else
231+
break; /* candidate successfully authenticated */
232+
}
233+
234+
/* First time we boot this update, set to TESTING to await
235+
* confirmation from the system
236+
*/
237+
if ((wolfBoot_get_partition_state(candidate, &p_state) == 0) &&
238+
(p_state == IMG_STATE_UPDATING))
239+
{
240+
hal_flash_unlock();
241+
wolfBoot_set_partition_state(candidate, IMG_STATE_TESTING);
242+
hal_flash_lock();
243+
}
244+
245+
/* Booting from update is possible via HW-assisted swap */
246+
if (candidate == PART_UPDATE)
247+
hal_flash_dualbank_swap();
248+
249+
hal_prepare_boot();
250+
do_boot((void *)WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE);
251+
}
252+
#endif
253+
254+
#ifdef RAM_CODE
255+
256+
static void RAMFUNCTION wolfBoot_erase_bootloader(void)
257+
{
258+
uint32_t *start = (uint32_t *)&_start_text;
259+
uint32_t len = WOLFBOOT_PARTITION_BOOT_ADDRESS - (uint32_t)start;
260+
hal_flash_erase((uint32_t)start, len);
261+
262+
}
263+
264+
#include <string.h>
265+
266+
static void RAMFUNCTION wolfBoot_self_update(struct wolfBoot_image *src)
267+
{
268+
uint32_t pos = 0;
269+
uint32_t src_offset = IMAGE_HEADER_SIZE;
270+
271+
hal_flash_unlock();
272+
wolfBoot_erase_bootloader();
273+
#ifdef EXT_FLASH
274+
while (pos < src->fw_size) {
275+
if (PART_IS_EXT(src)) {
276+
uint8_t buffer[FLASHBUFFER_SIZE];
277+
if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
278+
ext_flash_read((uint32_t)(src->hdr) + src_offset + pos, (void *)buffer, FLASHBUFFER_SIZE);
279+
hal_flash_write(pos + (uint32_t)&_start_text, buffer, FLASHBUFFER_SIZE);
280+
}
281+
pos += FLASHBUFFER_SIZE;
282+
}
283+
goto lock_and_reset;
284+
}
285+
#endif
286+
while (pos < src->fw_size) {
287+
if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
288+
uint8_t *orig = (uint8_t*)(src->hdr + src_offset + pos);
289+
hal_flash_write(pos + (uint32_t)&_start_text, orig, FLASHBUFFER_SIZE);
290+
}
291+
pos += FLASHBUFFER_SIZE;
292+
}
293+
294+
lock_and_reset:
295+
hal_flash_lock();
296+
arch_reboot();
297+
}
298+
299+
static void wolfBoot_check_self_update(void)
300+
{
301+
uint8_t st;
302+
struct wolfBoot_image update;
303+
uint8_t *update_type;
304+
uint32_t update_version;
305+
306+
/* Check for self update in the UPDATE partition */
307+
if ((wolfBoot_get_partition_state(PART_UPDATE, &st) == 0) && (st == IMG_STATE_UPDATING) &&
308+
(wolfBoot_open_image(&update, PART_UPDATE) == 0) &&
309+
wolfBoot_get_image_type(PART_UPDATE) == (HDR_IMG_TYPE_WOLFBOOT | HDR_IMG_TYPE_AUTH)) {
310+
uint32_t update_version = wolfBoot_update_firmware_version();
311+
if (update_version <= wolfboot_version) {
312+
hal_flash_unlock();
313+
wolfBoot_erase_partition(PART_UPDATE);
314+
hal_flash_lock();
315+
return;
316+
}
317+
if (wolfBoot_verify_integrity(&update) < 0)
318+
return;
319+
if (wolfBoot_verify_authenticity(&update) < 0)
320+
return;
321+
wolfBoot_self_update(&update);
322+
}
323+
}
324+
#endif /* RAM_CODE for self_update */
325+
326+
#ifndef DUALBANK_SWAP
327+
static void wolfBoot_start(void)
328+
{
329+
uint8_t st;
330+
struct wolfBoot_image boot, update;
331+
332+
#ifdef RAM_CODE
333+
wolfBoot_check_self_update();
334+
#endif
335+
336+
/* Check if the BOOT partition is still in TESTING,
337+
* to trigger fallback.
338+
*/
339+
if ((wolfBoot_get_partition_state(PART_BOOT, &st) == 0) && (st == IMG_STATE_TESTING)) {
340+
wolfBoot_update_trigger();
341+
wolfBoot_update(1);
342+
/* Check for new updates in the UPDATE partition */
343+
} else if ((wolfBoot_get_partition_state(PART_UPDATE, &st) == 0) && (st == IMG_STATE_UPDATING)) {
344+
wolfBoot_update(0);
345+
}
346+
if ((wolfBoot_open_image(&boot, PART_BOOT) < 0) ||
347+
(wolfBoot_verify_integrity(&boot) < 0) ||
348+
(wolfBoot_verify_authenticity(&boot) < 0)) {
349+
if (wolfBoot_update(1) < 0) {
350+
while(1)
351+
/* panic */;
352+
}
353+
}
354+
hal_prepare_boot();
355+
do_boot((void *)boot.fw_base);
356+
}
357+
#endif /* ifndef DUALBANK_SWAP */
358+
28359
int main(void)
29360
{
30361
hal_init();

0 commit comments

Comments
 (0)