Skip to content

Commit a9f4347

Browse files
committed
[nrf noup] zephyr: Keep boot preference after reboot
Add a possibility to keep the boot preference value between device resets. Ref: NCSDK-35479 Signed-off-by: Tomasz Chyrowicz <[email protected]>
1 parent 3839107 commit a9f4347

File tree

1 file changed

+217
-34
lines changed

1 file changed

+217
-34
lines changed

boot/bootutil/zephyr/src/boot_request_retention.c

Lines changed: 217 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,23 @@
1414
/** Additional memory used by the retention subsystem (2B - prefix, 4B - CRC).*/
1515
#define BOOT_REQUEST_ENTRY_METADATA_SIZE (2 + 4)
1616

17+
/** Size of the retention area used for copying boot request entries. */
18+
#define BOOT_REQUEST_RETENTION_SIZE (BOOT_REQUEST_ENTRY_MAX * sizeof(uint8_t))
19+
20+
/** Value indicating that the data in the retention area is valid. */
21+
#define DATA_VALID_VALUE 1
22+
23+
/** Number of images supported by the bootloader requests. */
24+
#define BOOT_REQUEST_IMG_NUM 2
25+
1726
BOOT_LOG_MODULE_REGISTER(bootloader_request);
1827

1928
static const struct device *bootloader_request_dev =
2029
DEVICE_DT_GET(DT_CHOSEN(nrf_bootloader_request));
30+
#ifdef NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP
31+
static const struct device *bootloader_request_backup_dev =
32+
DEVICE_DT_GET(DT_CHOSEN(nrf_bootloader_request_backup));
33+
#endif
2134

2235
enum boot_request_type {
2336
/** Invalid request. */
@@ -141,18 +154,190 @@ static int boot_request_entry_find(enum boot_request_type type, boot_request_img
141154
return 0;
142155
}
143156

157+
#ifdef NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP
158+
static int boot_request_copy(const struct device *dst, const struct device *src)
159+
{
160+
uint8_t buffer[BOOT_REQUEST_RETENTION_SIZE];
161+
int rc;
162+
163+
rc = retention_read(src, 0, buffer, sizeof(buffer));
164+
if (rc != 0) {
165+
return rc;
166+
}
167+
168+
rc = retention_write(dst, 0, buffer, sizeof(buffer));
169+
if (rc != 0) {
170+
return rc;
171+
}
172+
173+
return 0;
174+
}
175+
176+
static bool boot_request_equal(const struct device *dev1, const struct device *dev2)
177+
{
178+
uint8_t buffer1[BOOT_REQUEST_RETENTION_SIZE];
179+
uint8_t buffer2[BOOT_REQUEST_RETENTION_SIZE];
180+
int rc;
181+
182+
rc = retention_read(dev1, 0, buffer1, sizeof(buffer1));
183+
if (rc != 0) {
184+
return false;
185+
}
186+
187+
rc = retention_read(dev2, 0, buffer2, sizeof(buffer2));
188+
if (rc != 0) {
189+
return false;
190+
}
191+
192+
return (memcmp(buffer1, buffer2, sizeof(buffer1)) == 0);
193+
}
194+
195+
static bool boot_request_updateable(void)
196+
{
197+
if (retention_is_valid(bootloader_request_dev) != DATA_VALID_VALUE) {
198+
if (retention_is_valid(bootloader_request_backup_dev) == DATA_VALID_VALUE) {
199+
/* Recover main area from a valid backup. */
200+
if (boot_request_copy(bootloader_request_dev,
201+
bootloader_request_backup_dev) != 0) {
202+
return false;
203+
}
204+
} else if (retention_clear(bootloader_request_dev) != 0) {
205+
/* Both areas are not valid - clear the main area. */
206+
return false;
207+
}
208+
}
209+
210+
if (retention_is_valid(bootloader_request_dev) != DATA_VALID_VALUE) {
211+
/* Cannot update area if it is still corrupted. */
212+
return false;
213+
}
214+
215+
return true;
216+
}
217+
#endif /* NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP */
218+
219+
static int boot_request_read(enum boot_request_type type, boot_request_img_t image, uint8_t *value)
220+
{
221+
size_t req_entry;
222+
int ret;
223+
224+
ret = boot_request_entry_find(type, image, &req_entry);
225+
if (ret != 0) {
226+
return -EINVAL;
227+
}
228+
229+
#ifdef NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP
230+
if (retention_is_valid(bootloader_request_dev) == DATA_VALID_VALUE) {
231+
/* Read from the main area. */
232+
ret = retention_read(bootloader_request_dev, req_entry * sizeof(uint8_t),
233+
(void *)value, sizeof(uint8_t));
234+
} else if (retention_is_valid(bootloader_request_backup_dev) == DATA_VALID_VALUE) {
235+
/* Read from backup area. */
236+
ret = retention_read(bootloader_request_backup_dev, req_entry * sizeof(uint8_t),
237+
(void *)value, sizeof(uint8_t));
238+
} else {
239+
/* Both areas are invalid. */
240+
return -EIO;
241+
}
242+
#else
243+
ret = retention_read(bootloader_request_dev, req_entry * sizeof(uint8_t), (void *)value,
244+
sizeof(uint8_t));
245+
#endif
246+
return ret;
247+
}
248+
144249
int boot_request_init(void)
145250
{
146251
if (!device_is_ready(bootloader_request_dev)) {
147252
return -EIO;
148253
}
149254

255+
#ifdef NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP
256+
if (!device_is_ready(bootloader_request_backup_dev)) {
257+
return -EIO;
258+
}
259+
260+
/* Both areas must have the same size. */
261+
if ((retenstion_size(bootloader_request_dev) != BOOT_REQUEST_RETENTION_SIZE) ||
262+
(retention_size(bootloader_request_backup_dev) != BOOT_REQUEST_RETENTION_SIZE)) {
263+
return -EIO;
264+
}
265+
266+
if (retention_is_valid(bootloader_request_dev) == DATA_VALID_VALUE) {
267+
if (retention_is_valid(bootloader_request_backup_dev) == DATA_VALID_VALUE) {
268+
if (!boot_request_equal(bootloader_request_dev,
269+
bootloader_request_backup_dev)) {
270+
/* Primary is valid, backup is outdated. */
271+
boot_request_copy(bootloader_request_backup_dev,
272+
bootloader_request_dev);
273+
} else {
274+
/* Both are valid and equal, nothing to do. */
275+
}
276+
} else {
277+
/* Backup is invalid, copy primary to backup. */
278+
boot_request_copy(bootloader_request_backup_dev, bootloader_request_dev);
279+
}
280+
} else {
281+
if (retention_is_valid(bootloader_request_backup_dev) == DATA_VALID_VALUE) {
282+
/* Primary is invalid, restore from backup. */
283+
boot_request_copy(bootloader_request_dev, bootloader_request_backup_dev);
284+
} else {
285+
/* Both are invalid, clear both. */
286+
retention_clear(bootloader_request_dev);
287+
retention_clear(bootloader_request_backup_dev);
288+
}
289+
}
290+
#endif
291+
150292
return 0;
151293
}
152294

153295
int boot_request_clear(void)
154296
{
297+
#ifdef NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP
298+
uint8_t value = BOOT_REQUEST_SLOT_INVALID;
299+
size_t req_entry;
300+
int ret;
301+
uint8_t image;
302+
303+
if (retention_is_valid(bootloader_request_backup_dev) == DATA_VALID_VALUE) {
304+
/* Erase the main area. */
305+
ret = retention_clear(bootloader_request_dev);
306+
if (ret != 0) {
307+
return ret;
308+
}
309+
310+
/* Set the boot preference, based on the backup data. */
311+
for (image = 0; image < BOOT_REQUEST_IMG_NUM; image++) {
312+
ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image,
313+
&req_entry);
314+
if (ret != 0) {
315+
return ret;
316+
}
317+
318+
ret = retention_read(bootloader_request_backup_dev,
319+
req_entry * sizeof(value), (void *)&value,
320+
sizeof(value));
321+
if (ret != 0) {
322+
return ret;
323+
}
324+
325+
ret = retention_write(bootloader_request_dev, req_entry * sizeof(value),
326+
(void *)&value, sizeof(value));
327+
if (ret != 0) {
328+
return ret;
329+
}
330+
}
331+
332+
/* Sync backup with the main area. */
333+
return boot_request_copy(bootloader_request_backup_dev, bootloader_request_dev);
334+
}
335+
336+
/* Backup is invalid, do not clear the memory to keep at least one valid copy. */
337+
return 0;
338+
#else
155339
return retention_clear(bootloader_request_dev);
340+
#endif
156341
}
157342

158343
int boot_request_confirm_slot(uint8_t image, enum boot_slot slot)
@@ -161,6 +346,13 @@ int boot_request_confirm_slot(uint8_t image, enum boot_slot slot)
161346
size_t req_entry;
162347
int ret;
163348

349+
#ifdef NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP
350+
if (!boot_request_updateable()) {
351+
/* Cannot update area if it is corrupted. */
352+
return -EIO;
353+
}
354+
#endif
355+
164356
ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry);
165357
if (ret != 0) {
166358
return ret;
@@ -184,16 +376,9 @@ int boot_request_confirm_slot(uint8_t image, enum boot_slot slot)
184376
bool boot_request_check_confirmed_slot(uint8_t image, enum boot_slot slot)
185377
{
186378
uint8_t value = BOOT_REQUEST_SLOT_INVALID;
187-
size_t req_entry;
188379
int ret;
189380

190-
ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry);
191-
if (ret != 0) {
192-
return false;
193-
}
194-
195-
ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value,
196-
sizeof(value));
381+
ret = boot_request_read(BOOT_REQUEST_IMG_CONFIRM, image, &value);
197382
if (ret != 0) {
198383
return false;
199384
}
@@ -216,6 +401,13 @@ int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot)
216401
size_t req_entry;
217402
int ret;
218403

404+
#ifdef NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP
405+
if (!boot_request_updateable()) {
406+
/* Cannot update area if it is corrupted. */
407+
return -EIO;
408+
}
409+
#endif
410+
219411
ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry);
220412
if (ret != 0) {
221413
return ret;
@@ -239,16 +431,9 @@ int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot)
239431
enum boot_slot boot_request_get_preferred_slot(uint8_t image)
240432
{
241433
uint8_t value = BOOT_REQUEST_SLOT_INVALID;
242-
size_t req_entry;
243434
int ret;
244435

245-
ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry);
246-
if (ret != 0) {
247-
return BOOT_SLOT_NONE;
248-
}
249-
250-
ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value,
251-
sizeof(value));
436+
ret = boot_request_read(BOOT_REQUEST_IMG_PREFERENCE, image, &value);
252437
if (ret != 0) {
253438
return BOOT_SLOT_NONE;
254439
}
@@ -271,6 +456,13 @@ int boot_request_enter_recovery(void)
271456
size_t req_entry;
272457
int ret;
273458

459+
#ifdef NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP
460+
if (!boot_request_updateable()) {
461+
/* Cannot update area if it is corrupted. */
462+
return -EIO;
463+
}
464+
#endif
465+
274466
ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER,
275467
&req_entry);
276468
if (ret != 0) {
@@ -285,17 +477,9 @@ int boot_request_enter_recovery(void)
285477
bool boot_request_detect_recovery(void)
286478
{
287479
uint8_t value = BOOT_REQUEST_MODE_INVALID;
288-
size_t req_entry;
289480
int ret;
290481

291-
ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER,
292-
&req_entry);
293-
if (ret != 0) {
294-
return false;
295-
}
296-
297-
ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value,
298-
sizeof(value));
482+
ret = boot_request_read(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, &value);
299483
if ((ret == 0) && (value == BOOT_REQUEST_MODE_RECOVERY)) {
300484
return true;
301485
}
@@ -310,6 +494,13 @@ int boot_request_enter_firmware_loader(void)
310494
size_t req_entry;
311495
int ret;
312496

497+
#ifdef NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP
498+
if (!boot_request_updateable()) {
499+
/* Cannot update area if it is corrupted. */
500+
return -EIO;
501+
}
502+
#endif
503+
313504
ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER,
314505
&req_entry);
315506
if (ret != 0) {
@@ -324,17 +515,9 @@ int boot_request_enter_firmware_loader(void)
324515
bool boot_request_detect_firmware_loader(void)
325516
{
326517
uint8_t value = BOOT_REQUEST_MODE_INVALID;
327-
size_t req_entry;
328518
int ret;
329519

330-
ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER,
331-
&req_entry);
332-
if (ret != 0) {
333-
return false;
334-
}
335-
336-
ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value,
337-
sizeof(value));
520+
ret = boot_request_read(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, &value);
338521
if ((ret == 0) && (value == BOOT_REQUEST_MODE_FIRMWARE_LOADER)) {
339522
return true;
340523
}

0 commit comments

Comments
 (0)