-
Notifications
You must be signed in to change notification settings - Fork 247
[nrf noup] zephyr: Keep boot preference after reboot #574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
tomchy
wants to merge
1
commit into
nrfconnect:main
Choose a base branch
from
tomchy:feature/boot_req/NCSDK-35479_Preserve_boot_request_values
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+878
−305
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,378 @@ | ||
| /* | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * Copyright (c) 2025 Nordic Semiconductor ASA | ||
| */ | ||
| #include <bootutil/boot_request.h> | ||
|
|
||
| #include "bootutil/bootutil_log.h" | ||
| #include "boot_request_mem.h" | ||
|
|
||
| /** Special value of image number, indicating a request to the bootloader. */ | ||
| #define BOOT_REQUEST_IMG_BOOTLOADER 0xFF | ||
|
|
||
| /** Additional memory used by the retention subsystem (2B - prefix, 4B - CRC).*/ | ||
| #define BOOT_REQUEST_ENTRY_METADATA_SIZE (2 + 4) | ||
|
|
||
| /** Number of images supported by the bootloader requests. */ | ||
| #define BOOT_REQUEST_IMG_NUM 2 | ||
|
|
||
| BOOT_LOG_MODULE_REGISTER(bootloader_request); | ||
|
|
||
| enum boot_request_type { | ||
| /** Invalid request. */ | ||
| BOOT_REQUEST_INVALID = 0, | ||
|
|
||
| /** Request a change in the bootloader boot mode. | ||
| * | ||
| * @details Use @p boot_request_mode as argument. | ||
| * @p BOOT_REQUEST_IMG_BOOTLOADER as image number. | ||
| * | ||
| * @note Used to trigger recovery through i.e. retention sybsystem. | ||
| */ | ||
| BOOT_REQUEST_BOOT_MODE = 1, | ||
|
|
||
| /** Select the preferred image to be selected during boot or update. | ||
| * | ||
| * @details Use @p boot_request_slot_t as argument. | ||
| * | ||
| * @note Used in the Direct XIP mode. | ||
| */ | ||
| BOOT_REQUEST_IMG_PREFERENCE = 2, | ||
|
|
||
| /** Request a confirmation of an image. | ||
| * | ||
| * @details Use @p boot_request_slot_t as argument. | ||
| * | ||
| * @note Used if the code cannot modify the image trailer directly. | ||
| */ | ||
| BOOT_REQUEST_IMG_CONFIRM = 3, | ||
| }; | ||
|
|
||
| /* Entries inside the boot request shared memory. */ | ||
| enum boot_request_entry { | ||
| BOOT_REQUEST_ENTRY_BOOT_MODE = 0, | ||
| BOOT_REQUEST_ENTRY_IMAGE_0_PREFERENCE = 1, | ||
| BOOT_REQUEST_ENTRY_IMAGE_0_CONFIRM = 2, | ||
| BOOT_REQUEST_ENTRY_IMAGE_1_PREFERENCE = 3, | ||
| BOOT_REQUEST_ENTRY_IMAGE_1_CONFIRM = 4, | ||
| BOOT_REQUEST_ENTRY_MAX = 5, | ||
| }; | ||
|
|
||
| /* Assert that all requests will fit within the retention area. */ | ||
| BUILD_ASSERT((BOOT_REQUEST_ENTRY_METADATA_SIZE + BOOT_REQUEST_ENTRY_MAX * sizeof(uint8_t)) < | ||
| DT_REG_SIZE_BY_IDX(DT_CHOSEN(nrf_bootloader_request), 0), | ||
| "nrf,bootloader-request area is too small for bootloader request struct"); | ||
|
|
||
| enum boot_request_slot { | ||
| /** Unsupported value. */ | ||
| BOOT_REQUEST_SLOT_INVALID = 0, | ||
| /** Primary slot. */ | ||
| BOOT_REQUEST_SLOT_PRIMARY = 1, | ||
| /** Secondary slot. */ | ||
| BOOT_REQUEST_SLOT_SECONDARY = 2, | ||
| }; | ||
|
|
||
| /** Alias type for the image and number. */ | ||
| typedef uint8_t boot_request_slot_t; | ||
|
|
||
| enum boot_request_mode { | ||
| /** Execute a regular boot logic. */ | ||
| BOOT_REQUEST_MODE_REGULAR = 0, | ||
| /** Execute the recovery boot logic. */ | ||
| BOOT_REQUEST_MODE_RECOVERY = 1, | ||
| /** Execute the firmware loader logic. */ | ||
| BOOT_REQUEST_MODE_FIRMWARE_LOADER = 2, | ||
| /** Unsupported value. */ | ||
| BOOT_REQUEST_MODE_INVALID = 0xFF, | ||
| }; | ||
|
|
||
| /** Alias type for the image number. */ | ||
| typedef uint8_t boot_request_img_t; | ||
|
|
||
| /** | ||
| * @brief Find an entry for a given request. | ||
| * | ||
| * @param[in] type Type of request. | ||
| * @param[in] image Image number. Use @p BOOT_REQUEST_IMG_BOOTLOADER for generic requests. | ||
| * @param[out] entry Entry to use. | ||
| * | ||
| * @return 0 on success; nonzero on failure. | ||
| */ | ||
| static int boot_request_entry_find(enum boot_request_type type, boot_request_img_t image, | ||
| size_t *entry) | ||
| { | ||
| if (entry == NULL) { | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| switch (type) { | ||
| case BOOT_REQUEST_BOOT_MODE: | ||
| *entry = BOOT_REQUEST_ENTRY_BOOT_MODE; | ||
| break; | ||
| case BOOT_REQUEST_IMG_PREFERENCE: | ||
| switch (image) { | ||
| case 0: | ||
| *entry = BOOT_REQUEST_ENTRY_IMAGE_0_PREFERENCE; | ||
| break; | ||
| case 1: | ||
| *entry = BOOT_REQUEST_ENTRY_IMAGE_1_PREFERENCE; | ||
| break; | ||
| default: | ||
| return -EINVAL; | ||
| } | ||
| break; | ||
| case BOOT_REQUEST_IMG_CONFIRM: | ||
| switch (image) { | ||
| case 0: | ||
| *entry = BOOT_REQUEST_ENTRY_IMAGE_0_CONFIRM; | ||
| break; | ||
| case 1: | ||
| *entry = BOOT_REQUEST_ENTRY_IMAGE_1_CONFIRM; | ||
| break; | ||
| default: | ||
| return -EINVAL; | ||
| } | ||
| break; | ||
| default: | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| int boot_request_init(void) | ||
| { | ||
| return boot_request_mem_init(); | ||
| } | ||
|
|
||
| int boot_request_clear(void) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add short note what it does. |
||
| { | ||
| #ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP | ||
| size_t nv_indexes[BOOT_REQUEST_IMG_NUM]; | ||
| uint8_t image; | ||
|
|
||
| for (image = 0; image < BOOT_REQUEST_IMG_NUM; image++) { | ||
| if (boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, | ||
| &nv_indexes[image]) != 0) { | ||
| return -EINVAL; | ||
| } | ||
| } | ||
|
|
||
| return boot_request_mem_selective_erase(nv_indexes, BOOT_REQUEST_IMG_NUM); | ||
| #else | ||
| return boot_request_mem_selective_erase(NULL, 0); | ||
| #endif | ||
| } | ||
|
|
||
| int boot_request_confirm_slot(uint8_t image, enum boot_slot slot) | ||
| { | ||
| uint8_t value = BOOT_REQUEST_SLOT_INVALID; | ||
| size_t req_entry; | ||
| int ret; | ||
|
|
||
| #ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP | ||
| if (!boot_request_mem_updateable()) { | ||
| BOOT_LOG_ERR("Unable to confirm slot - area not updateable."); | ||
| /* Cannot update area if it is corrupted. */ | ||
| return -EIO; | ||
| } | ||
| #endif | ||
|
|
||
| ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry); | ||
| if (ret != 0) { | ||
| return ret; | ||
| } | ||
|
|
||
| switch (slot) { | ||
| case BOOT_SLOT_PRIMARY: | ||
| value = BOOT_REQUEST_SLOT_PRIMARY; | ||
| break; | ||
| case BOOT_SLOT_SECONDARY: | ||
| value = BOOT_REQUEST_SLOT_SECONDARY; | ||
| break; | ||
| default: | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| return boot_request_mem_write(req_entry * sizeof(value), &value); | ||
| } | ||
|
|
||
| bool boot_request_check_confirmed_slot(uint8_t image, enum boot_slot slot) | ||
| { | ||
| uint8_t value = BOOT_REQUEST_SLOT_INVALID; | ||
| size_t req_entry; | ||
| int ret; | ||
|
|
||
| ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry); | ||
| if (ret != 0) { | ||
| return false; | ||
| } | ||
|
|
||
| ret = boot_request_mem_read(req_entry * sizeof(uint8_t), &value); | ||
| if (ret != 0) { | ||
| return false; | ||
| } | ||
|
|
||
| switch (value) { | ||
| case BOOT_REQUEST_SLOT_PRIMARY: | ||
| return (slot == BOOT_SLOT_PRIMARY); | ||
| case BOOT_REQUEST_SLOT_SECONDARY: | ||
| return (slot == BOOT_SLOT_SECONDARY); | ||
| default: | ||
| break; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot) | ||
| { | ||
| uint8_t value = BOOT_REQUEST_SLOT_INVALID; | ||
| size_t req_entry; | ||
| int ret; | ||
|
|
||
| #ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP | ||
| if (!boot_request_mem_updateable()) { | ||
| BOOT_LOG_ERR("Unable to select slot - area not updateable."); | ||
| /* Cannot update area if it is corrupted. */ | ||
| return -EIO; | ||
| } | ||
| #endif | ||
|
|
||
| ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry); | ||
| if (ret != 0) { | ||
| return ret; | ||
| } | ||
|
|
||
| switch (slot) { | ||
| case BOOT_SLOT_PRIMARY: | ||
| value = BOOT_REQUEST_SLOT_PRIMARY; | ||
| break; | ||
| case BOOT_SLOT_SECONDARY: | ||
| value = BOOT_REQUEST_SLOT_SECONDARY; | ||
| break; | ||
| default: | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| return boot_request_mem_write(req_entry * sizeof(value), &value); | ||
| } | ||
|
|
||
| enum boot_slot boot_request_get_preferred_slot(uint8_t image) | ||
| { | ||
| uint8_t value = BOOT_REQUEST_SLOT_INVALID; | ||
| size_t req_entry; | ||
| int ret; | ||
|
|
||
| ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry); | ||
| if (ret != 0) { | ||
| return BOOT_SLOT_NONE; | ||
| } | ||
|
|
||
| ret = boot_request_mem_read(req_entry * sizeof(uint8_t), &value); | ||
| if (ret != 0) { | ||
| return BOOT_SLOT_NONE; | ||
| } | ||
|
|
||
| switch (value) { | ||
| case BOOT_REQUEST_SLOT_PRIMARY: | ||
| return BOOT_SLOT_PRIMARY; | ||
| case BOOT_REQUEST_SLOT_SECONDARY: | ||
| return BOOT_SLOT_SECONDARY; | ||
| default: | ||
| break; | ||
| } | ||
|
|
||
| return BOOT_SLOT_NONE; | ||
| } | ||
|
|
||
| int boot_request_enter_recovery(void) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. almost the same code as boot_request_enter_firmware_loader(). Can It be refactored using static inline function ? |
||
| { | ||
| uint8_t value = BOOT_REQUEST_MODE_RECOVERY; | ||
| size_t req_entry; | ||
| int ret; | ||
|
|
||
| #ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP | ||
| if (!boot_request_mem_updateable()) { | ||
| BOOT_LOG_ERR("Unable to enter recovery - area not updateable."); | ||
| /* Cannot update area if it is corrupted. */ | ||
| return -EIO; | ||
| } | ||
| #endif | ||
|
|
||
| ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, | ||
| &req_entry); | ||
| if (ret != 0) { | ||
| return ret; | ||
| } | ||
|
|
||
| return boot_request_mem_write(req_entry * sizeof(value), &value); | ||
| } | ||
|
|
||
| #ifdef CONFIG_NRF_BOOT_SERIAL_BOOT_REQ | ||
| bool boot_request_detect_recovery(void) | ||
| { | ||
| uint8_t value = BOOT_REQUEST_MODE_INVALID; | ||
| size_t req_entry; | ||
| int ret; | ||
|
|
||
| ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, | ||
| &req_entry); | ||
| if (ret != 0) { | ||
| return false; | ||
| } | ||
|
|
||
| ret = boot_request_mem_read(req_entry * sizeof(uint8_t), &value); | ||
| if ((ret == 0) && (value == BOOT_REQUEST_MODE_RECOVERY)) { | ||
| return true; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
| #endif /* CONFIG_NRF_BOOT_SERIAL_BOOT_REQ */ | ||
|
|
||
| int boot_request_enter_firmware_loader(void) | ||
| { | ||
| uint8_t value = BOOT_REQUEST_MODE_FIRMWARE_LOADER; | ||
| size_t req_entry; | ||
| int ret; | ||
|
|
||
| #ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST_PREFERENCE_KEEP | ||
| if (!boot_request_mem_updateable()) { | ||
| BOOT_LOG_ERR("Unable to enter FW loader - area not updateable."); | ||
| /* Cannot update area if it is corrupted. */ | ||
| return -EIO; | ||
| } | ||
| #endif | ||
|
|
||
| ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, | ||
| &req_entry); | ||
| if (ret != 0) { | ||
| return ret; | ||
| } | ||
|
|
||
| return boot_request_mem_write(req_entry * sizeof(value), &value); | ||
| } | ||
|
|
||
| #ifdef CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ | ||
| bool boot_request_detect_firmware_loader(void) | ||
| { | ||
| uint8_t value = BOOT_REQUEST_MODE_INVALID; | ||
| size_t req_entry; | ||
| int ret; | ||
|
|
||
| ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, | ||
| &req_entry); | ||
| if (ret != 0) { | ||
| return false; | ||
| } | ||
|
|
||
| ret = boot_request_mem_read(req_entry * sizeof(uint8_t), &value); | ||
| if ((ret == 0) && (value == BOOT_REQUEST_MODE_FIRMWARE_LOADER)) { | ||
| return true; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
| #endif /* CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ */ | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is uint8_t refer to any alias types you established bellow? If so, use it instead.