samples: tfm_integration: Remove psa_firmware

Removes the `psa_firmware` sample, which is based on an older version
(0.7) of the FWU service from TF-M 1.6.0. This sample needs to be
refactored to use FWU 1.0, included in TF-M 1.7.0 and future releases.

Signed-off-by: Kevin Townsend <kevin.townsend@linaro.org>
Signed-off-by: David Brown <david.brown@linaro.org>
This commit is contained in:
Kevin Townsend 2023-01-23 14:39:09 +01:00 committed by Anas Nashif
parent 2ba39d8bf1
commit a50aafd938
8 changed files with 0 additions and 4294 deletions

View file

@ -1,105 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(tfm_psa_firmware)
if (NOT CONFIG_APP_FIRMWARE_UPDATE_IMAGE)
message(FATAL_ERROR "CONFIG_APP_FIRMWARE_UPDATE_IMAGE required")
endif()
# NOTE: These must not include ${CMAKE_BINARY_DIR} otherwise you get an
# absolute path as part of the C symbols in the generated object file.
# This is difficult to use in a correct and portable way. Instead, we will
# take advantage of running everything from within the build directory.
set(UPDATE_SIGNED_HEX update-signed.hex)
set(UPDATE_BIN update-image.bin)
set(UPDATE_OBJ update-image.o)
set(UPDATE_HEADER_BIN update-header.bin)
set(UPDATE_HEADER_OBJ update-header.o)
# The following sequence of add_custom_command calls builds a dependency
# graph of all the bits we need to sign# an image. The process looks
# something like:
#
# [(1) sample.hex ]
# |
# v
# [(2) sign with imgtool ]
# |
# v
# [(3) split-header.py ]
# | |
# app | | header
# v v
# [(4,5) objdump bin to obj ]
# | |
# app obj | | header obj
# v v
# [(6) target_sources(..) ]
#
# Note that node (1) is an input.
# This is duplicated from the trusted-firmware-m CMakeLists.txt, as this
# needs it and CMAKE does not allow us to import the varibales from that
# directory.
set(TFM_MCUBOOT_DIR "${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/bl2/ext/mcuboot")
# Node (2) in the above graphic
add_custom_command(
DEPENDS ${CONFIG_APP_FIRMWARE_UPDATE_IMAGE}
OUTPUT ${UPDATE_SIGNED_HEX}
COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${ZEPHYR_MCUBOOT_MODULE_DIR}/scripts
${PYTHON_EXECUTABLE}
${TFM_MCUBOOT_DIR}/scripts/wrapper/wrapper.py
--layout "${CMAKE_BINARY_DIR}/tfm/bl2/ext/mcuboot/CMakeFiles/signing_layout_ns.dir/signing_layout_ns.o"
-k ${CONFIG_TFM_KEY_FILE_NS}
--public-key-format "full"
--align 1
-v ${CONFIG_APP_FIRMWARE_UPDATE_IMAGE_VERSION}
--pad
-s auto
-H ${CONFIG_ROM_START_OFFSET}
${CONFIG_APP_FIRMWARE_UPDATE_IMAGE}
${UPDATE_SIGNED_HEX}
)
# Node (3) in the above graphic
add_custom_command(
OUTPUT ${UPDATE_HEADER_BIN}
OUTPUT ${UPDATE_BIN}
DEPENDS ${UPDATE_SIGNED_HEX}
COMMAND ${PYTHON_EXECUTABLE}
${CMAKE_CURRENT_LIST_DIR}/split-header.py
${UPDATE_SIGNED_HEX}
${UPDATE_BIN}
${UPDATE_HEADER_BIN}
)
# Node (4) in the above graphic
add_custom_command(
OUTPUT ${UPDATE_HEADER_OBJ}
DEPENDS ${UPDATE_HEADER_BIN}
COMMAND ${CMAKE_OBJCOPY} -I binary -O elf32-littlearm -B arm
${UPDATE_HEADER_BIN}
${UPDATE_HEADER_OBJ}
)
# Node (5) in the above graphic
add_custom_command(
OUTPUT ${UPDATE_OBJ}
DEPENDS ${UPDATE_BIN}
COMMAND ${CMAKE_OBJCOPY} -I binary -O elf32-littlearm -B arm
${UPDATE_BIN}
${UPDATE_OBJ}
)
# Source files in this sample
# Node (6) in the above graphic
target_sources(app PRIVATE src/main.c ${UPDATE_OBJ} ${UPDATE_HEADER_OBJ})
target_include_directories(app PRIVATE
$<TARGET_PROPERTY:tfm,TFM_BINARY_DIR>/install/interface/include
)

View file

@ -1,27 +0,0 @@
# Private config options for PSA firmware application
# Copyright (c) 2021 Linaro
# SPDX-License-Identifier: Apache-2.0
mainmenu "PSA firmware sample application"
menu "Application configuration"
module = APP
module-str = app
source "subsys/logging/Kconfig.template.log_config"
endmenu
config APP_FIRMWARE_UPDATE_IMAGE
string "Firmware update image to update to"
help
This required option specifies the path to an image that this
exapmle will update to.
default "$(shell, dirname $(filename))/boards/hello-an547.hex" if BOARD_MPS3_AN547
config APP_FIRMWARE_UPDATE_IMAGE_VERSION
string "Version of the new image to update to"
default "0.0.2+0"
source "Kconfig.zephyr"

View file

@ -1,197 +0,0 @@
.. _tfm_psa_firmware:
TF-M PSA Firmware
#################
Overview
********
This TF-M integration example demonstrates how to use the PSA Firmware API
to retrieve information about the current firmware, or implement a custom
firmware update process.
Trusted Firmware (TF-M) Platform Security Architecture (PSA) APIs
are used for the secure processing environment, with Zephyr running in the
non-secure processing environment.
It uses **IPC Mode** for communication, where an IPC mechanism is inserted to
handle secure TF-M API calls and responses. The OS-specific code to handle
the IPC calls is in ``tfm_ipc.c``.
TF-M supports three types of firmware upgrade mechanisms:
``https://tf-m-user-guide.trustedfirmware.org/docs/technical_references/design_docs/tfm_secure_boot.html#firmware-upgrade-operation``
This example uses the overwrite firmware upgrade mechanism, in particular, it showcases
upgrading the non-secure image which can be built from any other sample in the
``zephyr/samples`` directory.
The sample prints test info to the console either as a single-thread or
multi-thread application.
Building and Running
********************
This project needs another firmware as the update payload. It must use another
example's hex file, and should be specified on the command line
as ``CONFIG_APP_FIRMWARE_UPDATE_IMAGE``.
To use the ``tfm_integration/tfm_ipc`` sample as the NS firmware update
payload, follow the instructions below:
This sample will only build on a Linux or macOS development system
(not Windows), and has been tested on the following setups:
- macOS Big Sur using QEMU 6.0.0 with gcc-arm-none-eabi-9-2020-q2-update
- Linux (NixOS) using QEMU 6.2.0 with gcc from Zephyr SDK 0.14.1
- Targets ``MPS3 AN547`` and ``NXP LPCXPRESSO55S69``
On MPS3 AN547:
===============
Build:
======
1. Build the ``tfm_ipc`` sample with the non-secure board configuration, which will
generate the firmware image we'll use in ``psa_firmware`` during the update:
.. zephyr-app-commands::
:zephyr-app: samples/tfm_integration/tfm_ipc
:host-os: unix
:board: mps3_an547_ns
:goals: build
:build-dir: build/tfm_ipc
:compact:
2. Build psa_firmware
.. zephyr-app-commands::
:zephyr-app: samples/tfm_integration/psa_firmware
:host-os: unix
:board: mps3_an547_ns
:goals: build
:build-dir: build/psa_firmware
:gen-args: -DCONFIG_APP_FIRMWARE_UPDATE_IMAGE=\"full/path/to/zephyr/build/tfm_ipc/zephyr/zephyr.hex\"
:compact:
Note:
This sample includes a pre-built firmware image (``hello-an547.hex``) in the ``boards``
directory. If you don't pass the ``CONFIG_APP_FIRMWARE_UPDATE_IMAGE`` command
line argument during step 2 (``-- -DCONFIG_APP_FIRMWARE_UPDATE_IMAGE=...``),
this sample will automatically uses the pre-built hex file.
Run in real target:
===================
1. Copy application binary files (mcuboot.bin and tfm_sign.bin) to
``<MPS3 device name>/SOFTWARE/``.
2. Edit (e.g., with vim) the ``<MPS3 device name>/MB/HBI0263C/AN547/images.txt``
file, and update it as shown below:
.. code-block:: bash
TITLE: Versatile Express Images Configuration File
[IMAGES]
TOTALIMAGES: 2 ;Number of Images (Max: 32)
IMAGE0ADDRESS: 0x10000000
IMAGE0FILE: \SOFTWARE\mcuboot.bin ; BL2 bootloader
IMAGE1ADDRESS: 0x10080000
IMAGE1FILE: \SOFTWARE\tfm_sign.bin ; TF-M with application binary blob
3. Save the file, exit the editor, and reset the MPS3 board.
Run in QEMU:
============
.. zephyr-app-commands::
:zephyr-app: samples/tfm_integration/psa_firmware
:host-os: unix
:board: mps3_an547_ns
:goals: run
:build-dir: build/psa_firmware
:gen-args: -DCONFIG_APP_FIRMWARE_UPDATE_IMAGE=\"full/path/to/zephyr/build/tfm_ipc/zephyr/zephyr.hex\"
:compact:
On LPCxpresso55S69:
===================
1. Build the ``tfm_ipc`` sample with the non-secure board configuration, which will
generate the firmware image we'll use in ``psa_firmware`` during the update:
.. zephyr-app-commands::
:zephyr-app: samples/tfm_integration/tfm_ipc
:host-os: unix
:board: lpcxpresso55s69_ns
:goals: build
:build-dir: build/tfm_ipc
:compact:
2. Build psa_firmware:
.. zephyr-app-commands::
:zephyr-app: samples/tfm_integration/psa_firmware
:host-os: unix
:board: lpcxpresso55s69_ns
:goals: build
:build-dir: build/psa_firmware
:gen-args: -DCONFIG_APP_FIRMWARE_UPDATE_IMAGE=\"full/path/to/zephyr/build/tfm_ipc/zephyr/zephyr.hex\"
:compact:
Make sure your board is set up with :ref:`lpclink2-jlink-onboard-debug-probe`,
since this isn't the debug interface boards ship with from the factory;
Next we need to manually flash the resulting image (``tfm_merged.bin``) with a
J-Link as follows:
.. code-block:: console
JLinkExe -device lpc55s69 -if swd -speed 2000 -autoconnect 1
J-Link>r
J-Link>erase
J-Link>loadfile build/tfm_merged.bin
Resetting the board and erasing it will unlock the board, this is useful in case
it's in an unknown state and can't be flashed.
We need to reset the board manually after flashing the image to run this code.
Sample Output
=============
.. code-block:: console
[INF] Beginning TF-M provisioning
[WRN] TFM_DUMMY_PROVISIONING is not suitable for production! This device is NOT SECURE
[Sec Thread] Secure image initializing!
Booting TF-M v1.6.0+8cffe127
Creating an empty ITS flash layout.
Creating an empty PS flash layout.
*** Booting Zephyr OS build zephyr-v3.1.0-3851-g2bef8051b2fc ***
PSA Firmware API test
Active S image version: 0.0.3-0
Active NS image version: 0.0.1-0
Starting FWU; Writing Firmware from 21000000 size 17802 bytes
Wrote Firmware; Writing Header from 2100458a size 16 bytes
Wrote Header; Installing Image
Installed New Firmware; Reboot Needed; Rebooting
[WRN] This device was provisioned with dummy keys. This device is NOT SECURE
[Sec Thread] Secure image initializing!
Booting TF-M v1.6.0+8cffe127
*** Booting Zephyr OS build zephyr-v3.1.0-3851-g2bef8051b2fc ***
The version of the PSA Framework API is 257.
The minor version is 1.
Connect success!
TF-M IPC on mps3_an547
Common Problems
***************
Compilation fails with ``Error: Header padding was not requested...``
=====================================================================
This error occurs when passing a signed image to ``CONFIG_APP_FIRMWARE_UPDATE_IMAGE``
on the command line, ex: ``zephyr_ns_signed.hex``.
Make sure you pass an unsigned, non-secure image (ex. ``zephyr.hex``) to ``CONFIG_APP_FIRMWARE_UPDATE_IMAGE``.

File diff suppressed because it is too large Load diff

View file

@ -1,19 +0,0 @@
CONFIG_LOG=y
CONFIG_LOG_RUNTIME_FILTERING=y
CONFIG_LOG_BUFFER_SIZE=2048
CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD=0
CONFIG_LOG_DEFAULT_LEVEL=4
CONFIG_BUILD_WITH_TFM=y
CONFIG_TFM_PROFILE_TYPE_NOT_SET=y
CONFIG_TFM_BL2=y
CONFIG_TFM_IPC=y
CONFIG_TFM_PARTITION_FIRMWARE_UPDATE=y
CONFIG_TFM_IMAGE_VERSION_S="0.0.3"
CONFIG_TFM_IMAGE_VERSION_NS="0.0.1"
# The Zephyr CMSIS emulation assumes that ticks are ms, currently
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_HEAP_MEM_POOL_SIZE=4096

View file

@ -1,35 +0,0 @@
sample:
description: This app provides an example of using the PSA Firmware calls
to update to a new firmware using TF-M and MCUBoot.
name: TF-M PSA firmware update example
tests:
sample.update-success:
tags: introduction tfm
platform_allow: mps3_an547_ns
integration_platforms:
- mps3_an547_ns
harness: console
timeout: 300
extra_configs:
- CONFIG_APP_FIRMWARE_UPDATE_IMAGE_VERSION="0.0.2+0"
harness_config:
type: multi_line
regex:
- "Active NS image version: 0.0.1-0"
- "Wrote Header; Installing Image"
- "Hello World from UserSpace!"
sample.fail-rollback:
tags: introduction tfm
platform_allow: mps3_an547_ns
integration_platforms:
- mps3_an547_ns
harness: console
timeout: 300
extra_configs:
- CONFIG_APP_FIRMWARE_UPDATE_IMAGE_VERSION="0.0.0+0"
harness_config:
type: multi_line
regex:
- "Active NS image version: 0.0.1-0"
- "Wrote Header; Installing Image"
- "Active NS image version: 0.0.1-0"

View file

@ -1,28 +0,0 @@
#!/usr/bin/env python3
#
# Copyright (c) 2022, Linaro
#
# SPDX-License-Identifier: Apache-2.0
"""
Split a hex file signed by imagetool into its binary/image and
its header. This is needed to be able to pack these two parts
into the sample separately, saving flash space.
"""
import argparse
from intelhex import IntelHex
def dump_header(infile, image, header):
inhex = IntelHex(infile)
(start, end) = inhex.segments()[0]
inhex.tobinfile(image, start=start, end=end-1)
(start, end) = inhex.segments()[-1]
inhex.tobinfile(header, start=start, end=end-1)
if __name__ == "__main__":
parser = argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument('input')
parser.add_argument('image')
parser.add_argument('header')
args = parser.parse_args()
dump_header(args.input, args.image, args.header)

View file

@ -1,269 +0,0 @@
/*
* Copyright (c) 2021 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/logging/log_ctrl.h>
#include <zephyr/logging/log.h>
#include <psa/update.h>
#include "tfm_ns_interface.h"
extern uint8_t _binary_update_image_bin_start[];
extern uint8_t _binary_update_image_bin_end;
extern uint8_t _binary_update_image_bin_size;
extern uint8_t _binary_update_header_bin_start[];
extern uint8_t _binary_update_header_bin_end;
extern uint8_t _binary_update_header_bin_size;
/*
* The _size symbol is particularly bizarre, since it's a length exposed as
* a symbol's address, not a variable
*/
const size_t update_image_size = (size_t) &_binary_update_image_bin_size;
const size_t update_header_size = (size_t) &_binary_update_header_bin_size;
/* Turns out you can't flash blocks that are not a multiple of this */
const size_t min_block_size = 512;
/** Declare a reference to the application logging interface. */
LOG_MODULE_DECLARE(app, CONFIG_LOG_DEFAULT_LEVEL);
bool fwu_query_ver_active(psa_image_id_t image_id, psa_image_info_t *info)
{
psa_status_t status;
/* Query the active image. */
status = psa_fwu_query(image_id, info);
/* Get the active image version. State can be one of: */
/* PSA_IMAGE_UNDEFINED */
/* PSA_IMAGE_CANDIDATE */
/* PSA_IMAGE_INSTALLED */
/* PSA_IMAGE_REJECTED */
/* PSA_IMAGE_PENDING_INSTALL */
/* PSA_IMAGE_REBOOT_NEEDED */
return info->state == PSA_IMAGE_INSTALLED && status == PSA_SUCCESS;
}
void fwu_disp_ver_active(void)
{
/* Image type can be one of: */
/* FWU_IMAGE_TYPE_NONSECURE */
/* FWU_IMAGE_TYPE_SECURE */
/* FWU_IMAGE_TYPE_FULL */
/* Making the call with FWU_IMAGE_TYPE_FULL will return the information */
/* for the full image, which is a combination of the secure and nonsecure */
/* images. This is related to the way images are managed in the */
/* bootloader. For example, if the secure image and the nonsecure image */
/* are combined together and then the combined image is signed and padded */
/* with some metadata to generate the final image, then the final */
/* generated image is a “full image”. This image management mode is */
/* enabled via: */
/* -DMCUBOOT_IMAGE_NUMBER=1 */
/* If this mode is enabled when building TF-M, then the application */
/* should use the “FWU_IMAGE_TYPE_FULL” type when calling the Firmware */
/* Update service. */
/* If this mode is not enabled, then the application should use the */
/* “FWU_IMAGE_TYPE_NONSECURE” or “FWU_IMAGE_TYPE_SECURE” type. */
psa_image_id_t image_id = FWU_CALCULATE_IMAGE_ID(FWU_IMAGE_ID_SLOT_ACTIVE,
FWU_IMAGE_TYPE_SECURE,
0);
psa_image_info_t info = { 0 };
bool status = fwu_query_ver_active(image_id, &info);
if (status) {
printk("Active S image version: %d.%d.%d-%d\n",
info.version.iv_major,
info.version.iv_minor,
info.version.iv_revision,
info.version.iv_build_num);
} else {
printk("\nUnable to query active secure image version!\n");
}
image_id = FWU_CALCULATE_IMAGE_ID(FWU_IMAGE_ID_SLOT_ACTIVE,
FWU_IMAGE_TYPE_NONSECURE,
0);
status = fwu_query_ver_active(image_id, &info);
if (status) {
printk("Active NS image version: %d.%d.%d-%d\n",
info.version.iv_major,
info.version.iv_minor,
info.version.iv_revision,
info.version.iv_build_num);
} else {
printk("\nUnable to query active nonsecure image version!\n");
}
}
/**
* Copy a part of a firmware update from the memory pointed to by `cur_block`,
* with `size` size, into the `image_id` partition, * at offset `offset`.
*/
void write_update_part(psa_image_id_t image_id, size_t size, size_t offset, void *cur_block)
{
size_t coppied = 0;
while (coppied < size) {
size_t next_block_size = PSA_FWU_MAX_BLOCK_SIZE;
size_t remainder = size - coppied;
if (remainder < next_block_size) {
next_block_size = remainder;
}
psa_status_t write_status = psa_fwu_write(
image_id,
coppied + offset,
&((uint8_t *)cur_block)[coppied],
next_block_size
);
switch (write_status) {
case PSA_ERROR_INVALID_ARGUMENT:
printk("FW Update failed: Invalid Argument\n");
k_oops();
break;
case PSA_ERROR_INSUFFICIENT_MEMORY:
printk("FW Update failed: Insufficient Memory\n");
k_oops();
break;
case PSA_ERROR_INSUFFICIENT_STORAGE:
printk("FW Update failed: Insufficient Storage\n");
k_oops();
break;
case PSA_ERROR_GENERIC_ERROR:
printk("FW Update failed: Generic Error\n");
k_oops();
break;
case PSA_ERROR_CURRENTLY_INSTALLING:
printk("FW Update failed: Currently Installing\n");
k_oops();
break;
default:
break;
}
if (write_status != PSA_SUCCESS) {
k_oops();
}
coppied += next_block_size;
}
}
/**
* Run a test firmware update
*/
void update_firmware(void)
{
uintptr_t size = ((update_image_size + (min_block_size - 1)) / min_block_size)
* min_block_size;
void *cur_block = &_binary_update_image_bin_start[0];
printk("Starting FWU; Writing Firmware from %lx size %5ld bytes\n",
(uintptr_t) cur_block,
(uintptr_t) update_image_size
);
psa_image_id_t image_id = FWU_CALCULATE_IMAGE_ID(FWU_IMAGE_ID_SLOT_STAGE,
FWU_IMAGE_TYPE_NONSECURE,
0);
write_update_part(image_id, size, 0, cur_block);
size_t header_offset = 0x18000 - update_header_size;
cur_block = &_binary_update_header_bin_start[0];
printk("Wrote Firmware; Writing Header from %lx size %5ld bytes\n",
(uintptr_t) cur_block,
(uintptr_t) update_header_size
);
write_update_part(image_id, update_header_size, header_offset, cur_block);
printk("Wrote Header; Installing Image\n");
psa_image_id_t uuid;
psa_image_version_t version;
psa_status_t install_stat = psa_fwu_install(image_id, &uuid, &version);
switch (install_stat) {
case PSA_SUCCESS:
case PSA_SUCCESS_REBOOT:
break;
case PSA_ERROR_INVALID_ARGUMENT:
printk("FW Update failed: Invalid Argument\n");
k_oops();
break;
case PSA_ERROR_INVALID_SIGNATURE:
printk("FW Update failed: Invalid Signature\n");
k_oops();
break;
case PSA_ERROR_GENERIC_ERROR:
printk("FW Update failed: Generic Error\n");
k_oops();
break;
case PSA_ERROR_STORAGE_FAILURE:
printk("FW Update failed: Storage Failure\n");
k_oops();
break;
case PSA_ERROR_DEPENDENCY_NEEDED:
printk(
"FW Update failed: Dependency Needed: uuid: %x version: %d.%d.%d-%d\n",
uuid,
version.iv_major,
version.iv_minor,
version.iv_revision,
version.iv_build_num
);
k_oops();
break;
}
psa_image_info_t info = { 0 };
psa_fwu_query(image_id, &info);
switch (info.state) {
case PSA_IMAGE_UNDEFINED:
printk("Installed New Firmware; Error: State UNDEFINED\n");
break;
case PSA_IMAGE_CANDIDATE:
printk("Installed New Firmware as Candidate; Rebooting\n");
break;
case PSA_IMAGE_INSTALLED:
printk("Installed New Firmware; Rebooting\n");
break;
case PSA_IMAGE_REJECTED:
printk("Installed New Firmware; Error: Rejected\n");
break;
case PSA_IMAGE_PENDING_INSTALL:
printk("Installed New Firmware pending install; Rebooting\n");
break;
case PSA_IMAGE_REBOOT_NEEDED:
printk("Installed New Firmware; Reboot Needed; Rebooting\n");
break;
}
/* Flush all logs in the deferred mode. */
while (IS_ENABLED(CONFIG_LOG_MODE_DEFERRED) && log_data_pending()) {
k_msleep(100);
}
psa_fwu_request_reboot();
}
void tfm_ns_interface_init(void);
void main(void)
{
/* Initialize the TFM NS interface */
tfm_ns_interface_init();
printk("PSA Firmware API test\n");
/* Display current firmware version. */
fwu_disp_ver_active();
update_firmware();
}