Skip to content
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

nRF5340 external-xip DFU sample #13509

Merged
merged 3 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ NFC samples
nRF5340 samples
---------------

|no_changes_yet_note|
* Added the :ref:`smp_svr_ext_xip` sample that demonstrates how to split an application that uses internal flash and Quad Serial Peripheral Interface (QSPI) flash with the Simple Management Protocol (SMP) server.

Peripheral samples
------------------
Expand Down
192 changes: 177 additions & 15 deletions modules/mcuboot/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ if (CONFIG_MCUBOOT)
endif()
endif()

if(CONFIG_XIP_SPLIT_IMAGE)
# Add MCUboot extra configuration file to disable image verification and use 3 images
add_overlay_config(
mcuboot
${ZEPHYR_NRF_MODULE_DIR}/modules/mcuboot/nrf5340_exip_image.conf
)
endif()

if(CONFIG_BOOTLOADER_MCUBOOT)
if (CONFIG_NCS_IS_VARIANT_IMAGE)
# NCS Handles everything regarding mcuboot, ensure Zephyr doesn't interfere.
Expand Down Expand Up @@ -203,6 +211,58 @@ if(CONFIG_BOOTLOADER_MCUBOOT)
)
endfunction()

function(split)
# Splits an elf image into 2 sets of hex and bin files
#
# Required arguments are:
# ELF_FILE_IN
# ELF_SECTION_NAMES
# HEX_INCLUDE_FILE_OUT
# HEX_EXCLUDE_FILE_OUT
set(oneValueArgs ELF_FILE_IN HEX_INCLUDE_FILE_OUT HEX_EXCLUDE_FILE_OUT)
set(multiValueArgs ELF_SECTION_NAMES DEPENDS)
cmake_parse_arguments(SPLIT_ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
check_arguments_required_all(split SPLIT_ARG ${oneValueArgs} ELF_SECTION_NAMES)

set(include_param)
set(exclude_param)

foreach(section_name ${SPLIT_ARG_ELF_SECTION_NAMES})
set(include_param ${include_param} -R ${section_name})
set(exclude_param ${exclude_param} -j ${section_name})
endforeach()

add_custom_command(
OUTPUT
${SPLIT_ARG_HEX_INCLUDE_FILE_OUT}

COMMAND
${CMAKE_OBJCOPY}
--output-target=ihex
${include_param}
${SPLIT_ARG_ELF_FILE_IN}
${SPLIT_ARG_HEX_INCLUDE_FILE_OUT}

DEPENDS
${SPLIT_ARG_DEPENDS}
de-nordic marked this conversation as resolved.
Show resolved Hide resolved
)

add_custom_command(
OUTPUT
${SPLIT_ARG_HEX_EXCLUDE_FILE_OUT}

COMMAND
${CMAKE_OBJCOPY}
--output-target=ihex
${exclude_param}
${SPLIT_ARG_ELF_FILE_IN}
${SPLIT_ARG_HEX_EXCLUDE_FILE_OUT}

DEPENDS
${SPLIT_ARG_DEPENDS}
)
endfunction()

if (CONFIG_BUILD_S1_VARIANT AND ("${CONFIG_S1_VARIANT_IMAGE_NAME}" STREQUAL "mcuboot"))
# Inject this configuration from parent image to mcuboot.
add_overlay_config(
Expand Down Expand Up @@ -389,6 +449,81 @@ if(CONFIG_BOOTLOADER_MCUBOOT)
set(rom_fixed)
endif()

if(CONFIG_XIP_SPLIT_IMAGE)
split(
ELF_FILE_IN ${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}
ELF_SECTION_NAMES ".extflash_text_reloc;.extflash_rodata_reloc"
HEX_INCLUDE_FILE_OUT ${PROJECT_BINARY_DIR}/internal_flash.hex
HEX_EXCLUDE_FILE_OUT ${PROJECT_BINARY_DIR}/qspi_flash.hex
DEPENDS ${app_sign_depends} ${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}
)

add_custom_target(mcuboot_split_target
DEPENDS
${PROJECT_BINARY_DIR}/internal_flash.hex
${PROJECT_BINARY_DIR}/qspi_flash.hex
)

sign(
SIGNED_BIN_FILE_IN ${PROJECT_BINARY_DIR}/internal_flash.hex
SIGNED_HEX_FILE_NAME_PREFIX ${PROJECT_BINARY_DIR}/internal_flash
SLOT_SIZE $<TARGET_PROPERTY:partition_manager,PM_MCUBOOT_PRIMARY_SIZE>
SIGNED_HEX_FILE_OUT internal_flash_signed_hex
SIGNED_BIN_FILE_OUT internal_flash_signed_bin
${sign_dependencies}
${rom_fixed}
DEPENDS ${app_sign_depends} mcuboot_split_target
)

sign(
SIGNED_BIN_FILE_IN ${PROJECT_BINARY_DIR}/qspi_flash.hex
SIGNED_HEX_FILE_NAME_PREFIX ${PROJECT_BINARY_DIR}/qspi_flash
SLOT_SIZE $<TARGET_PROPERTY:partition_manager,PM_MCUBOOT_PRIMARY_SIZE>
SIGNED_HEX_FILE_OUT qspi_flash_signed_hex
SIGNED_BIN_FILE_OUT qspi_flash_signed_bin
${sign_dependencies}
${rom_fixed}
DEPENDS ${app_sign_depends} mcuboot_split_target
)

add_custom_target(mcuboot_sign_target
DEPENDS
${internal_flash_signed_hex}
${internal_flash_signed_bin}
${qspi_flash_signed_hex}
${qspi_flash_signed_bin}
)

# When signing split images then we must inform partition manager that it
# now has to use both images as mcuboot primary app.
set_property(GLOBAL PROPERTY
mcuboot_primary_app_PM_HEX_FILE
${qspi_flash_signed_hex}
${internal_flash_signed_hex}
)
set_property(GLOBAL PROPERTY
mcuboot_primary_app_PM_TARGET
mcuboot_sign_target
)

set(generate_bin_app_files
${PROJECT_BINARY_DIR}/internal_flash_update.bin
${PROJECT_BINARY_DIR}/qspi_flash_update.bin
)

set(generate_script_app_params
"internal_flash_update.binload_address=$<TARGET_PROPERTY:partition_manager,PM_APP_ADDRESS>"
"internal_flash_update.binimage_index=0"
"internal_flash_update.binslot_index_primary=1"
"internal_flash_update.binslot_index_secondary=2"
"internal_flash_update.binversion_MCUBOOT=${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION}"
"qspi_flash_update.binload_address=$<TARGET_PROPERTY:partition_manager,PM_APP_ADDRESS>"
"qspi_flash_update.binimage_index=2"
"qspi_flash_update.binslot_index_primary=5"
"qspi_flash_update.binslot_index_secondary=6"
"qspi_flash_update.binversion_MCUBOOT=${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION}"
)
else()
sign(
SIGNED_BIN_FILE_IN ${app_to_sign_hex}
SIGNED_HEX_FILE_NAME_PREFIX ${PROJECT_BINARY_DIR}/app
Expand All @@ -415,6 +550,11 @@ if(CONFIG_BOOTLOADER_MCUBOOT)
mcuboot_sign_target
)

set(generate_bin_app_files
${PROJECT_BINARY_DIR}/${app_core_binary_name}
)
endif()

if (CONFIG_BOOT_BUILD_DIRECT_XIP_VARIANT)
get_shared(mcuboot_secondary_app_bin_dir IMAGE mcuboot_secondary_app PROPERTY ZEPHYR_BINARY_DIR)
set(mcuboot_secondary_app_hex ${mcuboot_secondary_app_bin_dir}/zephyr.hex)
Expand Down Expand Up @@ -506,15 +646,22 @@ if(CONFIG_BOOTLOADER_MCUBOOT)
get_shared(net_core_version IMAGE net_core PROPERTY VERSION)

set(generate_bin_files
${PROJECT_BINARY_DIR}/${app_core_binary_name}
${generate_bin_app_files}
${PROJECT_BINARY_DIR}/${net_core_binary_name}
)

if(NOT CONFIG_XIP_SPLIT_IMAGE)
set(generate_script_app_params
"${app_core_binary_name}load_address=$<TARGET_PROPERTY:partition_manager,PM_APP_ADDRESS>"
"${app_core_binary_name}image_index=0"
"${app_core_binary_name}slot_index_primary=1"
"${app_core_binary_name}slot_index_secondary=2"
"${app_core_binary_name}version_MCUBOOT=${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION}"
)
endif()

set(generate_script_params
"${app_core_binary_name}load_address=$<TARGET_PROPERTY:partition_manager,PM_APP_ADDRESS>"
"${app_core_binary_name}image_index=0"
"${app_core_binary_name}slot_index_primary=1"
"${app_core_binary_name}slot_index_secondary=2"
"${app_core_binary_name}version_MCUBOOT=${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION}"
${generate_script_app_params}
"${net_core_binary_name}image_index=1"
"${net_core_binary_name}slot_index_primary=3"
"${net_core_binary_name}slot_index_secondary=4"
Expand All @@ -526,27 +673,37 @@ if(CONFIG_BOOTLOADER_MCUBOOT)
else()
# No network core update
if(CONFIG_BOOT_BUILD_DIRECT_XIP_VARIANT)
if(CONFIG_XIP_SPLIT_IMAGE)
message(FATAL_ERROR "This build configuration is not supported:
CONFIG_BOOT_BUILD_DIRECT_XIP_VARIANT cannot be used with CONFIG_XIP_SPLIT_IMAGE.")
endif()

set(secondary_app_core_binary_name mcuboot_secondary_app_update.bin)
set(generate_bin_files
${PROJECT_BINARY_DIR}/${app_core_binary_name}
${generate_bin_app_files}
${PROJECT_BINARY_DIR}/${secondary_app_core_binary_name}
)
)
set(generate_script_params
"${app_core_binary_name}load_address=$<TARGET_PROPERTY:partition_manager,PM_MCUBOOT_PRIMARY_APP_ADDRESS>"
"${app_core_binary_name}version_MCUBOOT+XIP=${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION}"
"${app_core_binary_name}slot=0"
"${secondary_app_core_binary_name}load_address=$<TARGET_PROPERTY:partition_manager,PM_MCUBOOT_SECONDARY_APP_ADDRESS>"
"${secondary_app_core_binary_name}version_MCUBOOT+XIP=${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION}"
"${secondary_app_core_binary_name}slot=1"
)
)
else()
set(generate_bin_files
${PROJECT_BINARY_DIR}/${app_core_binary_name}
)
set(generate_script_params
"load_address=$<TARGET_PROPERTY:partition_manager,PM_APP_ADDRESS>"
"version_MCUBOOT=${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION}"
${generate_bin_app_files}
)

if(NOT CONFIG_XIP_SPLIT_IMAGE)
set(generate_script_params
"load_address=$<TARGET_PROPERTY:partition_manager,PM_APP_ADDRESS>"
"version_MCUBOOT=${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION}"
)
else()
set(generate_script_params ${generate_script_app_params})
endif()
endif()
endif()

Expand All @@ -555,7 +712,7 @@ if(CONFIG_BOOTLOADER_MCUBOOT)
BIN_FILES ${generate_bin_files}
TYPE application
SCRIPT_PARAMS ${generate_script_params}
)
)

if (CONFIG_BUILD_S1_VARIANT AND ("${CONFIG_S1_VARIANT_IMAGE_NAME}" STREQUAL "mcuboot"))
# Secure Boot (B0) is enabled, and we have to build update candidates
Expand Down Expand Up @@ -643,6 +800,11 @@ if (CONFIG_DFU_MULTI_IMAGE_PACKAGE_BUILD)
set(dfu_multi_image_paths)
set(dfu_multi_image_targets)

if(CONFIG_XIP_SPLIT_IMAGE)
message(FATAL_ERROR "This build configuration is not supported:
CONFIG_DFU_MULTI_IMAGE_PACKAGE_BUILD cannot be used with CONFIG_XIP_SPLIT_IMAGE.")
endif()

if (CONFIG_DFU_MULTI_IMAGE_PACKAGE_APP)
list(APPEND dfu_multi_image_ids 0)
list(APPEND dfu_multi_image_paths "${PROJECT_BINARY_DIR}/${app_core_binary_name}")
Expand Down
10 changes: 10 additions & 0 deletions modules/mcuboot/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,13 @@ config MCUBOOT_USE_ALL_AVAILABLE_RAM
RAM partition.

endmenu

config XIP_SPLIT_IMAGE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a note in the readme that explains what the purpose of this extra config. I think it is important to explain that this config is not a global one and won't work outside the sample. I also think it is important to explain to the user that there is custom code (cmake, linker script, and partition manager configuration) in the sample.

bool "Split XIP image"
depends on SOC_NRF5340_CPUAPP
depends on !MCUBOOT
help
Allows for an image to be split into 2 parts where there is code executing from internal
flash and code from QSPI via XIP. Requires specific project setup for projects to use
this feature: project's cmake which supports code dispatching, linker script for describe QSPI
linking area and dedicated partition manager configuration.
38 changes: 38 additions & 0 deletions modules/mcuboot/nrf5340_exip_image.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#
# Copyright (c) 2023 Nordic Semiconductor ASA
#

# Disable image verification for MCUboot and set to 3 images
CONFIG_MCUBOOT_VERIFY_IMG_ADDRESS=n
CONFIG_UPDATEABLE_IMAGE_NUMBER=3

# Flash
CONFIG_FLASH=y
CONFIG_BOOT_ERASE_PROGRESSIVELY=y
CONFIG_SOC_FLASH_NRF_EMULATE_ONE_BYTE_WRITE_ACCESS=y
CONFIG_FPROTECT=y
CONFIG_BOOT_MAX_IMG_SECTORS=512

# Required by QSPI
CONFIG_NORDIC_QSPI_NOR=y
CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16
CONFIG_MULTITHREADING=y

# Decrease memory footprint
CONFIG_CBPRINTF_NANO=y
CONFIG_RESET_ON_FATAL_ERROR=n

# The following configurations are required to support simultaneous multi image update
CONFIG_PCD_APP=y
CONFIG_BOOT_UPGRADE_ONLY=y

# The network core cannot access external flash directly. The flash simulator must be used to
# provide a memory region that is used to forward the new firmware to the network core.
CONFIG_FLASH_SIMULATOR=y
CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y
CONFIG_FLASH_SIMULATOR_STATS=n

# Enable custom command to erase settings partition.
CONFIG_ENABLE_MGMT_PERUSER=y
CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE=y
26 changes: 26 additions & 0 deletions samples/nrf5340/extxip_smp_svr/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

project(smp_svr_ext_xip)

# This project uses orginal sdk-zephyr C source code
target_sources(app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src/main.c)
target_sources_ifdef(CONFIG_MCUMGR_TRANSPORT_BT app PRIVATE $ENV{ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c)

# This places the application bluetooth.c file and some MCUmgr libraries into QSPI XIP
zephyr_code_relocate(FILES $ENV{ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c LOCATION EXTFLASH_TEXT NOCOPY)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__mgmt LOCATION EXTFLASH_TEXT NOCOPY)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__transport LOCATION EXTFLASH_TEXT NOCOPY)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__util LOCATION EXTFLASH_TEXT NOCOPY)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__smp LOCATION EXTFLASH_TEXT NOCOPY)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__grp__img_mgmt LOCATION EXTFLASH_TEXT NOCOPY)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__grp__os_mgmt LOCATION EXTFLASH_TEXT NOCOPY)

zephyr_code_relocate(FILES $ENV{ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c LOCATION RAM_DATA)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__mgmt LOCATION RAM_DATA)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__transport LOCATION RAM_DATA)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__util LOCATION RAM_DATA)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__smp LOCATION RAM_DATA)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__grp__img_mgmt LOCATION RAM_DATA)
zephyr_code_relocate(LIBRARY subsys__mgmt__mcumgr__grp__os_mgmt LOCATION RAM_DATA)
Loading
Loading