Compare commits

..
22 Commits
Author SHA1 Message Date
Jon Mason 673e8d7c5d arm/uefi-secureboot: fix race with secureboot keys
gen-sbkeys creates and installs the secure boot signing keys, certificates,
and database used by U-Boot and systemd-boot.  Both recipes require these
files during do_compile, but there was no dependency ensuring that
gen-sbkeys:do_install completed first.

Add an explicit do_compile dependency on gen-sbkeys:do_install for both
U-Boot and systemd-boot to prevent the race, which was causing intermittent
CI failures.

The uki.bbclass also requires the secure boot keys and certificates, but
depends on systemd-boot:do_deploy, which ensures the keys are available before
they are needed.

Issues being tracked in meta-secure-core
https://github.com/Wind-River/meta-secure-core/issues/145
https://github.com/Wind-River/meta-secure-core/issues/146

Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-09-16 15:40:08 -04:00
Jon Mason 9dab8bdd49 arm/scp-firmware: add CVE_PRODUCT
Per https://nvd.nist.gov/products/cpe/detail/593B1385-F4BE-452B-AE3B-51627F6CAE45
add CVE_PRODUCT entry.  Since there wasn't one existing, there is no
need to remove anything.

(cherry picked from commit 9aaee17adb)

Signed-off-by: Javier Tia <javier@peridio.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-09-02 19:00:18 -04:00
Jon Mason 19d96baf78 arm/trusted-firmware-m: add CVE_PRODUCT
Per https://nvd.nist.gov/products/cpe/detail/C0F7CF14-9ACD-42C5-A1F8-839937F8C4DC
add CVE_PRODUCT entry.  Since there wasn't one existing, there is no
need to remove anything.

(cherry picked from commit d0b93e582c)

Signed-off-by: Javier Tia <javier@peridio.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-09-02 19:00:18 -04:00
Jon Mason 6049c06156 arm/trusted-firmware-a: modify CVE_PRODUCT
Per https://nvd.nist.gov/products/cpe/detail/2E1BD3E8-DF65-42E3-A0BA-747137D6DEF2
Adding "trustedfirmware:trusted_firmware-a"

We can probably remove "arm:trusted_firmware-a", since it has been
depreciated.  Fearing unintended issues, leaving it in for now.

(cherry picked from commit e2e63f20b5)

Signed-off-by: Javier Tia <javier@peridio.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-09-02 19:00:18 -04:00
Jon Mason f3567691f7 arm/optee: modify CVE_PRODUCT
Per https://nvd.nist.gov/products/cpe/detail/EB42962B-24FD-4716-B3E2-69F3258A57CF
adding "trustedfirmware:op-tee"

We can probably remove "linaro:op-tee", since it has been depreciated.
Fearing unintended issues, leaving it in for now.

(cherry picked from commit 81f5a92193)

Signed-off-by: Javier Tia <javier@peridio.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-09-02 19:00:18 -04:00
Jon Mason 0979b80429 arm-bsp/firmware-image-juno: remove dependency on Linaro firmware archive
The Juno firmware recipe currently depends on the
juno-latest-oe-uboot.zip archive hosted on Linaro. That archive is no
longer available, making the recipe impossible to build from scratch.

Replace the archive dependency with the individual firmware files
required to recreate the original directory layout. The recipe now
assembles the firmware tree during do_install(), generating the small
board-specific differences where appropriate.

The original archive contained duplicate copies of mbb_v151.ebf,
io_b118.bit, and tapid.arm under the HBI0262B/C/D directories. The only
meaningful differences between those directories are the PMS firmware
filename and references to it, so the recipe generates the board-specific
files with sed rather than storing duplicate copies.

Similarly, the SITE1 images.txt files only differ in the referenced DTB,
so those are generated from a common template.

Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-07-27 11:30:16 -04:00
Harsimran Singh Tungal caa36c53f7 ci: enable testimage coverage for Corstone-1000 A320 FVP
Update the Corstone-1000 A320 FVP CI matrix to run testimage jobs.

This enables testimage coverage for both the firmware-only and no-firmware
entries.

Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-06-30 09:00:17 -04:00
Harsimran Singh Tungal bcc633b8ce fvp:corstone1000-a320: update Corstone-1000 A320 FVP to 11.31
Update the Corstone-1000 with Cortex-A320 FVP recipe to use the
11.31.cs1000_a320_2 release from Arm Developer.

Switch the source URL to the new package layout, add the architecture-specific
download tokens, and update the x86_64 and aarch64 SHA256 checksums.

The new package extracts directly into the FVP install directory, so update the
install step and license paths accordingly.

Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-06-30 09:00:17 -04:00
Harsimran Singh Tungal 9488c75a67 corstone1000: Pin layers SHA for wrynose release
Pinned layers in corstone1000-base.yml

Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-06-30 09:00:17 -04:00
Harsimran Singh Tungal 2c9968a29c arm-bsp/documentation: corstone1000-a320: update 2026.05 wrynose release documentation
Update the Corstone-1000 with Cortex-A320 changelog, release notes,
user guide, tests documentation and metadata for the 2026.05 release.

Add the new 2026.05 changelog entry for the Corstone-1000 with
Cortex-A320 specific updates and align the component version tables and
Yocto distribution component versions with the current release content.

Refresh the user guide and tests documentation to align with the
2026.05 release state, including release tag references, recipe version
references, report links

Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-06-30 09:00:17 -04:00
Harsimran Singh Tungal 80129934a6 arm-bsp/documentation: corstone1000: update 2026.05 wrynose release documentation
Update the Corstone-1000 changelog, release notes and user guide for
the 2026.05 wrynose release.

Add the new 2026.05 changelog entry and capture the main release work,
including the component upgrades, TF-M GPT and PSA FWU changes, and the
updated SSH-enabled build flow.
Refresh the component version tables and Yocto distribution component
versions in changelog for the new release.

Update the user guide to align with the 2026.05 release branch and
documentation state, including the Yocto release name, recipe version
references, release tag references, and related asset and report links.

Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-06-30 09:00:17 -04:00
Ross Burton 01c33e4946 CI: add option to control whether warnings should be fatal or not
Warnings being always fatal is quite anti-social because sometimes there
are temporary warnings that we don't want to break the CI.

Signed-off-by: Ross Burton <ross.burton@arm.com>
2026-06-22 10:50:52 +01:00
Ross Burton 61fd528759 CI: use a single multiline script statement in .build
No change to the script, just formatting.

Signed-off-by: Ross Burton <ross.burton@arm.com>
2026-06-22 10:50:48 +01:00
Ross Burton 7d7f1fa63f CI: default CACHE_DIR to CI_PROJECT_DIR
Set the default cache directory to be the build tree so we don't assume
anything about the runner environment by default.

After this change, runners that don't set CACHE_DIR will need to set it
explicltly in their variables.

Signed-off-by: Ross Burton <ross.burton@arm.com>
2026-06-22 10:50:44 +01:00
Ross Burton bb4b6a9f7f CI: remove cve.yml and NVDCVE_API_KEY
This yml fragment wasn't actually used by our CI, and the cve-check class
no longer exists.

Signed-off-by: Ross Burton <ross.burton@arm.com>
2026-06-22 10:50:37 +01:00
Michael Safwat d3b55902fb arm-bsp/docs: corstone1000-a320: Add standalone A320 documentation
Add a separate Corstone-1000 Armv9-A Edge-AI documentation
set for the Cortex-A320 platform.

Populate the new documentation tree with the initial index,
user guide, software architecture, release notes, change log,
and supporting images.

Keep common Corstone-1000 material in the existing documentation
set and move A320-specific content into the new standalone
document set.

Signed-off-by: Michael Safwat <michael.safwat@arm.com>
Signed-off-by: Lisa Durbin <lisa.durbin@arm.com>
Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Hugues KAMBA MPIANA <hugues.kambampiana@arm.com>
2026-05-28 09:51:15 -04:00
Michael Safwat 31dd0e8a89 arm-bsp/docs: corstone1000: Drop A320 content from base documentation
Remove Cortex-A320-specific content from the base Corstone-1000
documentation.

Drop the A320-only sections, commands, notes, and subsystem image from
the shared Corstone-1000 software architecture and user guide now that
the platform is documented in its own standalone document set.

Signed-off-by: Michael Safwat <michael.safwat@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-05-18 15:00:18 -04:00
Hugues KAMBA MPIANA d73bc7bea7 ci: Add Corstone-1000 with Cortex-A320 builds
Add CI coverage for the Corstone-1000 with Cortex-A320 FVP machine.

Build the Corstone-1000 with Cortex-A320 FVP with the firmware-only
configuration and run both `none` and `tftf`.
Also run `none` for the no-firmware build.

Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Hugues KAMBA MPIANA <hugues.kambampiana@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-05-18 15:00:18 -04:00
Alex Chapman 9b00ce191c arm-bsp:corstone1000: Create a standalone corstone1000-a320-fvp machine
Add `corstone1000-a320-fvp` as a dedicated machine instead of enabling
the Cortex-A320 variant through a kas overlay on `corstone1000-fvp`.

Move the A320-specific machine features, overrides, FVP executable
selection, and Ethos-U85 configuration into the new machine
configuration. Keep the generic `corstone1000-fvp` machine focused on
the base FVP platform.

Update the A320 kas to use `corstone1000-a320-fvp` directly, and
allow pregenerated SSH host keys for the new virtual machine.

Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Hugues KAMBA MPIANA <hugues.kambampiana@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-05-18 15:00:18 -04:00
Alex Chapman cd1a545618 arm-bsp/docs,kas:corstone1000: Add SSH image build support
Add a shared Corstone-1000 kas configuration for building SSH-enabled
mass storage images across the supported Corstone-1000 machines.

Enable Dropbear SSH in the mass storage OS image, add pregenerated SSH
host keys for FVP builds, and document the SSH image build flow in the
user guides.

SSH support is too large for the flash OS image, so provide a dedicated
`core-image-minimal` kas configuration for SSH-enabled mass storage
images instead.

Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Hugues KAMBA MPIANA <hugues.kambampiana@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-05-18 15:00:18 -04:00
Alex Chapman b58ffc3a09 arm-bsp/tf-a: corstone1000: Fix Cortex-A320 errata override
Fix the Corstone-1000 with Cortex-A320 override for the
Trusted Firmware-A errata list.
The override was misspelled as
`ENABLE_CORTEX_A35_ERRATA:cortexta320` instead of
`ENABLE_CORTEX_A35_ERRATA:cortexa320`.

Rename the list to `ENABLE_CORTEX_A_ERRATA`, since it is shared by
the Cortex-A35 and Cortex-A320 variants.

Signed-off-by: Alex Chapman <alex.chapman@arm.com>
Signed-off-by: Hugues KAMBA MPIANA <hugues.kambampiana@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-05-18 15:00:18 -04:00
Jon Mason 052c2cf333 CI: use wrynose branches
Signed-off-by: Jon Mason <jon.mason@arm.com>
2026-04-29 11:26:18 -04:00
235 changed files with 21311 additions and 4242 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
image: ${MIRROR_GHCR}/siemens/kas/kas:5.2
image: ${MIRROR_GHCR}/siemens/kas/kas:4.7
variables:
# These are needed as the k8s executor doesn't respect the container
+2 -1
View File
@@ -7,11 +7,12 @@ distro: poky
defaults:
repos:
branch: master
branch: wrynose
repos:
bitbake:
url: https://git.openembedded.org/bitbake
branch: "2.18"
layers:
bitbake: disabled
+3 -4
View File
@@ -5,7 +5,6 @@ header:
local_conf_header:
latest_revisions: |
PREFERRED_VERSION_trusted-firmware-a ?= "2.14.%"
PREFERRED_VERSION_tf-a-tests ?= "2.14.%"
PREFERRED_VERSION_trusted-firmware-m ?= "2.2.%"
PREFERRED_VERSION_trusted-firmware-m-scripts-native ?= "2.2.%"
PREFERRED_VERSION_trusted-firmware-a ?= "2.10.%"
PREFERRED_VERSION_tf-a-tests ?= "2.10.%"
PREFERRED_VERSION_trusted-firmware-m ?= "2.1.%"
+5
View File
@@ -6,6 +6,11 @@ header:
- ci/base.yml
- ci/meta-openembedded.yml
local_conf_header:
version_for_ci: |
# For better CI coverage, use the LTS version of tf-m
PREFERRED_VERSION_trusted-firmware-m ?= "2.1.%"
machine: musca-b1
target:
-5
View File
@@ -6,11 +6,6 @@ header:
- ci/base.yml
- ci/meta-openembedded.yml
local_conf_header:
version_for_ci: |
# For better CI coverage, use the LTS version of tf-m
PREFERRED_VERSION_trusted-firmware-m ?= "2.2.%"
machine: musca-s1
target:
+3 -1
View File
@@ -5,5 +5,7 @@ header:
local_conf_header:
sstate_mirror: |
BB_HASHSERVE_UPSTREAM = "wss://hashserv.yoctoproject.org/ws"
SSTATE_MIRRORS = "file://.* http://sstate.yoctoproject.org/all/PATH;downloadfilename=PATH"
BB_HASHSERVE = "auto"
BB_SIGNATURE_HANDLER = "OEEquivHash"
OE_FRAGMENTS += "core/yocto/sstate-mirror-cdn"
+7 -3
View File
@@ -5,21 +5,25 @@ distro: poky
defaults:
repos:
branch: master
branch: wrynose
repos:
bitbake:
url: https://git.openembedded.org/bitbake
branch: "2.18"
commit: 22021758e66737bcf68dfd2b74adc6a0cb1d42d9
layers:
bitbake: disabled
core:
url: https://git.openembedded.org/openembedded-core
commit: 06dd66e6220e5ce4ed4b9af4d8231ae5f0a8ce80
layers:
meta:
meta-yocto:
url: https://git.yoctoproject.org/meta-yocto
commit: 8251bdad5fda780a000fb41e6eda82eadf0fa39e
layers:
meta-poky:
@@ -31,7 +35,7 @@ repos:
meta-openembedded:
url: https://git.openembedded.org/meta-openembedded
# commit: 461d85a1831318747af5abe86da193bcde3fd9b4
commit: 9af4488d46cb4fd4c0d2d64820c86225ebd6ac71
layers:
meta-oe:
meta-python:
@@ -39,7 +43,7 @@ repos:
meta-secure-core:
url: https://github.com/wind-river/meta-secure-core.git
# commit: 59d7e90542947c342098863b9998693ac79352b0
commit: 07a99ae241acd488a2feda1ededf87dc70dfde80
layers:
meta-secure-core-common:
meta-signing-key:
+1 -1
View File
@@ -9,7 +9,7 @@ BBFILE_COLLECTIONS += "meta-arm-bsp"
BBFILE_PATTERN_meta-arm-bsp = "^${LAYERDIR}/"
BBFILE_PRIORITY_meta-arm-bsp = "5"
LAYERSERIES_COMPAT_meta-arm-bsp = "blacksail"
LAYERSERIES_COMPAT_meta-arm-bsp = "wrynose"
LAYERDEPENDS_meta-arm-bsp = "core meta-arm"
# This won't be used by layerindex-fetch, but works everywhere else
@@ -60,7 +60,7 @@ FVP_CONFIG[board.msd_mmc.diagnostics] ?= "0"
FVP_CONFIG[board.msd_mmc.p_max_block_count] ?= "0xFFFF"
FVP_CONFIG[board.msd_config.pl180_fifo_depth] ?= "16"
FVP_CONFIG[board.msd_mmc.support_unpadded_images] ?= "true"
FVP_CONFIG[board.msd_mmc.p_mmc_file] ?= "${IMAGE_LINK_NAME}.wic"
FVP_CONFIG[board.msd_mmc.p_mmc_file] ?= "${IMAGE_NAME}.wic"
# MMC2 card configuration
FVP_CONFIG[board.msd_mmc_2.card_type] ?= "SDHC"
+1 -1
View File
@@ -60,7 +60,7 @@ FVP_CONFIG[cluster0.stage12_tlb_size] ?= "1024"
FVP_CONFIG[cluster1.stage12_tlb_size] ?= "1024"
FVP_CONFIG[bp.secureflashloader.fname] ?= "trusted-firmware-a/bl1.bin"
FVP_CONFIG[bp.flashloader0.fname] ?= "trusted-firmware-a/fip.bin"
FVP_CONFIG[bp.virtioblockdevice.image_path] ?= "${IMAGE_LINK_NAME}.wic"
FVP_CONFIG[bp.virtioblockdevice.image_path] ?= "${IMAGE_NAME}.wic"
# FVP Base default is 8.0, so there is no has_arm_v8-0 for it. However, this is needed for every version after. So set this accordingly
FVP_EXTRA_ARGS = "--parameter cluster0.has_arm_v${ARM_ISA_MAJOR}-${ARM_ISA_MINOR}=1 --parameter cluster1.has_arm_v${ARM_ISA_MAJOR}-${ARM_ISA_MINOR}=1"
@@ -5,8 +5,7 @@ require ${TUNE_FILE}
MACHINEOVERRIDES =. "corstone1000:"
# TF-M
PREFERRED_VERSION_trusted-firmware-m ?= "2.3.%"
PREFERRED_VERSION_trusted-firmware-m-scripts-native ?= "2.3.%"
PREFERRED_VERSION_trusted-firmware-m ?= "2.2.%"
# TF-A
TFA_PLATFORM = "corstone1000"
@@ -17,8 +16,8 @@ TFA_BL2_BINARY = "bl2-corstone1000.bin"
TFA_FIP_BINARY = "fip-corstone1000.bin"
# optee
PREFERRED_VERSION_optee-os ?= "4.10.%"
PREFERRED_VERSION_optee-client ?= "4.10.%"
PREFERRED_VERSION_optee-os ?= "4.9.%"
PREFERRED_VERSION_optee-client ?= "4.9.%"
# Trusted Services
TS_PLATFORM = "arm/corstone1000"
@@ -27,7 +26,7 @@ TS_SP_SE_PROXY_CONFIG = "corstone1000"
MACHINE_FEATURES += "ts-smm-gateway ts-se-proxy"
# U-Boot
PREFERRED_VERSION_u-boot ?= "2026.07"
PREFERRED_VERSION_u-boot ?= "2025.10"
MACHINE_FEATURES += "efi"
EFI_PROVIDER ?= "grub-efi"
+1 -6
View File
@@ -49,15 +49,10 @@ FVP_CONFIG[board.dram_size] ?= "0x200000000"
FVP_CONFIG[board.virtio_net.enabled] ?= "1"
FVP_CONFIG[board.virtio_net.hostbridge.userNetworking] ?= "1"
FVP_CONFIG[board.virtio_net.hostbridge.userNetPorts] = "2222=22"
FVP_CONFIG[board.virtioblockdevice.image_path] ?= "${IMAGE_LINK_NAME}.wic"
FVP_CONFIG[board.virtioblockdevice.image_path] ?= "${IMAGE_NAME}.wic"
FVP_CONSOLES[default] = "terminal_ns_uart_ap"
FVP_TERMINALS[css.scp.terminal_uart_scp] ?= "SCP Console"
FVP_TERMINALS[css.mcp.terminal_uart_mcp] ?= "MCP Console"
FVP_TERMINALS[css.terminal_ns_uart_ap] ?= "NS Console"
FVP_TERMINALS[css.terminal_s_uart_ap] ?= "S Console"
# Seeing intermittent test timeout errors in CI where the boot is almost
# complete. Lengthen the timeout to allow for more opportunity to
# complete successfully.
TEST_FVP_LINUX_BOOT_TIMEOUT = "900"
+1 -6
View File
@@ -51,15 +51,10 @@ FVP_CONFIG[board.dram_size] ?= "0x200000000"
FVP_CONFIG[board.virtio_net.enabled] ?= "1"
FVP_CONFIG[board.virtio_net.hostbridge.userNetworking] ?= "1"
FVP_CONFIG[board.virtio_net.hostbridge.userNetPorts] = "2222=22"
FVP_CONFIG[board.virtioblockdevice.image_path] ?= "${IMAGE_LINK_NAME}.wic"
FVP_CONFIG[board.virtioblockdevice.image_path] ?= "${IMAGE_NAME}.wic"
FVP_CONSOLES[default] = "terminal_ns_uart_ap"
FVP_TERMINALS[css.scp.terminal_uart_scp] ?= "SCP Console"
FVP_TERMINALS[css.mcp.terminal_uart_mcp] ?= "MCP Console"
FVP_TERMINALS[css.terminal_ns_uart_ap] ?= "NS Console"
FVP_TERMINALS[css.terminal_s_uart_ap] ?= "S Console"
# Seeing intermittent test timeout errors in CI where the boot is almost
# complete. Lengthen the timeout to allow for more opportunity to
# complete successfully.
TEST_FVP_LINUX_BOOT_TIMEOUT = "900"
-2
View File
@@ -26,8 +26,6 @@ EFI_PROVIDER ?= "${@bb.utils.contains("DISTRO_FEATURES", "systemd", "systemd-boo
SERIAL_CONSOLES ?= "115200;ttyAMA0 115200;hvc0"
EXTRA_IMAGEDEPENDS += "edk2-firmware"
#FIXME - in 2.15.0, new logic for pen hold the SMP cores was added, which breaks this platform. Hold this back until it can be resolved.
PREFERRED_VERSION_trusted-firmware-a ?= "2.14.%"
QB_SYSTEM_NAME = "qemu-system-aarch64"
QB_MACHINE = "-machine sbsa-ref"
@@ -192,11 +192,20 @@ The following payloads can be individually updated:
### Generate capsules {.reference}
Capsules are generated by running the `image_uefi_capsule` task for
`corstone1000-flash-firmware-image`. The task uses EDK II's `GenerateCapsule`
tool and creates the capsule metadata JSON automatically from the recipe settings.
[EDK II's]($edk2_repository) `GenerateCapsule` tool is used to generate capsules and is built automatically
for the host machine during the firmware image building process.
The tool can be found at `${WORKSPACE}/build/tmp/sysroots-components/aarch64/edk2-basetools-native/usr/bin/edk2-BaseTools/BinWrappers/PosixLike/GenerateCapsule`.
The capsule's default metadata can be found in the `${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/images/corstone1000-flash-firmware-image.bb`
:::note
The `aarch64` part of this path depends on the build host architecture
and can be different on another host.
:::
A JSON file containing metadata about the capsule payloads needs to be created using the script
found at `${WORKSPACE}/meta-arm/meta-arm/scripts/generate_capsule_json_multiple.py`.
This JSON file is required by EDK II's `GenerateCapsule` tool to generate the capsule.
The capsule's default metadata passed can be found in the `${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/images/corstone1000-flash-firmware-image.bb`
and `${WORKSPACE}/meta-arm/kas/corstone1000-image-configuration.yml` files.
#### Valid full capsule {.reference}
@@ -213,39 +222,116 @@ To generate a capsule that updates only a single component, explicitly set the f
The partial capsule is also valid, but sets the firmware version to 7 only for the BL2 component, indicating that no other components should be updated.
Run the command below to generate the partial capsule:
Use the following commands to generate the `capsule_config.json` file, which is required by the EDK2 tool for capsule creation:
```
cd ${WORKSPACE}
kas shell meta-arm/kas/corstone1000-a320-fvp.yml:meta-arm/ci/debug.yml -c '
echo "CAPSULE_VERSION = \"7\"" >> conf/local.conf
echo "CAPSULE_LOWEST_SUPPORTED_VERSION = \"7\"" >> conf/local.conf
echo "CAPSULE_SELECTED_COMPONENTS = \"BL2\"" >> conf/local.conf
bitbake corstone1000-flash-firmware-image -c image_uefi_capsule
'
python3 meta-arm/meta-arm/scripts/generate_capsule_json_multiple.py \
--selected_components DUMMY_START BL2 DUMMY_END \
--components DUMMY_START BL2 TFM_S FIP INITRAMFS DUMMY_END \
--fw_versions 0 7 0 0 0 0 \
--guids \
6f784cbf-7938-5c23-8d6e-24d2f1410fa9 \
${BL2_GUID} ${TFM_S_GUID} ${FIP_GUID} ${INITRAMFS_GUID} \
b57e432b-a250-5c73-93e3-90205e64baba \
--hardware_instances 1 1 1 1 1 1 \
--lowest_supported_versions 5 5 5 5 5 5 \
--monotonic_counts 1 1 1 1 1 1 \
--payloads \
build/tmp/work/corstone1000_a320_fvp-poky-linux-musl/corstone1000-flash-firmware-image/1.0/sources/corstone1000-flash-firmware-image-1.0/dummy.bin \
build/tmp/deploy/images/corstone1000-a320-fvp/trusted-firmware-m/bl2_signed.bin \
build/tmp/deploy/images/corstone1000-a320-fvp/trusted-firmware-m/tfm_s_signed.bin \
build/tmp/deploy/images/corstone1000-a320-fvp/signed_fip.bin \
build/tmp/deploy/images/corstone1000-a320-fvp/Image.gz-initramfs-corstone1000-a320-fvp.bin \
build/tmp/work/corstone1000_a320_fvp-poky-linux-musl/corstone1000-flash-firmware-image/1.0/sources/corstone1000-flash-firmware-image-1.0/dummy.bin \
--update_image_indexes 5 1 2 3 4 6 \
--private_keys \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
--certificates \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
--output capsule_config.json
```
The partial capsule will be located at
`${WORKSPACE}/build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000-a320-fvp-v7.uefi.capsule`.
Run the command below to generate the partial capsule:
#### Rollback capsule {.reference}
```
./build/tmp/sysroots-components/aarch64/edk2-basetools-native/usr/bin/edk2-BaseTools/BinWrappers/PosixLike/GenerateCapsule \
-e \
-j capsule_config.json \
--capflag PersistAcrossReset \
-o corstone1000-a320-fvp-partial-v7.uefi.capsule
```
The partial capsule will be located in the `${WORKSPACE}` directory.
#### Invalid capsule {.reference}
Generate a capsule with firmware version metadata for all payloads set lower than that of a valid capsule.
The valid capsule has a default firmware version of 6 for all payloads, while the simulated invalid capsule has the firmware version set to 5 for all payloads.
Run the command below to generate the rollback capsule:
Use the following commands to generate the `capsule_config.json` file, which is required by the EDK2 tool for capsule creation:
```
cd ${WORKSPACE}
kas shell meta-arm/kas/corstone1000-a320-fvp.yml:meta-arm/ci/debug.yml -c '
echo "CAPSULE_VERSION = \"5\"" >> conf/local.conf
echo "CAPSULE_LOWEST_SUPPORTED_VERSION = \"5\"" >> conf/local.conf
bitbake corstone1000-flash-firmware-image -c image_uefi_capsule
'
python3 meta-arm/meta-arm/scripts/generate_capsule_json_multiple.py \
--selected_components DUMMY_START BL2 TFM_S FIP INITRAMFS DUMMY_END \
--components DUMMY_START BL2 TFM_S FIP INITRAMFS DUMMY_END \
--fw_versions 5 5 5 5 5 5 \
--guids \
6f784cbf-7938-5c23-8d6e-24d2f1410fa9 \
${BL2_GUID} ${TFM_S_GUID} ${FIP_GUID} ${INITRAMFS_GUID} \
b57e432b-a250-5c73-93e3-90205e64baba \
--hardware_instances 1 1 1 1 1 1 \
--lowest_supported_versions 5 5 5 5 5 5 \
--monotonic_counts 1 1 1 1 1 1 \
--payloads \
build/tmp/work/corstone1000_a320_fvp-poky-linux-musl/corstone1000-flash-firmware-image/1.0/sources/corstone1000-flash-firmware-image-1.0/dummy.bin \
build/tmp/deploy/images/corstone1000-a320-fvp/trusted-firmware-m/bl2_signed.bin \
build/tmp/deploy/images/corstone1000-a320-fvp/trusted-firmware-m/tfm_s_signed.bin \
build/tmp/deploy/images/corstone1000-a320-fvp/signed_fip.bin \
build/tmp/deploy/images/corstone1000-a320-fvp/Image.gz-initramfs-corstone1000-a320-fvp.bin \
build/tmp/work/corstone1000_a320_fvp-poky-linux-musl/corstone1000-flash-firmware-image/1.0/sources/corstone1000-flash-firmware-image-1.0/dummy.bin \
--update_image_indexes 5 1 2 3 4 6 \
--private_keys \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_key.key \
--certificates \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000_capsule_cert.crt \
--output capsule_config.json
```
The rollback capsule will be located at
`${WORKSPACE}/build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000-a320-fvp-v5.uefi.capsule`.
Run the command below to generate the invalid capsule:
```
./build/tmp/sysroots-components/aarch64/edk2-basetools-native/usr/bin/edk2-BaseTools/BinWrappers/PosixLike/GenerateCapsule \
-e \
-j capsule_config.json \
--capflag PersistAcrossReset \
-o corstone1000-a320-fvp-v5.uefi.capsule
```
The invalid capsule will be located in the `${WORKSPACE}` directory.
### Transfer capsules to target {.reference}
@@ -283,8 +369,8 @@ as opposed to the on-disk method (delivery of capsules using a file on a mass st
```
sudo cp ${WORKSPACE}/build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000-a320-fvp-v6.uefi.capsule /mnt/ir-acs-live-image-generic-arm64/
sudo cp ${WORKSPACE}/build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000-a320-fvp-v5.uefi.capsule /mnt/ir-acs-live-image-generic-arm64/
sudo cp ${WORKSPACE}/build/tmp/deploy/images/corstone1000-a320-fvp/corstone1000-a320-fvp-v7.uefi.capsule /mnt/ir-acs-live-image-generic-arm64/
sudo cp ${WORKSPACE}/corstone1000-a320-fvp-v5.uefi.capsule /mnt/ir-acs-live-image-generic-arm64/
sudo cp ${WORKSPACE}/corstone1000-a320-fvp-partial-v7.uefi.capsule /mnt/ir-acs-live-image-generic-arm64/
sync
```
@@ -315,7 +401,7 @@ To run the test:
cd ${WORKSPACE} && tmux
```
2. Run the FVP within `tmux` with the IR prebuilt image which now also contains the three capsules:
2. Run the FVP within `tmux` with the IR prebuilt image which now also contains the two capsules:
```
kas shell meta-arm/kas/corstone1000-a320-fvp.yml:meta-arm/ci/debug.yml \
@@ -440,7 +526,7 @@ Do not terminate FVP between the positive full capsule update and partial capsul
#### Positive partial capsule update {.reference}
Follow the steps for the [Positive full capsule update test], ensuring you use `corstone1000-a320-fvp-v7.uefi.capsule` instead of `corstone1000-a320-fvp-v6.uefi.capsule`.
Follow the steps for the [Positive full capsule update test], ensuring you use `corstone1000-a320-fvp-partial-v7.uefi.capsule` instead of `corstone1000-a320-fvp-v6.uefi.capsule`.
Once the system has fully booted again, read [Verifying firmware versions with ESRT] to confirm that the firmware version reflects the updated capsule.
@@ -91,7 +91,7 @@ Table: OP-TEE components
| Type | Path |
| --------- | ---------------------------------------------------------------------------------------------------------------- |
| bbappend | `${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-security/optee/optee-os_%.bbappend` |
| Recipe | `${WORKSPACE}/meta-arm/meta-arm/recipes-security/optee/optee-os_4.10.0.bb` |
| Recipe | `${WORKSPACE}/meta-arm/meta-arm/recipes-security/optee/optee-os_4.9.0.bb` |
#### U-Boot {.reference}
@@ -103,7 +103,7 @@ Table: U-Boot components
| --------- | ---------------------------------------------------------------------------------------------------------------- |
| bbappend | `${WORKSPACE}/meta-arm/meta-arm/recipes-bsp/u-boot/u-boot_%.bbappend` |
| bbappend | `${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/u-boot/u-boot_%.bbappend` |
| Recipe | `${WORKSPACE}/core/meta/recipes-bsp/u-boot/u-boot_2026.07.bb` |
| Recipe | `${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/u-boot/u-boot_2025.10.bb` |
#### Linux {.reference}
@@ -135,7 +135,7 @@ Table: Trusted Firmware-M secure enclave components
| Type | Path |
| --------- | ---------------------------------------------------------------------------------------------------------------- |
| bbappend | `${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m_%.bbappend` |
| Recipe | `${WORKSPACE}/meta-arm/meta-arm/recipes-bsp/trusted-firmware-m/trusted-firmware-m_2.3.0.bb` |
| Recipe | `${WORKSPACE}/meta-arm/meta-arm/recipes-bsp/trusted-firmware-m/trusted-firmware-m_2.2.2.bb` |
## Build {.reference}
@@ -28,7 +28,6 @@ The following prerequisites must be available on the host system:
- GNU Tar 1.34 or greater.
- GNU Compiler Collection 12.2 or greater.
- GNU Make 4.3 or greater.
- mtools 4.0 or greater.
- tmux 3.3 or greater.
Please follow the steps described in the Yocto mega manual:
@@ -131,11 +130,11 @@ Host Processor Components
`OP-TEE <https://git.trustedfirmware.org/OP-TEE/optee_os.git>`__
================================================================
+----------+-------------------------------------------------------------------------------------------+
| bbappend | ``${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-security/optee/optee-os_%.bbappend`` |
+----------+-------------------------------------------------------------------------------------------+
| Recipe | ``${WORKSPACE}/meta-arm/meta-arm/recipes-security/optee/optee-os_4.10.0.bb`` |
+----------+-------------------------------------------------------------------------------------------+
+----------+------------------------------------------------------------------------------------------+
| bbappend | ``${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-security/optee/optee-os_%.bbappend`` |
+----------+------------------------------------------------------------------------------------------+
| Recipe | ``${WORKSPACE}/meta-arm/meta-arm/recipes-security/optee/optee-os_4.9.0.bb`` |
+----------+------------------------------------------------------------------------------------------+
`U-Boot <https://github.com/u-boot/u-boot.git>`__
=================================================
@@ -145,7 +144,7 @@ Host Processor Components
+----------+----------------------------------------------------------------------------------+
| bbappend | ``${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/u-boot/u-boot_%.bbappend`` |
+----------+----------------------------------------------------------------------------------+
| Recipe | ``${WORKSPACE}/core/meta/recipes-bsp/u-boot/u-boot_2026.07.bb`` |
| Recipe | ``${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/u-boot/u-boot_2025.10.bb`` |
+----------+----------------------------------------------------------------------------------+
Linux
@@ -173,7 +172,7 @@ Secure Enclave Components
+----------+-------------------------------------------------------------------------------------------------------+
| bbappend | ``${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m_%.bbappend`` |
+----------+-------------------------------------------------------------------------------------------------------+
| Recipe | ``${WORKSPACE}/meta-arm/meta-arm/recipes-bsp/trusted-firmware-m/trusted-firmware-m_2.3.0.bb`` |
| Recipe | ``${WORKSPACE}/meta-arm/meta-arm/recipes-bsp/trusted-firmware-m/trusted-firmware-m_2.2.2.bb`` |
+----------+-------------------------------------------------------------------------------------------------------+
************************************
@@ -211,22 +210,13 @@ Build
mkdir ${WORKSPACE}
cd ${WORKSPACE}
#. Create a Python virtual environment and activate it.
#. Install kas version 4.4 with ``sudo`` rights.
.. code-block:: console
python3 -m venv ${WORKSPACE}/venv_cs1k
source ${WORKSPACE}/venv_cs1k/bin/activate
sudo pip3 install kas==4.4
#. Install ``kas`` and ``wic`` inside the virtual environment.
.. code-block:: console
python3 -m pip install kas==5.1 "git+https://git.yoctoproject.org/wic@v0.3.0"
.. note::
Ensure the kas and wic installation directory is visible on the ``$PATH`` environment variable.
Ensure the kas installation directory is visible on the ``$PATH`` environment variable.
#. Clone the `meta-arm` Yocto layer in the workspace ``${WORKSPACE}``.
@@ -449,10 +439,6 @@ MPS3
sudo picocom -b 115200 /dev/ttyUSB3
.. note::
If the user is a member of the ``dialout`` group, ``sudo`` is not required for this step.
.. important::
Plug a connected Ethernet cable to the MPS3 or it will
wait for a network connection for a considerable amount of time, printing the following
@@ -878,15 +864,14 @@ The results can be fetched from the `acs_results` folder in the ``BOOT`` partiti
.. note::
Access the `acs_results` folder in FVP by copying it from the same ACS image that was used to boot the FVP.
The following command copies the ``acs_results`` directory from the ACS image to
``${WORKSPACE}/acs_results`` on the host development machine.
Access the `acs_results` folder in FVP by running the following commands:
.. code-block:: console
cd ${WORKSPACE}
wic cp ${WORKSPACE}/arm-systemready/IR/prebuilt_images/v23.09_2.1.0/ir-acs-live-image-generic-arm64.wic:1/acs_results \
${WORKSPACE}
sudo mkdir /mnt/test
sudo mount -o rw,offset=1048576 \
${WORKSPACE}/arm-systemready/IR/prebuilt_images/v23.09_2.1.0/ir-acs-live-image-generic-arm64.wic \
/mnt/test
#####################################################
@@ -942,11 +927,20 @@ The following payloads can be individually updated:
Generate Capsules
*****************
Capsules are generated by running the ``image_uefi_capsule`` task for
``corstone1000-flash-firmware-image``. The task uses EDK II's ``GenerateCapsule``
tool and creates the capsule metadata JSON automatically from the recipe settings.
`EDK II's <edk2-repository_>`__ ``GenerateCapsule`` tool is used to generate capsules and is built automatically
for the host machine during the firmware image building process.
The tool can be found at ``${WORKSPACE}/build/tmp/sysroots-components/aarch64/edk2-basetools-native/usr/bin/edk2-BaseTools/BinWrappers/PosixLike/GenerateCapsule``.
The capsule's default metadata can be found in the ``${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/images/corstone1000-flash-firmware-image.bb``
.. note::
The ``aarch64`` part of this path depends on the build host architecture
and can be different on another host.
A JSON file containing metadata about the capsule payloads needs to be created using the script
found at ``${WORKSPACE}/meta-arm/meta-arm/scripts/generate_capsule_json_multiple.py``.
This JSON file is required by EDK II's ``GenerateCapsule`` tool to generate the capsule.
The capsule's default metadata passed can be found in the ``${WORKSPACE}/meta-arm/meta-arm-bsp/recipes-bsp/images/corstone1000-flash-firmware-image.bb``
and ``${WORKSPACE}/meta-arm/kas/corstone1000-image-configuration.yml`` files.
Valid Full Capsule
@@ -965,40 +959,118 @@ To generate a capsule that updates only a single component, explicitly set the f
The **partial capsule** is also valid, but sets the firmware version to **7** **only** for the **BL2** component, indicating that no other components should be updated.
Use the following commands to generate the `capsule_config.json` file, which is required by the EDK2 tool for capsule creation:
.. code-block:: console
cd ${WORKSPACE}
python3 meta-arm/meta-arm/scripts/generate_capsule_json_multiple.py \
--selected_components DUMMY_START BL2 DUMMY_END \
--components DUMMY_START BL2 TFM_S FIP INITRAMFS DUMMY_END \
--fw_versions 0 7 0 0 0 0 \
--guids \
6f784cbf-7938-5c23-8d6e-24d2f1410fa9 \
${BL2_GUID} ${TFM_S_GUID} ${FIP_GUID} ${INITRAMFS_GUID} \
b57e432b-a250-5c73-93e3-90205e64baba \
--hardware_instances 1 1 1 1 1 1 \
--lowest_supported_versions 5 5 5 5 5 5 \
--monotonic_counts 1 1 1 1 1 1 \
--payloads \
build/tmp/work/corstone1000_${TARGET}-poky-linux-musl/corstone1000-flash-firmware-image/1.0/sources/corstone1000-flash-firmware-image-1.0/dummy.bin \
build/tmp/deploy/images/corstone1000-${TARGET}/trusted-firmware-m/bl2_signed.bin \
build/tmp/deploy/images/corstone1000-${TARGET}/trusted-firmware-m/tfm_s_signed.bin \
build/tmp/deploy/images/corstone1000-${TARGET}/signed_fip.bin \
build/tmp/deploy/images/corstone1000-${TARGET}/Image.gz-initramfs-corstone1000-${TARGET}.bin \
build/tmp/work/corstone1000_${TARGET}-poky-linux-musl/corstone1000-flash-firmware-image/1.0/sources/corstone1000-flash-firmware-image-1.0/dummy.bin \
--update_image_indexes 5 1 2 3 4 6 \
--private_keys \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
--certificates \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
--output capsule_config.json
Run the command below to generate the partial capsule:
.. code-block:: console
cd ${WORKSPACE}
kas shell meta-arm/kas/corstone1000-${TARGET}.yml:meta-arm/ci/debug.yml -c '
echo "CAPSULE_VERSION = \"7\"" >> conf/local.conf
echo "CAPSULE_LOWEST_SUPPORTED_VERSION = \"7\"" >> conf/local.conf
echo "CAPSULE_SELECTED_COMPONENTS = \"BL2\"" >> conf/local.conf
bitbake corstone1000-flash-firmware-image -c image_uefi_capsule
'
./build/tmp/sysroots-components/aarch64/edk2-basetools-native/usr/bin/edk2-BaseTools/BinWrappers/PosixLike/GenerateCapsule \
-e \
-j capsule_config.json \
--capflag PersistAcrossReset \
-o corstone1000-${TARGET}-partial-v7.uefi.capsule
The partial capsule will be located at
``${WORKSPACE}/build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000-${TARGET}-v7.uefi.capsule``.
The partial capsule will be located in the ``${WORKSPACE}`` directory.
Rollback Capsule
================
Invalid Capsule
===============
Generate a capsule with firmware version metadata for all payloads set lower than that of a valid capsule.
The valid capsule has a default firmware version of 6 for all payloads, while the simulated invalid capsule has the firmware version set to 5 for all payloads.
Run the command below to generate the rollback capsule:
Use the following commands to generate the `capsule_config.json` file, which is required by the EDK2 tool for capsule creation:
.. code-block:: console
cd ${WORKSPACE}
kas shell meta-arm/kas/corstone1000-${TARGET}.yml:meta-arm/ci/debug.yml -c '
echo "CAPSULE_VERSION = \"5\"" >> conf/local.conf
echo "CAPSULE_LOWEST_SUPPORTED_VERSION = \"5\"" >> conf/local.conf
bitbake corstone1000-flash-firmware-image -c image_uefi_capsule
'
The rollback capsule will be located at
``${WORKSPACE}/build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000-${TARGET}-v5.uefi.capsule``.
python3 meta-arm/meta-arm/scripts/generate_capsule_json_multiple.py \
--selected_components DUMMY_START BL2 TFM_S FIP INITRAMFS DUMMY_END \
--components DUMMY_START BL2 TFM_S FIP INITRAMFS DUMMY_END \
--fw_versions 5 5 5 5 5 5 \
--guids \
6f784cbf-7938-5c23-8d6e-24d2f1410fa9 \
${BL2_GUID} ${TFM_S_GUID} ${FIP_GUID} ${INITRAMFS_GUID} \
b57e432b-a250-5c73-93e3-90205e64baba \
--hardware_instances 1 1 1 1 1 1 \
--lowest_supported_versions 5 5 5 5 5 5 \
--monotonic_counts 1 1 1 1 1 1 \
--payloads \
build/tmp/work/corstone1000_${TARGET}-poky-linux-musl/corstone1000-flash-firmware-image/1.0/sources/corstone1000-flash-firmware-image-1.0/dummy.bin \
build/tmp/deploy/images/corstone1000-${TARGET}/trusted-firmware-m/bl2_signed.bin \
build/tmp/deploy/images/corstone1000-${TARGET}/trusted-firmware-m/tfm_s_signed.bin \
build/tmp/deploy/images/corstone1000-${TARGET}/signed_fip.bin \
build/tmp/deploy/images/corstone1000-${TARGET}/Image.gz-initramfs-corstone1000-${TARGET}.bin \
build/tmp/work/corstone1000_${TARGET}-poky-linux-musl/corstone1000-flash-firmware-image/1.0/sources/corstone1000-flash-firmware-image-1.0/dummy.bin \
--update_image_indexes 5 1 2 3 4 6 \
--private_keys \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_key.key \
--certificates \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000_capsule_cert.crt \
--output capsule_config.json
Run the command below to generate the invalid capsule:
.. code-block:: console
./build/tmp/sysroots-components/aarch64/edk2-basetools-native/usr/bin/edk2-BaseTools/BinWrappers/PosixLike/GenerateCapsule \
-e \
-j capsule_config.json \
--capflag PersistAcrossReset \
-o corstone1000-${TARGET}-v5.uefi.capsule
The invalid capsule will be located in the ``${WORKSPACE}`` directory.
***************************
Transfer Capsules to Target
@@ -1007,48 +1079,76 @@ Transfer Capsules to Target
The capsule delivery process described below is the direct method (usage of capsules from the ACS image)
as opposed to the on-disk method (delivery of capsules using a file on a mass storage device).
MPS3
====
#. Prepare a USB drive as explained in `this <mps3-instructions-for-acs-image_>`_ section.
#. Copy the capsule files to the root directory of the ``BOOT`` partition in the USB drive.
.. code-block:: console
cp ${WORKSPACE}/build/tmp/deploy/images/corstone1000-mps3/corstone1000-mps3-v6.uefi.capsule /dev/sdc/BOOT/
cp ${WORKSPACE}/corstone1000-mps3-v5.uefi.capsule /dev/sdc/EFI/BOOT/
cp ${WORKSPACE}/corstone1000-mps3-partial-v7.uefi.capsule /dev/sdc/EFI/BOOT/
sync
.. note::
The staging steps below are shared between ``mps3`` and ``fvp``.
``/dev/sdc`` is the assumed path for the ACS Image USB drive.
Replace it with the actual device path as enumerated on your development machine.
#. Download and extract the ACS image `as described for the MPS3 <mps3-instructions-for-acs-image_>`_.
The ACS image extraction location will be referred below as ``${ACS_IMAGE_PATH}``.
#. Copy the ACS image to the workspace root directory and rename it to
``ir-acs-live-image-generic-arm64-staged.wic``. The staged image will then be
populated with the capsule files.
``${ACS_STAGED_IMAGE}`` refers to
``${WORKSPACE}/ir-acs-live-image-generic-arm64-staged.wic``.
.. code-block:: console
cp ${ACS_IMAGE_PATH}/ir-acs-live-image-generic-arm64.wic \
${ACS_STAGED_IMAGE}
#. Copy the capsules to the staged ACS image:
.. code-block:: console
cd ${WORKSPACE}
wic cp ${WORKSPACE}/build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000-${TARGET}-v6.uefi.capsule \
${ACS_STAGED_IMAGE}:1/corstone1000-${TARGET}-v6.uefi.capsule
wic cp ${WORKSPACE}/build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000-${TARGET}-v5.uefi.capsule \
${ACS_STAGED_IMAGE}:1/corstone1000-${TARGET}-v5.uefi.capsule
wic cp ${WORKSPACE}/build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000-${TARGET}-v7.uefi.capsule \
${ACS_STAGED_IMAGE}:1/corstone1000-${TARGET}-v7.uefi.capsule
.. important::
The direct Capsule Update method requires that the capsule files not be placed in the ``EFI/UpdateCapsule`` directory,
as doing so might inadvertently trigger the on-disk update method.
MPS3
====
FVP
===
#. Write ``${ACS_STAGED_IMAGE}`` to the ACS USB drive by following the
`MPS3 ACS image steps <mps3-instructions-for-acs-image_>`_ and replacing
``ir-acs-live-image-generic-arm64.wic`` with ``${ACS_STAGED_IMAGE}``.
#. Download and extract the ACS image `as described for the MPS3 <mps3-instructions-for-acs-image_>`_.
The ACS image extraction location will be referred below as ``${ACS_IMAGE_PATH}``.
.. note::
Creating a USB drive with the ACS image is not required as the image will be mounted with the steps below.
#. Find the first partition's offset of the ``ir-acs-live-image-generic-arm64.wic`` image using the ``fdisk`` tool.
The partition table can be listed using:
.. code-block:: console
fdisk -lu ${ACS_IMAGE_PATH}/ir-acs-live-image-generic-arm64.wic
Device Start End Sectors Size Type
${ACS_IMAGE_PATH}/ir-acs-live-image-generic-arm64.wic1 2048 309247 307200 150M Microsoft basic data
${ACS_IMAGE_PATH}/ir-acs-live-image-generic-arm64.wic2 309248 1343339 1034092 505M Linux filesystem
Given that the first partition starts at sector 2048 and each sector is 512 bytes in size,
the first partition is at offset 1048576 (2048 x 512).
#. Mount the ``ir-acs-live-image-generic-arm64.wic`` image using the previously calculated offset:
.. code-block:: console
sudo mkdir /mnt/ir-acs-live-image-generic-arm64
sudo mount -o rw,offset=<first_partition_offset> ${ACS_IMAGE_PATH}/ir-acs-live-image-generic-arm64.wic /mnt/ir-acs-live-image-generic-arm64
#. Copy the capsules:
.. code-block:: console
sudo cp ${WORKSPACE}/build/tmp/deploy/images/corstone1000-fvp/corstone1000-fvp-v6.uefi.capsule /mnt/ir-acs-live-image-generic-arm64/
sudo cp ${WORKSPACE}/corstone1000-fvp-v5.uefi.capsule /mnt/ir-acs-live-image-generic-arm64/
sudo cp ${WORKSPACE}/corstone1000-fvp-partial-v7.uefi.capsule /mnt/ir-acs-live-image-generic-arm64/
sync
#. Unmount the IR image:
.. code-block:: console
sudo umount /mnt/ir-acs-live-image-generic-arm64
************************
Run Capsule Update Tests
@@ -1072,7 +1172,7 @@ Positive Full Capsule Update Test
- MPS3:
#. Plug the prepared USB drive which has the IR prebuilt image and three capsules to the MPS3.
#. Plug the prepared USB drive which has the IR prebuilt image and two capsules to the MPS3.
#. Power cycle the MPS3.
- FVP:
@@ -1083,18 +1183,17 @@ Positive Full Capsule Update Test
cd ${WORKSPACE} && tmux
#. Run the FVP within ``tmux`` with the IR prebuilt image which now also contains the three capsules:
#. Run the FVP within ``tmux`` with the IR prebuilt image which now also contains the two capsules:
.. code-block:: console
cd ${WORKSPACE}
kas shell meta-arm/kas/corstone1000-fvp.yml:meta-arm/ci/debug.yml \
-c "../meta-arm/scripts/runfvp --terminals=tmux \
-- -C board.msd_mmc.p_mmc_file=${ACS_STAGED_IMAGE}"
-- -C board.msd_mmc.p_mmc_file=${ACS_IMAGE_PATH}/ir-acs-live-image-generic-arm64.wic"
.. warning::
``${ACS_STAGED_IMAGE}`` must be an absolute path. Ensure there are no spaces before or after of ``=`` of the ``-C board.msd_mmc.p_mmc_file`` option.
``${ACS_IMAGE_PATH}`` must be an absolute path. Ensure there are no spaces before or after of ``=`` of the ``-C board.msd_mmc.p_mmc_file`` option.
#. Wait until U-Boot loads EFI from the ACS image and interrupt the EFI shell by pressing the ``Escape`` key when the following prompt is displayed on the Host Processor terminal (``ttyUSB2`` for MPS3).
@@ -1115,7 +1214,7 @@ Positive Full Capsule Update Test
.. code-block:: console
EFI/BOOT/app/CapsuleApp.efi corstone1000-mps3-v6.uefi.capsule
EFI/BOOT/app/CapsuleApp.efi EFI/BOOT/corstone1000-mps3-v6.uefi.capsule
- FVP:
@@ -1228,7 +1327,7 @@ Positive Partial Capsule Update Test
====================================
Follow the steps for the `positive full capsule update test <positive-full-capsule-update-test_>`__ ensuring you use
``corstone1000-${TARGET}-v7.uefi.capsule`` instead of ``corstone1000-${TARGET}-v6.uefi.capsule``.
``corstone1000-${TARGET}-partial-v7.uefi.capsule`` instead of ``corstone1000-${TARGET}-v6.uefi.capsule``.
Once the system has fully booted again, `read the ESRT <verifying-firmware-versions-via-esrt_>`__ to
confirm that the firmware version reflects the updated capsule.
@@ -1269,7 +1368,7 @@ Rollback Protection Capsule Update Test
.. code-block:: console
EFI/BOOT/app/CapsuleApp.efi corstone1000-mps3-v5.uefi.capsule
EFI/BOOT/app/CapsuleApp.efi EFI/BOOT/corstone1000-mps3-v5.uefi.capsule
- FVP:
@@ -1584,10 +1683,6 @@ MPS3
sudo picocom -b 115200 /dev/ttyUSB2
.. note::
If the user is a member of the ``dialout`` group, ``sudo`` is not required for this step.
#. When the installation screen is displayed on ``ttyUSB2``, plug in the (still empty) system drive to the MPS3.
#. Start the distribution installation process.
@@ -1808,17 +1903,19 @@ Generate Keys, Signed Image and Unsigned Image
The `efitools <https://github.com/vathpela/efitools/>`__ package is required to execute the script.
The ``mtools`` package is required on the host development machine to execute the script.
``${CERTIFICATE_VALIDITY_DURATION_IN_DAYS}`` is an integer that specifies the certificate's validity period in days.
.. note::
Consult the image signing script help message (``-h``) for more information about other optional arguments.
The script is interactive and contains commands that require ``sudo`` level permissions.
The keys, signed kernel image, and unsigned kernel image will be copied to the exisiting ESP image.
The modified ESP image can be found at ``${WORKSPACE}/build/tmp/deploy/images/corstone1000-${TARGET}/corstone1000-esp-image-corstone1000-${TARGET}.wic``.
****************************
Run Unsigned Image Boot Test
****************************
@@ -2129,75 +2226,33 @@ For more information about this, see the following resources:
- `Authenticated Debug Access Control Specification <https://developer.arm.com/documentation/den0101/latest/>`__
- `Arm Corstone-1000 for MPS3 Application Note AN550, Chapter 7 <https://developer.arm.com/documentation/dai0550/latest/>`__
#. Install `Arm Development Studio <arm-ds-website_>`__ 2026.1, or Arm
Development Studio Platinum 2026.b. These releases contain a built-in
PSA-ADAC Secure Debug Manager.
The Secure Debug Manager API is implemented in the `Secure Debug Manager (PSA-ADAC / SDC-600) <secure-debug-manager-repo-readme_>`__ repository.
This repository also contains the necessary files for the Arm Development Studio support.
The build and integration instructions can be found in its `README <secure-debug-manager-repo-readme_>`__.
#. Clone the `Secure Debug Manager
<https://github.com/ARM-software/secure-debug-manager>`__
repository to obtain the dummy test credentials.
The `Secure Debug Manager (PSA-ADAC / SDC-600)` repository also contains the private key and chain certificate to be used during the tests.
The private key's public pair is provisioned into the One-Time Programmable memory in TrustedFirmware-M.
These are dummy keys that should not be used in production.
To test the Secure Debug feature, you'll need a debug probe from the `Arm ULINKpro family <arm-ulink-pro-website_>`__
and `Arm Development Studio <arm-ds-website_>`__ versions 2022.2, 2022.c, or 2023.a.
#. Clone the `Secure Debug Manager (PSA-ADAC / SDC-600)` repository to your workspace.
.. code-block:: console
cd ${WORKSPACE}
git clone https://github.com/ARM-software/secure-debug-manager.git
Only the example private key and certificate chain are needed from this
repository.
The public key corresponding to these credentials is provisioned into the
TrustedFirmware-M One-Time Programmable memory. The supplied credentials
are test credentials and must not be used in production.
#. Create a user configuration database based on the Arm Development Studio
Corstone-1000 database. The following example assumes that Arm Development
Studio Platinum 2026.b is installed in ``/opt/arm``:
#. Navigate into the repository directory and checkout the specific commit in the listing below.
.. code-block:: console
export ARMDS_INSTALL_DIR=/opt/arm/developmentstudio_platinum-2026.b
export CS1000_ADAC_DB=${WORKSPACE}/armds-cs1000-adac611
cd ${WORKSPACE}/secure-debug-manager
git checkout b30d6496ca749123e86b39b161b9f70ef76106d6
mkdir -p "${CS1000_ADAC_DB}/Boards/Arm_Development_Boards"
cp -a \
"${ARMDS_INSTALL_DIR}/sw/debugger/configdb/Boards/Arm Development Boards/MPS3_Corstone_1000" \
"${CS1000_ADAC_DB}/Boards/Arm_Development_Boards/MPS3_Corstone_1000_ADAC_611"
cp -a "${ARMDS_INSTALL_DIR}/sw/debugger/configdb/Include" "${CS1000_ADAC_DB}/"
cp -a "${ARMDS_INSTALL_DIR}/sw/debugger/configdb/Schemas" "${CS1000_ADAC_DB}/"
cp -a "${ARMDS_INSTALL_DIR}/sw/debugger/configdb/ATP" "${CS1000_ADAC_DB}/"
If Arm Development Studio is installed elsewhere, change
``ARMDS_INSTALL_DIR`` accordingly.
#. Enable the built-in PSA-ADAC Secure Debug Manager in the copied database.
In
``${CS1000_ADAC_DB}/Boards/Arm_Development_Boards/MPS3_Corstone_1000_ADAC_611/project_types.xml``,
add the following element alongside the existing ``dtsl_config`` parameter:
.. code-block:: xml
<secure_debug_manager type="adac_sdc600" manifest="CDB://../../../ATP/manifest.xml" device="CSAPBCOM" reset_type="nSRST"/>
This selects the built-in PSA-ADAC implementation, its authentication-token
provider, the SDC-600 communication device, and the board reset signal.
#. Describe the Corstone-1000 debug port as DPv3. In
``${CS1000_ADAC_DB}/Boards/Arm_Development_Boards/MPS3_Corstone_1000_ADAC_611/MPS3_Corstone_1000.sdf``,
add the following item to the ``<device_info>`` block of the ``ARMCS-DP``
device:
.. code-block:: xml
<device_info_item name="DP_VERSION">DPv3</device_info_item>
DPv3 is required so that Arm Development Studio uses the ADIv6 debug-port
addressing needed to reach ``CSAPBCOM``.
In the same file, give the copied platform a unique title:
.. code-block:: xml
<platform_info info_url="" manufacturer="Arm" title="MPS3_Corstone_1000_ADAC_611"/>
#. Follow the instructions in the `Secure Debug Manager (PSA-ADAC / SDC-600)'s README <secure-debug-manager-repo-readme_>`__ for the development machine setup.
#. Rebuild the software stack with Secure Debug.
@@ -2217,60 +2272,11 @@ For more information about this, see the following resources:
IComPortInit : 383 : warn : init : IComPortInit: Blocked reading LPH2RA
#. Open a new Arm Development Studio IDE window and add the user configuration
database.
#. Connect the debug probe to the MPS3 using the 20-pin 1.27mm connector with the ``CS_20W_1.27MM silkscreen`` label.
#. Select ``Window`` > ``Preferences``.
#. Expand ``Arm DS`` and select ``Configuration Database``.
#. Select ``Add``.
#. Enter a descriptive name, such as ``Corstone-1000 Secure Debug``.
The name does not affect the connection.
#. Set ``Location`` to ``${WORKSPACE}/armds-cs1000-adac611``.
#. Select ``OK`` to close the ``Add configuration database location`` dialog.
#. Select ``Rebuild database``.
#. Select ``Apply and Close``.
#. Create a debug configuration in Arm Development Studio as described in the `Secure Debug Manager (PSA-ADAC / SDC-600)'s README <secure-debug-manager-armds-integration_>`__.
#. Create the Arm Development Studio hardware connection.
#. Select ``Create a debug connection...``.
#. Select ``Hardware Connection``, then select ``Next``.
#. Enter a descriptive debug connection name, then select ``Next``.
The name does not affect the connection.
#. In ``Target Selection``, select ``MPS3_Corstone_1000_ADAC_611``.
#. Select ``Finish``.
#. Configure one of the following external debug connections.
To use an external `ULINKpro D <arm-ulink-pro-d-website_>`__ probe:
#. Connect the ULINKpro D probe to the MPS3 connector labelled
``CS_20W_1.27MM``.
#. Select ``Arm`` > ``MPS3_Corstone_1000_ADAC_611`` >
``Bare Metal Debug`` > ``Cortex-M0+``.
#. For ``Target Connection``, select ``ULINKpro D``.
#. Select ``Browse...``, select the detected ULINKpro D probe, and then
select ``Select``.
#. Select ``JTAG/SWJ``, set the debug clock to ``500 kHz``, and select
``Connect only``.
To use an external `DSTREAM <arm-dstream-website_>`__ probe:
#. Connect the DSTREAM probe to the MPS3 connector labelled
``CS_20W_1.27MM``.
#. Select ``Arm`` > ``MPS3_Corstone_1000_ADAC_611`` >
``Bare Metal Debug`` > ``Cortex-M0+``.
#. For ``Target Connection``, select ``DSTREAM``.
#. Select ``Browse...``, select the detected DSTREAM probe, and then select
``Select``.
#. Select ``JTAG/SWJ``, set the debug clock to ``500 kHz``, and select
``Connect only``.
In both cases, use ``Cortex-M0+`` because Secure Debug runs in the Secure
Enclave. Do not select the host ``Cortex-A35`` connection.
#. Select ``Debug``. Arm Development Studio resets the target using ``nSRST``
and the built-in Secure Debug Manager communicates with ``CSAPBCOM`` to
perform authentication.
#. Connect the debuger to the target using the debug configuration.
#. Provide the paths to the private key and trust chain certificate when asked by Arm Development Studio Console.
@@ -2279,21 +2285,21 @@ For more information about this, see the following resources:
...
Please provide private key file path:
Enter file path > ${WORKSPACE}/secure-debug-manager/example/data/keys/EcdsaP256Key-3.pem
Enter file path > ${WORKSPACE}\secure-debug-manager\example\data\keys\EcdsaP256Key-3.pem
Please provide trust chain file path:
Enter file path > ${WORKSPACE}/secure-debug-manager/example/data/chains/chain.EcdsaP256-3
Enter file path > ${WORKSPACE}\secure-debug-manager\example\data\chains\chain.EcdsaP256-3
...
#. After authentication succeeds, verify that the image continues booting and
is not left waiting inside the Secure Debug authentication flow.
Authentication alone is not sufficient to pass the test. Confirm that the
Host terminal reaches the Linux login prompt:
#. When successful authenticated, Arm Development Studio will connect to the running MPS3 and the debug features can be used.
The following prompt should appear in the Secure Enclave terminal (``ttyUSB1``):
.. code-block:: console
corstone1000-mps3 login:
...
boot_platform_init: Corstone-1000 Secure Debug is a success.
...
--------------
@@ -2301,8 +2307,9 @@ For more information about this, see the following resources:
*Copyright (c) 2022-2026, Arm Limited. All rights reserved.*
.. _arm-developer-fvp: https://developer.arm.com/tools-and-software/open-source-software/arm-platforms-software/arm-ecosystem-fvps
.. _secure-debug-manager-repo-readme: https://github.com/ARM-software/secure-debug-manager/tree/master?tab=readme-ov-file#secure-debug-manager-psa-adac--sdc-600
.. _secure-debug-manager-armds-integration: https://github.com/ARM-software/secure-debug-manager?tab=readme-ov-file#arm-development-studio-integration
.. _meta-arm-repository-release-branch: https://docs.yoctoproject.org/next/migration-guides/migration-6.0.html
.. _arm-ulink-pro-website: https://www.arm.com/products/development-tools/debug-probes/ulink-pro
.. _arm-ds-website: https://www.arm.com/products/development-tools/embedded-and-software/arm-development-studio
.. _arm-ulink-pro-d-website: https://www.arm.com/products/development-tools/debug-probes/ulink-pro
.. _arm-dstream-website: https://www.arm.com/products/development-tools/debug-probes/dstream-st
.. _edk2-repository: https://github.com/tianocore/edk2
@@ -23,7 +23,7 @@ part --source rawcopy --size 144k --sourceparams="file=trusted-firmware-m/bl2_si
part --source rawcopy --size 320k --sourceparams="file=trusted-firmware-m/tfm_s_signed.bin" --align 4 --part-name="tfm_primary" --uuid 07F9616C-1233-439C-ACBA-72D75421BF70 --part-type 7FAD470E-5EC5-5C03-A2C1-4756B495DE61
# Rawcopy of the FIP binary
part --source rawcopy --size 2560k --sourceparams="file=signed_fip.bin" --align 4 --part-name="FIP_A" --uuid B9C7AC9D-40FF-4675-956B-EEF4DE9DF1C5 --part-type F1933675-5A8C-5B6D-9EF4-846739E89BC8
part --source rawcopy --size 2 --sourceparams="file=signed_fip.bin" --align 4 --part-name="FIP_A" --uuid B9C7AC9D-40FF-4675-956B-EEF4DE9DF1C5 --part-type F1933675-5A8C-5B6D-9EF4-846739E89BC8
# Rawcopy of kernel with initramfs
part --source rawcopy --size 12 --sourceparams="file=Image.gz-initramfs-${MACHINE}.bin" --align 4 --part-name="kernel_primary" --uuid BF7A6142-0662-47FD-9434-6A8811980816 --part-type F771AFF9-C7E9-5F99-9EDA-2369DD694F61
@@ -1,3 +1,2 @@
arch_timer: Failed to initialize memory-mapped timer.
PCI: OF: of_root node is NULL, cannot create PCI host bridge node
_OSC: platform retains control of PCIe features (AE_ERROR)
@@ -1,3 +1,2 @@
arch_timer: Failed to initialize memory-mapped timer.
PCI: OF: of_root node is NULL, cannot create PCI host bridge node
_OSC: platform retains control of PCIe features (AE_ERROR)
@@ -1,18 +1,17 @@
SUMMARY = "External system Cortex-M3 Firmware"
DESCRIPTION = "Firmware to be loaded and run in External System Harness in\
support to the main application CPU."
HOMEPAGE = "https://gitlab.arm.com/arm-reference-solutions/corstone1000/external_system/rtx"
HOMEPAGE = "https://git.linaro.org/landing-teams/working/arm/external-system.git"
DEPENDS = "gcc-arm-none-eabi-native"
INHIBIT_DEFAULT_DEPS = "1"
LICENSE = "Apache-2.0 AND BSD-3-Clause"
LIC_FILES_CHKSUM = "file://LICENSE;md5=e44b2531cd6ffe9dece394dbe988d9a0 \
LICENSE = "BSD-3-Clause & Apache-2.0"
LIC_FILES_CHKSUM = "file://license.md;md5=e44b2531cd6ffe9dece394dbe988d9a0 \
file://cmsis/LICENSE.txt;md5=e3fc50a88d0a364313df4b21ef20c29e"
SRC_URI = "gitsm://gitlab.arm.com/arm-reference-solutions/corstone1000/external_system/rtx.git;protocol=https;branch=master \
SRC_URI = "gitsm://git.gitlab.arm.com/arm-reference-solutions/corstone1000/external_system/rtx.git;protocol=https;branch=master \
file://0001-tools-gen_module_code-atomically-rewrite-the-generat.patch"
SRCREV = "3a38cef6e9582907ad6f79950e3d54330c9ab42c"
UPSTREAM_CHECK_COMMITS = "1"
SRCREV = "8c9dca74b104ff6c9722fb0738ba93dd3719c080"
PV .= "+git"
COMPATIBLE_MACHINE = "(corstone1000)"
PACKAGE_ARCH = "${MACHINE_ARCH}"
@@ -160,10 +160,9 @@ TFA_FIP_BINARY = "fip.bin"
TFA_BL2_RE_IMAGE_LOAD_ADDRESS = "0x62353000"
TFA_BL2_RE_SIGN_BIN_SIZE = "0x2d000"
TFA_FIP_RE_IMAGE_LOAD_ADDRESS = "0x68130000"
TFA_FIP_RE_SIGN_BIN_SIZE = "0x00280000"
TFA_FIP_RE_SIGN_BIN_SIZE = "0x00200000"
RE_LAYOUT_WRAPPER_VERSION = "0.0.7"
TFM_SIGN_PRIVATE_KEY = "${libdir}/tfm-scripts/root-EC-P256_1.pem"
TFM_IMAGE_SIGN_PSA_KEY_IDS = "2147451244"
RE_IMAGE_OFFSET = "0x1000"
do_sign_images() {
@@ -11,7 +11,6 @@ SRC_URI:append = " \
TFA_DEBUG = "1"
TFA_UBOOT ?= "1"
#FIXME - this can be removed after moving to 2.15.0
TFA_MBEDTLS = "1"
TFA_BUILD_TARGET = "bl2 bl31 fip"
@@ -55,6 +55,9 @@ TFA_PLATFORM = "fvp"
# Disable debug build if measured boot is enabled.
TFA_DEBUG := "${@bb.utils.contains('MACHINE_FEATURES', 'ts-attestation', '0',\
d.getVar('TFA_DEBUG'), d)}"
# Add mbedtls if measured boot is enabled
TFA_MBEDTLS := "${@bb.utils.contains('MACHINE_FEATURES', 'ts-attestation',\
'1', d.getVar('TFA_MBEDTLS'), d)}"
TFA_UBOOT ?= "1"
TFA_BUILD_TARGET = "bl1 bl2 bl31 dtbs fip"
@@ -3,6 +3,7 @@
COMPATIBLE_MACHINE = "juno"
TFA_PLATFORM = "juno"
TFA_DEBUG = "1"
TFA_MBEDTLS = "1"
TFA_UBOOT ?= "1"
TFA_BUILD_TARGET = "bl1 bl2 bl31 dtbs fip"
@@ -27,29 +27,3 @@ SRCREV_tfa = "a4b376b128bb5b91771002f7808566f53c8d9f3a"
SRC_URI:remove = "file://0001-feat-build-add-HOSTLDFLAGS-to-pass-flags-to-host-lin.patch"
LIC_FILES_CHKSUM:remove = "file://docs/license.rst;md5=6ed7bace7b0bc63021c6eba7b524039e"
LIC_FILES_CHKSUM += "file://docs/license.rst;md5=1118e32884721c0be33267bd7ae11130"
# sub-directory in which mbedtls will be downloaded
# Only needed for legacy versions, as v2.15.0 added this as a git submodule
TFA_MBEDTLS_DIR ?= "mbedtls"
# This should be set to MBEDTLS download URL if MBEDTLS is needed
SRC_URI_MBEDTLS ??= ""
# This should be set to MBEDTLS LIC FILES checksum
LIC_FILES_CHKSUM_MBEDTLS ??= ""
# add MBEDTLS to our sources if activated
SRC_URI:append = " ${@bb.utils.contains('TFA_MBEDTLS', '1', '${SRC_URI_MBEDTLS}', '', d)}"
# Update license variables
LICENSE:append = "${@bb.utils.contains('TFA_MBEDTLS', '1', ' AND Apache-2.0', '', d)}"
LIC_FILES_CHKSUM:append = "${@bb.utils.contains('TFA_MBEDTLS', '1', ' ${LIC_FILES_CHKSUM_MBEDTLS}', '', d)}"
# add mbed TLS to version
SRCREV_FORMAT:append = "${@bb.utils.contains('TFA_MBEDTLS', '1', '_mbedtls', '', d)}"
# Handle MBEDTLS
EXTRA_OEMAKE += "${@bb.utils.contains('TFA_MBEDTLS', '1', 'MBEDTLS_DIR=${TFA_MBEDTLS_DIR}', '', d)}"
# in TF-A src, docs/getting_started/prerequisites.rst lists the expected version mbedtls
# mbedtls-3.6.5
SRCBRANCH_MBEDTLS = "mbedtls-3.6"
SRC_URI_MBEDTLS = "gitsm://github.com/Mbed-TLS/mbedtls;name=mbedtls;protocol=https;destsuffix=${BB_GIT_DEFAULT_DESTSUFFIX}/mbedtls;branch=${SRCBRANCH_MBEDTLS}"
SRCREV_mbedtls = "e185d7fd85499c8ce5ca2a54f5cf8fe7dbe3f8df"
LIC_FILES_CHKSUM_MBEDTLS = "file://mbedtls/LICENSE;md5=379d5819937a6c2f1ef1630d341e026d"
@@ -27,29 +27,3 @@ SRCREV_tfa = "a4b376b128bb5b91771002f7808566f53c8d9f3a"
SRC_URI:remove = "file://0001-feat-build-add-HOSTLDFLAGS-to-pass-flags-to-host-lin.patch"
LIC_FILES_CHKSUM:remove = "file://docs/license.rst;md5=6ed7bace7b0bc63021c6eba7b524039e"
LIC_FILES_CHKSUM += "file://docs/license.rst;md5=1118e32884721c0be33267bd7ae11130"
# sub-directory in which mbedtls will be downloaded
# Only needed for legacy versions, as v2.15.0 added this as a git submodule
TFA_MBEDTLS_DIR ?= "mbedtls"
# This should be set to MBEDTLS download URL if MBEDTLS is needed
SRC_URI_MBEDTLS ??= ""
# This should be set to MBEDTLS LIC FILES checksum
LIC_FILES_CHKSUM_MBEDTLS ??= ""
# add MBEDTLS to our sources if activated
SRC_URI:append = " ${@bb.utils.contains('TFA_MBEDTLS', '1', '${SRC_URI_MBEDTLS}', '', d)}"
# Update license variables
LICENSE:append = "${@bb.utils.contains('TFA_MBEDTLS', '1', ' AND Apache-2.0', '', d)}"
LIC_FILES_CHKSUM:append = "${@bb.utils.contains('TFA_MBEDTLS', '1', ' ${LIC_FILES_CHKSUM_MBEDTLS}', '', d)}"
# add mbed TLS to version
SRCREV_FORMAT:append = "${@bb.utils.contains('TFA_MBEDTLS', '1', '_mbedtls', '', d)}"
# Handle MBEDTLS
EXTRA_OEMAKE += "${@bb.utils.contains('TFA_MBEDTLS', '1', 'MBEDTLS_DIR=${TFA_MBEDTLS_DIR}', '', d)}"
# in TF-A src, docs/getting_started/prerequisites.rst lists the expected version mbedtls
# mbedtls-3.6.5
SRCBRANCH_MBEDTLS = "mbedtls-3.6"
SRC_URI_MBEDTLS = "gitsm://github.com/Mbed-TLS/mbedtls;name=mbedtls;protocol=https;destsuffix=${BB_GIT_DEFAULT_DESTSUFFIX}/mbedtls;branch=${SRCBRANCH_MBEDTLS}"
SRCREV_mbedtls = "e185d7fd85499c8ce5ca2a54f5cf8fe7dbe3f8df"
LIC_FILES_CHKSUM_MBEDTLS = "file://mbedtls/LICENSE;md5=379d5819937a6c2f1ef1630d341e026d"
@@ -0,0 +1,25 @@
From f3400c6527e6d0c073215694e19734a6268a6bc9 Mon Sep 17 00:00:00 2001
From: Ali Can Ozaslan <ali.oezaslan@arm.com>
Date: Wed, 24 Jan 2024 16:10:08 +0000
Subject: [PATCH] arm/trusted-firmware-m: disable address warnings into an
error
Signed-off-by: Emekcan Aras <emekcan.aras@arm.com>
Signed-off-by: Ali Can Ozaslan <ali.oezaslan@arm.com>
Upstream-Status: Inappropriate
---
toolchain_GNUARM.cmake | 1 +
1 file changed, 1 insertion(+)
diff --git a/toolchain_GNUARM.cmake b/toolchain_GNUARM.cmake
index 56a220ba8471..af80a2746676 100644
--- a/toolchain_GNUARM.cmake
+++ b/toolchain_GNUARM.cmake
@@ -113,6 +113,7 @@ add_compile_options(
-Wno-format
-Wno-return-type
-Wno-unused-but-set-variable
+ -Wno-error=address
-c
-fdata-sections
-ffunction-sections
@@ -0,0 +1,449 @@
From 9ed08f26cafc2c6e5bf1d5cc04f91ca17d94a1bd Mon Sep 17 00:00:00 2001
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Date: Wed, 13 Aug 2025 14:02:57 +0000
Subject: [PATCH] Platform: CS1000: Remove unused BL1 files
These files are not referenced anywhere so removed them to prevent
confusion.
Signed-off-by: Bence Balogh <bence.balogh@arm.com>
Upstream-Status: Backport [9a7bdf9ef595196e1e518a27d3c79079aedb5bda]
---
.../arm/corstone1000/bl1/CMakeLists.txt | 345 ------------------
.../arm/corstone1000/bl1/bl1_security_cnt.c | 75 ----
2 files changed, 420 deletions(-)
delete mode 100644 platform/ext/target/arm/corstone1000/bl1/CMakeLists.txt
delete mode 100644 platform/ext/target/arm/corstone1000/bl1/bl1_security_cnt.c
diff --git a/platform/ext/target/arm/corstone1000/bl1/CMakeLists.txt b/platform/ext/target/arm/corstone1000/bl1/CMakeLists.txt
deleted file mode 100644
index d85b0611dd42..000000000000
--- a/platform/ext/target/arm/corstone1000/bl1/CMakeLists.txt
+++ /dev/null
@@ -1,345 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2020-2024, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-
-cmake_minimum_required(VERSION 3.15)
-cmake_policy(SET CMP0079 NEW)
-
-project("BL1 Bootloader" VERSION 0.0.1 LANGUAGES C ASM)
-
-# BL1 only loads the BL2 image, image number always equals 1
-set(BL1_IMAGE_NUMBER 1)
-
-# Version of BL2 image
-set(BL2_IMAGE_VERSION "0.1.0")
-
-add_executable(bl1)
-
-set_target_properties(bl1
- PROPERTIES
- SUFFIX ".axf"
- RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
-)
-
-target_link_options(bl1
- PRIVATE
- $<$<C_COMPILER_ID:GNU>:-Wl,-Map=${CMAKE_BINARY_DIR}/bin/bl1.map>
-)
-
-add_convert_to_bin_target(bl1)
-
-# bl2_crypto reused as it is, but it pulls the MCUBOOT_IMAGE_NUMBER=${MCUBOOT_IMAGE_NUMBER}
-# configuration, where image number is 3. (Coming from BL2 build). To not to collide with BL1's
-# build where image number is 1 mbedcrypto library is separated from the build of other source
-# files.
-target_link_libraries(bl1
- PRIVATE
- bl1_main
- bl2_crypto
- cmsis_stack_override
- cmsis
-)
-
-# add_convert_to_bin_target(bl1) requires at least one source file added to bl1. This sources will
-# be built with wrong image number macro (value coming from BL2 config), so the start-up files
-# added here, as those not use this image number macro.
-target_sources(bl1
- PRIVATE
- $<$<C_COMPILER_ID:GNU>:${CMAKE_CURRENT_SOURCE_DIR}/../Device/Source/startup_corstone1000.c>
-)
-
-# Needed for the GCC startup files
-target_include_directories(bl1
- PRIVATE
- ${CMAKE_SOURCE_DIR}/platform/include
- ../Device/Include
-)
-
-# target_add_scatter_file(bl1) cannot be used as it would add the platform_region_defs dependency
-# to bl1, again pulling the image number property matching with BL2 build, so scatter setup done
-# here by hand.
-target_link_options(bl1
- PRIVATE
- -T $<TARGET_OBJECTS:bl1_scatter>
-)
-
-add_library(bl1_scatter OBJECT)
-
-add_dependencies(bl1
- bl1_scatter
- )
-
-target_sources(bl1_scatter
- PRIVATE
- ../Device/Source/gcc/corstone1000_bl1.ld
-)
-
-set_source_files_properties(../Device/Source/gcc/corstone1000_bl1.ld
- PROPERTIES
- LANGUAGE C
-)
-
-target_compile_options(bl1_scatter
- PRIVATE
- -E
- -P
- -xc
-)
-
-target_compile_definitions(bl1_scatter
- PRIVATE
- MCUBOOT_IMAGE_NUMBER=${BL1_IMAGE_NUMBER}
- BL1
-)
-
-target_include_directories(bl1_scatter
- PRIVATE
- ../partition
-)
-
-# Library to spearate build from bl2_mbedcrypto configurations
-add_library(bl1_main STATIC)
-
-target_compile_definitions(bl1_main
- PRIVATE
- MCUBOOT_IMAGE_NUMBER=${BL1_IMAGE_NUMBER}
- BL1
- BL2
- $<$<BOOL:${PLATFORM_IS_FVP}>:PLATFORM_IS_FVP>
-)
-
-# Configurations based on bl2/CMakeLists.txt
-
-# Many files are reused form TF-M's bl2 directory
-set(BL2_SOURCE ${CMAKE_SOURCE_DIR}/bl2)
-
-target_sources(bl1_main
- PRIVATE
- ${BL2_SOURCE}/src/flash_map.c
- ./provisioning.c
-)
-
-target_include_directories(bl1_main
- PRIVATE
- $<BUILD_INTERFACE:${BL2_SOURCE}/include>
-)
-
-# Include path needed for mbedcrypto headers
-target_include_directories(bl1_main
- PRIVATE
- $<BUILD_INTERFACE:${MBEDCRYPTO_PATH}/include>
-)
-
-# Configurations based on bl2/ext/mcuboot/CMakeLists.txt
-target_link_libraries(bl1_main
- PRIVATE
- mcuboot_config
- bl2_crypto_config
-)
-
-target_include_directories(bl1_main
- PRIVATE
- $<BUILD_INTERFACE:${BL2_SOURCE}/ext/mcuboot/include>
-)
-
-target_sources(bl1_main
- PRIVATE
- ${BL2_SOURCE}/ext/mcuboot/bl2_main.c
- ${BL2_SOURCE}/ext/mcuboot/keys.c
- ${BL2_SOURCE}/ext/mcuboot/flash_map_legacy.c
-)
-
-# Configurations based on ${MCUBOOT_PATH}/boot/bootutil/CMakeLists.txt
-# add_subdirectory("${MCUBOOT_PATH}/boot/bootutil" bootutil) cannot work as we want to define different hal
-# functions compared to BL2
-target_sources(bl1_main
- PRIVATE
- ${MCUBOOT_PATH}/boot/bootutil/src/loader.c
- ${MCUBOOT_PATH}/boot/bootutil/src/bootutil_misc.c
- ${MCUBOOT_PATH}/boot/bootutil/src/bootutil_public.c
- ${MCUBOOT_PATH}/boot/bootutil/src/image_validate.c
- ${MCUBOOT_PATH}/boot/bootutil/src/image_rsa.c
- ${MCUBOOT_PATH}/boot/bootutil/src/tlv.c
- ${MCUBOOT_PATH}/boot/bootutil/src/boot_record.c
- ${MCUBOOT_PATH}/boot/bootutil/src/swap_scratch.c
- ${MCUBOOT_PATH}/boot/bootutil/src/swap_move.c
- ${MCUBOOT_PATH}/boot/bootutil/src/swap_misc.c
- ${MCUBOOT_PATH}/boot/bootutil/src/encrypted.c
- ${MCUBOOT_PATH}/boot/bootutil/src/fault_injection_hardening.c
- ${MCUBOOT_PATH}/boot/bootutil/src/fault_injection_hardening_delay_rng_mbedtls.c
-)
-
-target_include_directories(bl1_main
- PRIVATE
- $<BUILD_INTERFACE:${MCUBOOT_PATH}/boot/bootutil/include>
- $<BUILD_INTERFACE:${MCUBOOT_PATH}/boot/bootutil/src>
- $<BUILD_INTERFACE:${MCUBOOT_PATH}/boot>
-)
-
-# Configurations based on platform/CMakeLists.txt
-target_include_directories(bl1_main
- PRIVATE
- $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/platform/include>
- $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/platform/ext/driver>
- $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/platform/ext/common>
- $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/platform/ext>
- $<$<BOOL:${CRYPTO_HW_ACCELERATOR}>:${CMAKE_SOURCE_DIR}/platform/ext/accelerator/interface>
-)
-
-target_sources(bl1_main
- PRIVATE
- $<$<BOOL:${PLATFORM_DEFAULT_UART_STDOUT}>:${CMAKE_SOURCE_DIR}/platform/ext/common/uart_stdout.c>
- $<$<BOOL:${PLATFORM_DEFAULT_NV_COUNTERS}>:${CMAKE_SOURCE_DIR}/platform/ext/common/template/nv_counters.c>
- $<$<OR:$<BOOL:${PLATFORM_DEFAULT_NV_COUNTERS}>,$<BOOL:${PLATFORM_DEFAULT_OTP}>>:${CMAKE_SOURCE_DIR}/platform/ext/common/template/flash_otp_nv_counters_backend.c>
- $<$<BOOL:${PLATFORM_DEFAULT_OTP}>:${CMAKE_SOURCE_DIR}/platform/ext/common/template/otp_flash.c>
-)
-
-target_link_libraries(bl1_main
- PRIVATE
- bl2_hal
- cmsis
-)
-
-target_compile_definitions(bl1_main
- PRIVATE
- MCUBOOT_${MCUBOOT_UPGRADE_STRATEGY}
- $<$<BOOL:${SYMMETRIC_INITIAL_ATTESTATION}>:SYMMETRIC_INITIAL_ATTESTATION>
- $<$<BOOL:${PLATFORM_DEFAULT_NV_COUNTERS}>:PLATFORM_DEFAULT_NV_COUNTERS>
- $<$<BOOL:${MCUBOOT_HW_KEY}>:MCUBOOT_HW_KEY>
- MCUBOOT_FIH_PROFILE_${MCUBOOT_FIH_PROFILE}
- $<$<BOOL:${PLATFORM_DEFAULT_NV_COUNTERS}>:PLATFORM_DEFAULT_NV_COUNTERS>
- $<$<BOOL:${PLATFORM_DEFAULT_OTP}>:PLATFORM_DEFAULT_OTP>
- $<$<BOOL:${OTP_NV_COUNTERS_RAM_EMULATION}>:OTP_NV_COUNTERS_RAM_EMULATION=1>
- $<$<BOOL:${TFM_DUMMY_PROVISIONING}>:TFM_DUMMY_PROVISIONING>
- $<$<BOOL:${PLATFORM_DEFAULT_OTP_WRITEABLE}>:OTP_WRITEABLE>
-)
-
-# Configurations based on cc312 cmake files
-target_compile_definitions(bl1_main
- PRIVATE
- $<$<BOOL:${CRYPTO_HW_ACCELERATOR_OTP_STATE}>:CRYPTO_HW_ACCELERATOR_OTP_${CRYPTO_HW_ACCELERATOR_OTP_STATE}>
- $<$<BOOL:${CRYPTO_HW_ACCELERATOR}>:CRYPTO_HW_ACCELERATOR>
- $<$<BOOL:${ENABLE_FWU_AGENT_DEBUG_LOGS}>:ENABLE_FWU_AGENT_DEBUG_LOGS>
-)
-
-target_include_directories(bl1_main
- PRIVATE
- $<$<BOOL:${CRYPTO_HW_ACCELERATOR}>:${CMAKE_SOURCE_DIR}/platform/ext/accelerator/cc312>
- $<$<BOOL:${CRYPTO_HW_ACCELERATOR}>:${CMAKE_SOURCE_DIR}/lib/ext/cryptocell-312-runtime/shared/include/mbedtls>
- $<$<BOOL:${CRYPTO_HW_ACCELERATOR}>:${CMAKE_SOURCE_DIR}/lib/ext/cryptocell-312-runtime/shared/include/crypto_api/cc3x>
- ../soft_crc
-)
-
-# Configurations based on platform level cmake files
-target_sources(bl1_main
- PRIVATE
- ../CMSIS_Driver/Driver_Flash.c
- ../CMSIS_Driver/Driver_USART.c
- ../Device/Source/device_definition.c
- ../Device/Source/system_core_init.c
- ../Native_Driver/firewall.c
- ../Native_Driver/uart_pl011_drv.c
- ../fw_update_agent/fwu_agent.c
- ../soft_crc/soft_crc.c
- ../Native_Driver/arm_watchdog_drv.c
- ../Native_Driver/watchdog.c
- bl1_boot_hal.c
- bl1_flash_map.c
- bl1_security_cnt.c
- flash_map_extended.c
- bl1_rotpk.c
-)
-
-if (PLATFORM_IS_FVP)
-target_sources(bl1_main
- PRIVATE
- ${PLATFORM_DIR}/ext/target/arm/drivers/flash/strata/spi_strataflashj3_flash_lib.c
- ${PLATFORM_DIR}/ext/target/arm/drivers/flash/cfi/cfi_drv.c
-)
-else()
-target_sources(bl1_main
- PRIVATE
- ${PLATFORM_DIR}/ext/target/arm/drivers/qspi/xilinx_pg153_axi/xilinx_pg153_axi_qspi_controller_drv.c
- ${PLATFORM_DIR}/ext/target/arm/drivers/flash/n25q256a/spi_n25q256a_flash_lib.c
- ${PLATFORM_DIR}/ext/target/arm/drivers/flash/sst26vf064b/spi_sst26vf064b_flash_lib.c
-)
-endif()
-
-target_include_directories(bl1_main
- PRIVATE
- ../partition
- ../Device/Include
- ../.
- ../CMSIS_Driver/Config
- ../Device/Config
- ../Native_Driver
- ../fw_update_agent
- ${PLATFORM_DIR}/ext/target/arm/drivers/flash/common
- ${PLATFORM_DIR}/ext/target/arm/drivers/flash/cfi
- ${PLATFORM_DIR}/ext/target/arm/drivers/flash/strata
- ${PLATFORM_DIR}/ext/target/arm/drivers/qspi/xilinx_pg153_axi
- ${PLATFORM_DIR}/ext/target/arm/drivers/flash/n25q256a
- ${PLATFORM_DIR}/ext/target/arm/drivers/flash/sst26vf064b
-
-)
-
-############################### SIGNING BL2 image ##################################
-
-find_package(Python3)
-
-set(FLASH_AREA_NUM 8)
-configure_file(signing_layout.c.in ${CMAKE_CURRENT_BINARY_DIR}/signing_layout.c @ONLY)
-add_library(signing_layout_for_bl2 OBJECT ${CMAKE_CURRENT_BINARY_DIR}/signing_layout.c)
-
-target_compile_options(signing_layout_for_bl2
- PRIVATE
- $<$<C_COMPILER_ID:GNU>:-E\;-xc>
- $<$<C_COMPILER_ID:ARMClang>:-E\;-xc>
- $<$<C_COMPILER_ID:IAR>:--preprocess=ns\;$<TARGET_OBJECTS:signing_layout_s>>
-)
-target_compile_definitions(signing_layout_for_bl2
- PRIVATE
- MCUBOOT_IMAGE_NUMBER=${BL1_IMAGE_NUMBER}
- BL1
-)
-
-target_include_directories(signing_layout_for_bl2
- PRIVATE
- ../partition
-)
-
-if (CONFIG_TFM_BOOT_STORE_MEASUREMENTS AND CONFIG_TFM_BOOT_STORE_ENCODED_MEASUREMENTS)
- set(MCUBOOT_MEASURED_BOOT ON)
-endif()
-
-add_custom_target(bl2_signed_bin
- ALL
- SOURCES bl2_signed.bin
-)
-add_custom_command(OUTPUT bl2_signed.bin
- DEPENDS $<TARGET_FILE_DIR:bl2>/bl2.bin
- DEPENDS bl2_bin signing_layout_for_bl2
- WORKING_DIRECTORY ${MCUBOOT_PATH}/scripts
-
- #Sign secure binary image with provided secret key
- COMMAND ${Python3_EXECUTABLE} ${BL2_SOURCE}/ext/mcuboot/scripts/wrapper/wrapper.py
- -v ${BL2_IMAGE_VERSION}
- --layout $<TARGET_OBJECTS:signing_layout_for_bl2>
- -k ${MCUBOOT_KEY_S}
- --public-key-format $<IF:$<BOOL:${MCUBOOT_HW_KEY}>,full,hash>
- --align 1
- --pad
- --pad-header
- -H 0x400
- -s ${MCUBOOT_SECURITY_COUNTER_S}
- -d \"\(0,${MCUBOOT_S_IMAGE_MIN_VER}\)\"
- $<$<STREQUAL:${MCUBOOT_UPGRADE_STRATEGY},OVERWRITE_ONLY>:--overwrite-only>
- $<$<BOOL:${MCUBOOT_ENC_IMAGES}>:-E${MCUBOOT_KEY_ENC}>
- $<$<BOOL:${MCUBOOT_MEASURED_BOOT}>:--measured-boot-record>
- $<TARGET_FILE_DIR:bl2>/bl2.bin
- ${CMAKE_CURRENT_BINARY_DIR}/bl2_signed.bin
- COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/bl2_signed.bin $<TARGET_FILE_DIR:bl2>
-)
diff --git a/platform/ext/target/arm/corstone1000/bl1/bl1_security_cnt.c b/platform/ext/target/arm/corstone1000/bl1/bl1_security_cnt.c
deleted file mode 100644
index 32c1481cca11..000000000000
--- a/platform/ext/target/arm/corstone1000/bl1/bl1_security_cnt.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include "bootutil/security_cnt.h"
-#include "tfm_plat_nv_counters.h"
-#include "tfm_plat_defs.h"
-#include "bootutil/fault_injection_hardening.h"
-#include <stdint.h>
-#include "tfm_plat_provisioning.h"
-#include "fwu_agent.h"
-
-fih_ret boot_nv_security_counter_init(void)
-{
- FIH_DECLARE(fih_rc, FIH_FAILURE);
-
- fih_rc = fih_ret_encode_zero_equality(tfm_plat_init_nv_counter());
-
- FIH_RET(fih_rc);
-}
-
-fih_ret boot_nv_security_counter_get(uint32_t image_id, fih_int *security_cnt)
-{
- FIH_DECLARE(fih_rc, FIH_FAILURE);
- uint32_t security_cnt_soft;
-
- /* Check if it's a null-pointer. */
- if (!security_cnt) {
- FIH_RET(FIH_FAILURE);
- }
-
- if (image_id != 0) {
- FIH_RET(FIH_FAILURE);
- }
-
- fih_rc = fih_ret_encode_zero_equality(
- tfm_plat_read_nv_counter(PLAT_NV_COUNTER_BL1_0,
- sizeof(security_cnt_soft),
- (uint8_t *)&security_cnt_soft));
- *security_cnt = fih_int_encode(security_cnt_soft);
-
- FIH_RET(fih_rc);
-}
-
-int32_t boot_nv_security_counter_update(uint32_t image_id,
- uint32_t img_security_cnt)
-{
- enum tfm_plat_err_t err;
- enum fwu_agent_error_t fwu_err;
-
- if (image_id != 0) {
- return -1;
- }
-
- if (tfm_plat_provisioning_is_required()) {
-
- err = tfm_plat_set_nv_counter(PLAT_NV_COUNTER_BL1_0, img_security_cnt);
- if (err != TFM_PLAT_ERR_SUCCESS) {
- return -1;
- }
-
- } else {
-
- fwu_err = fwu_stage_nv_counter(FWU_BL2_NV_COUNTER, img_security_cnt);
- if (fwu_err != FWU_AGENT_SUCCESS) {
- return -1;
- }
-
- }
-
- return 0;
-}
@@ -0,0 +1,43 @@
From 1d7ab426f171516c15ce8e5223541c62c91ec596 Mon Sep 17 00:00:00 2001
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Date: Wed, 13 Aug 2025 14:31:53 +0000
Subject: [PATCH] Platform: Corstone1000: Fix BL1 compiler switch and
regression test failure
Introduce a dedicated preprocessor definition (`BL1_BUILD`) added only to the
platform_bl1_1 target. This ensures that #if BL1 checks are evaluated correctly
based on the actual build configuration.
Signed-off-by: Michael Safwat <michael.safwat@arm.com>
Signed-off-by: Bence Balogh <bence.balogh@arm.com>
Upstream-Status: Backport [f25649cc0de56f360069c6128670f7533ba5e14d]
---
platform/ext/target/arm/corstone1000/CMakeLists.txt | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/platform/ext/target/arm/corstone1000/CMakeLists.txt b/platform/ext/target/arm/corstone1000/CMakeLists.txt
index ff7cf7330a07..66dfb2399503 100644
--- a/platform/ext/target/arm/corstone1000/CMakeLists.txt
+++ b/platform/ext/target/arm/corstone1000/CMakeLists.txt
@@ -146,6 +146,7 @@ target_sources(platform_s
rse_comms_permissions_hal.c
mem_check_v6m_v7m_hal.c
${PLATFORM_DIR}/ext/common/mem_check_v6m_v7m.c
+ platform.c
)
if (PLATFORM_IS_FVP)
@@ -215,6 +216,13 @@ target_compile_definitions(platform_bl1_1
$<$<BOOL:${CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING}>:CRYPTO_HW_ACCELERATOR_OTP_PROVISIONING>
MBEDTLS_CONFIG_FILE="${CMAKE_SOURCE_DIR}/lib/ext/mbedcrypto/mbedcrypto_config/tfm_mbedcrypto_config_default.h"
MBEDTLS_PSA_CRYPTO_CONFIG_FILE="${CMAKE_SOURCE_DIR}/lib/ext/mbedcrypto/mbedcrypto_config/crypto_config_default.h"
+
+ # This definition is only added to the bl1_main target. There are
+ # files that are shared between the BL1 and TFM_S targets. This flag
+ # can be used if the BL1 target needs different implementation than
+ # the TFM_S target.
+ BL1_BUILD
+
)
target_include_directories(platform_bl1_1_interface
@@ -1,90 +0,0 @@
From f0567aa80b2cc88d278c3adb0a5366ae9ff8cf58 Mon Sep 17 00:00:00 2001
From: Devaraj Ranganna <devaraj.ranganna@arm.com>
Date: Mon, 22 Sep 2025 12:59:43 +0100
Subject: [PATCH] bl2: corstone-1000: secure debug waiting in CM LCS
Currently, when the device is in Secure Enable (SE) LCS state,
setting the dcu_en register causes a CC-312 reset. Because CC-312 and
the device share a power domain, this effectively resets the device.
Temporarily perform the secure-debug handshake while the device
remains in the CM provisioned state. The long-term solution is to
complete the secure-debug handshake, reset the device, and apply
dcu_en during BL2.
Upstream-Status: Inappropriate [Need to be redesigned]
Signed-off-by: Devaraj Ranganna <devaraj.ranganna@arm.com>
Signed-off-by: Ahmed Gomaa <Ahmed.Gomaa@arm.com>
---
.../arm/corstone1000/bl2/boot_hal_bl2.c | 46 ++++++++++++-------
1 file changed, 30 insertions(+), 16 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c b/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c
index 9bc0f20e10..d034efe59f 100644
--- a/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c
+++ b/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c
@@ -187,7 +187,7 @@ int32_t boot_platform_post_init(void)
int32_t result;
enum tfm_plat_err_t plat_err;
#ifdef PLATFORM_PSA_ADAC_SECURE_DEBUG
- bool provisioning_required;
+ /* bool provisioning_required; */
#endif
#ifdef CRYPTO_HW_ACCELERATOR
@@ -204,26 +204,40 @@ int32_t boot_platform_post_init(void)
}
#ifdef PLATFORM_PSA_ADAC_SECURE_DEBUG
- plat_err = tfm_plat_provisioning_is_required(&provisioning_required);
+ /*
+ * TODO: Currently, when the device is in Secure Enable (SE) LCS state,
+ * setting `dcu_en` register causes CC-312 reset, which effectively resets
+ * the device as they are both on the same power domain. Therefore,
+ * temporarily perform the secure-debug handshake while the device remains
+ * in the CM provisioned state.
+ *
+ * The long-term solution is to complete the secure-debug handshake, reset
+ * the device, and apply `dcu_en` during BL2.
+ *
+ * TF-M 2.3 splits the provisioning check into an error return and a Boolean
+ * output value. Keep the complete gate commented while this workaround is
+ * required:
+ *
+ * plat_err = tfm_plat_provisioning_is_required(&provisioning_required);
+ * if (plat_err != TFM_PLAT_ERR_SUCCESS) {
+ * BOOT_LOG_ERR("Platform provisioning required check failed");
+ * FIH_PANIC;
+ * }
+ *
+ * if (!provisioning_required) {
+ */
+
+ plat_err = tfm_plat_otp_read(SECURE_DEBUG_ROTPK_ID, 32, secure_debug_rotpk);
if (plat_err != TFM_PLAT_ERR_SUCCESS) {
- BOOT_LOG_ERR("Platform provisioning required check failed");
- FIH_PANIC;
+ return plat_err;
}
- if (!provisioning_required) {
-
- plat_err = tfm_plat_otp_read(SECURE_DEBUG_ROTPK_ID, 32, secure_debug_rotpk);
- if (plat_err != TFM_PLAT_ERR_SUCCESS) {
- return plat_err;
- }
-
#ifndef PSA_ADAC_AS_TFM_RUNTIME_SERVICE
- result = tfm_to_psa_adac_corstone1000_secure_debug(secure_debug_rotpk, 32);
- BOOT_LOG_INF("%s: Corstone-1000 Secure Debug is a %s.\r\n", __func__,
- (result == 0) ? "success" : "failure");
+ result = tfm_to_psa_adac_corstone1000_secure_debug(secure_debug_rotpk, 32);
+ BOOT_LOG_INF("%s: Corstone-1000 Secure Debug is a %s.\r\n", __func__,
+ (result == 0) ? "success" : "failure");
#endif /* PSA_ADAC_AS_TFM_RUNTIME_SERVICE */
-
- }
+ /* } */
#endif /* PLATFORM_PSA_ADAC_SECURE_DEBUG */
return 0;
@@ -1,30 +0,0 @@
From cc48c5782b6968a34fa69047c04f3caf99a3bf18 Mon Sep 17 00:00:00 2001
From: Jon Mason <jon.mason@arm.com>
Date: Mon, 23 Feb 2026 11:53:38 -0500
Subject: [PATCH] Build: fix remaining GCC v14.2 AES type error
GCC v14.2 diagnoses the incompatible pointer type used when passing
the ECB key buffer to bl1_key_to_cc3xx_key(). Cast the uint32_t key
buffer to the uint8_t pointer type expected by the helper.
Upstream-Status: Inappropriate [GCC v14.2 compatibility workaround]
Signed-off-by: Jon Mason <jon.mason@arm.com>
Signed-off-by: Ahmed Gomaa <Ahmed.Gomaa@arm.com>
---
platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c b/platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c
index 6bc89fe115..2008e9641b 100644
--- a/platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c
+++ b/platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c
@@ -338,7 +338,7 @@ static int32_t aes_256_ecb_encrypt(enum tfm_bl1_key_id_t key_id,
return -1;
}
- rc = bl1_key_to_cc3xx_key(key_id, &cc3xx_key_type, key_buf, sizeof(key_buf));
+ rc = bl1_key_to_cc3xx_key(key_id, &cc3xx_key_type, (uint8_t *)key_buf, sizeof(key_buf));
if (rc) {
return rc;
}
@@ -0,0 +1,33 @@
From fdfbb3b82f62a2d4575a983ebaee14a67130d316 Mon Sep 17 00:00:00 2001
From: Ali Can Ozaslan <ali.oezaslan@arm.com>
Date: Tue, 15 Oct 2024 12:50:16 +0000
Subject: [PATCH] Platform: Corstone1000: Enable FWU partition
Enable firmware update partition for Corstone-1000 platform.
Increase the necessary flags to enable firmware update partition.
Set TFM_FWU_BOOTLOADER_LIB to use Corstone-1000 specific bootloader
configuration. Fix linker issues caused by enablement.
Upstream-Status: Backport [0107057d1411ec68e374fbd0ddc0e12abd5754ec]
Signed-off-by: Ali Can Ozaslan <ali.oezaslan@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
platform/ext/target/arm/corstone1000/config.cmake | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/platform/ext/target/arm/corstone1000/config.cmake b/platform/ext/target/arm/corstone1000/config.cmake
index 7a88542a32fc..6d9cb1fea750 100644
--- a/platform/ext/target/arm/corstone1000/config.cmake
+++ b/platform/ext/target/arm/corstone1000/config.cmake
@@ -55,6 +55,10 @@ set(TFM_PARTITION_CRYPTO ON CACHE BOOL "Enable Cryp
set(TFM_PARTITION_INITIAL_ATTESTATION ON CACHE BOOL "Enable Initial Attestation partition")
set(TFM_PARTITION_INTERNAL_TRUSTED_STORAGE ON CACHE BOOL "Enable Internal Trusted Storage partition")
+set(TFM_PARTITION_FIRMWARE_UPDATE ON CACHE BOOL "Enable firmware update partition")
+set(PLATFORM_HAS_FIRMWARE_UPDATE_SUPPORT ON CACHE BOOL "Wheter the platform has firmware update support")
+set(MCUBOOT_DATA_SHARING ON CACHE BOOL "Enable Data Sharing")
+set(TFM_FWU_BOOTLOADER_LIB "${CMAKE_CURRENT_LIST_DIR}/bootloader/mcuboot" CACHE STRING "Bootloader configure file for Firmware Update partition")
if (${CMAKE_BUILD_TYPE} STREQUAL Debug OR ${CMAKE_BUILD_TYPE} STREQUAL RelWithDebInfo)
set(ENABLE_FWU_AGENT_DEBUG_LOGS TRUE CACHE BOOL "Enable Firmware update agent debug logs.")
@@ -0,0 +1,46 @@
From 78231f27db0bbc747902b603bf279dce1707a3cc Mon Sep 17 00:00:00 2001
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Date: Mon, 16 Jun 2025 14:44:39 +0100
Subject: [PATCH] Platform: Corstone1000: Increase buffer sizes
Increase PSA_MAX_ASSET_SIZE and CRYPTO_IOVEC_BUFFER_SIZE
to accommodate large size EFI variables set by new U-Boot version.
This change is required to pass ACS tests related to Set/Get
EFI variables. These ACS tests started failing after introducing new
version of U-Boot, Trusted-Services and Trusted-Firmware-M while
implementing PSA FWU support.
Upstream-Status: Backport [bd80dee733e792eadfd2115f4bfa6bad748e5ce5]
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
platform/ext/target/arm/corstone1000/config_tfm_target.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/config_tfm_target.h b/platform/ext/target/arm/corstone1000/config_tfm_target.h
index 4920f67084d4..cf13712a1806 100644
--- a/platform/ext/target/arm/corstone1000/config_tfm_target.h
+++ b/platform/ext/target/arm/corstone1000/config_tfm_target.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -27,13 +27,13 @@
#define ITS_MAX_ASSET_SIZE 2048
/* The maximum asset size to be stored in the Protected Storage */
-#define PS_MAX_ASSET_SIZE 2592
+#define PS_MAX_ASSET_SIZE 3500
/* This is needed to be able to process the EFI variables during PS writes. */
#define CRYPTO_ENGINE_BUF_SIZE 0x5000
/* This is also has to be increased to fit the EFI variables into the iovecs. */
-#define CRYPTO_IOVEC_BUFFER_SIZE 6000
+#define CRYPTO_IOVEC_BUFFER_SIZE 7200
/* The Mailbox partition is used as an NS Agent so its stack size is used to
* determine the PSP and PSPLIM during the SFN backend initialization. It has to
@@ -0,0 +1,31 @@
From 291b717c9ff6124dd132602e84f75f320adbfda1 Mon Sep 17 00:00:00 2001
From: Yogesh Wani <yogesh.wani@arm.com>
Date: Wed, 30 Apr 2025 14:39:37 +0100
Subject: [PATCH] Platform: Corstone1000: Remove duplicate configuration
parameters for Corstone-1000
The PS_NUM_ASSET is duplicated in the cmake.config and the
config_tfm_target.h file under Corstone-1000. The commit removes
the one from the cmake.config and keeps the one in the header file.
The whole rationale behind this is for the vendor to be able
to override the configuration using the cmake file.
Upstream-Status: Backport [948cb8e7601dcf1fe822d855c77749287fe6d9bd]
Signed-off-by: Yogesh Wani <yogesh.wani@arm.com>
---
platform/ext/target/arm/corstone1000/config.cmake | 1 -
1 file changed, 1 deletion(-)
diff --git a/platform/ext/target/arm/corstone1000/config.cmake b/platform/ext/target/arm/corstone1000/config.cmake
index a923f63ca697..032265cdf4ac 100644
--- a/platform/ext/target/arm/corstone1000/config.cmake
+++ b/platform/ext/target/arm/corstone1000/config.cmake
@@ -74,7 +74,6 @@ endif()
# Platform-specific configurations
set(CONFIG_TFM_USE_TRUSTZONE OFF)
set(TFM_MULTI_CORE_TOPOLOGY ON)
-set(PS_NUM_ASSETS "40" CACHE STRING "The maximum number of assets to be stored in the Protected Storage area")
set(MCUBOOT_USE_PSA_CRYPTO ON CACHE BOOL "Enable the cryptographic abstraction layer to use PSA Crypto APIs")
set(MCUBOOT_SIGNATURE_TYPE "EC-P256" CACHE STRING "Algorithm to use for signature validation [RSA-2048, RSA-3072, EC-P256, EC-P384]")
@@ -0,0 +1,487 @@
From c5bcb737352ad2e1c24cc14a0b8ddf91ad7197b4 Mon Sep 17 00:00:00 2001
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Date: Tue, 29 Jul 2025 15:09:45 +0000
Subject: [PATCH] plat: corstone1000: Add support for Cortex-A320 variant
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add support for powering on the Cortex-A320 host in the DSU-120T
cluster and reserve Host SRAM for the normal world on the
Corstone-1000 platform. These changes enable secure-enclave firmware
control of the Cortex-A320 power domain and memory access
configuration.
**DSU-120T Power-Policy Unit (PPU) driver**
* Introduce a minimal driver to program the DSU-120T Power-Policy
Units, allowing the secure-enclave firmware to bring the
Cortex-A320 host cluster out of reset.
* The DSU utility-bus registers are located at:
* `0x6091_0000` in the Host memory map.
* `0xC091_0000` in the Secure-Enclave memory map.
* The FC1 firewall is configured so that only the Secure Enclave may
write to this window.
* Add new CMake option `CORSTONE1000_DSU_120T` and platform define to
enable Cortex-A320 DSU-120T–specific code.
**Host SRAM allocation**
* Reserve a 4 MiB block of Host SRAM at `0x0240_0000` for the
Cortex-A320 normal world.
* Open the same region in the Host-side firewall (CVM, region 2)
to allow non-secure access.
* This configuration is compiled in when `CORSTONE1000_CORTEX_A320`
is defined.
These updates prepare the Corstone-1000 platform for Cortex-A320
integration with proper cluster power management and normal-world
memory accessibility.
Upstream-Status: Submitted (https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/45749)
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
.../target/arm/corstone1000/CMakeLists.txt | 31 +++
.../Device/Include/platform_base_address.h | 8 +-
.../arm/corstone1000/bl1/boot_hal_bl1_1.c | 50 ++++-
.../target/arm/corstone1000/dsu-120t/ppu.c | 40 ++++
.../target/arm/corstone1000/dsu-120t/ppu.h | 185 ++++++++++++++++++
.../arm/corstone1000/tfm_hal_multi_core.c | 28 ++-
6 files changed, 339 insertions(+), 3 deletions(-)
create mode 100644 platform/ext/target/arm/corstone1000/dsu-120t/ppu.c
create mode 100644 platform/ext/target/arm/corstone1000/dsu-120t/ppu.h
diff --git a/platform/ext/target/arm/corstone1000/CMakeLists.txt b/platform/ext/target/arm/corstone1000/CMakeLists.txt
index 91bf197d86b7..993c51591fa7 100644
--- a/platform/ext/target/arm/corstone1000/CMakeLists.txt
+++ b/platform/ext/target/arm/corstone1000/CMakeLists.txt
@@ -423,6 +423,37 @@ target_sources(tfm_spm
$<$<BOOL:${TFM_S_REG_TEST}>:${CMAKE_CURRENT_SOURCE_DIR}/target_cfg.c>
)
+#========================= DSU-120T ============================================#
+if (CORSTONE1000_DSU_120T)
+ target_sources(tfm_psa_rot_partition_ns_agent_mailbox
+ PUBLIC
+ dsu-120t/ppu.c
+ )
+
+ target_compile_definitions(tfm_psa_rot_partition_ns_agent_mailbox
+ PUBLIC
+ CORSTONE1000_DSU_120T
+ )
+
+ target_compile_definitions(platform_bl1_1
+ PUBLIC
+ CORSTONE1000_DSU_120T
+ )
+
+ target_include_directories(tfm_psa_rot_partition_ns_agent_mailbox
+ PUBLIC
+ dsu-120t
+ )
+endif()
+
+#========================= Ethos-U NPU =========================================#
+if (CORSTONE1000_CORTEX_A320)
+ target_compile_definitions(platform_bl1_1
+ PUBLIC
+ CORSTONE1000_CORTEX_A320
+ )
+endif()
+
#========================= tfm_adac ============================================#
if (${PLATFORM_PSA_ADAC_SECURE_DEBUG})
diff --git a/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h b/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h
index 5f9f03ddc610..3908d69bc9bd 100644
--- a/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h
+++ b/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h
@@ -1,5 +1,7 @@
/*
- * Copyright (c) 2017-2024 Arm Limited. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -79,6 +81,10 @@
#define CORSTONE1000_HOST_AXI_QSPI_CTRL_REG_BASE_SE_SECURE_FLASH (0x90010000U) /* AXI QSPI Controller for SE FLash */
#define CORSTONE1000_HOST_DRAM_UEFI_CAPSULE (0xA0000000U) /* 1.5 GB DDR */
+#ifdef CORSTONE1000_DSU_120T
+#define CORSTONE1000_HOST_DSU_120T_BASE (0xC0910000U) /* DSU-120T PPU */
+#endif
+
/* Map Component definitions to Corstone definitions */
#define CC3XX_BASE_S CORSTONE1000_CRYPTO_ACCELERATOR_BASE
diff --git a/platform/ext/target/arm/corstone1000/bl1/boot_hal_bl1_1.c b/platform/ext/target/arm/corstone1000/bl1/boot_hal_bl1_1.c
index b51a233e9143..1a5e98ad3c35 100644
--- a/platform/ext/target/arm/corstone1000/bl1/boot_hal_bl1_1.c
+++ b/platform/ext/target/arm/corstone1000/bl1/boot_hal_bl1_1.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -48,6 +48,15 @@ REGION_DECLARE(Image$$, ARM_LIB_HEAP, $$ZI$$Limit)[];
#define HOST_SE_SECURE_FLASH_BASE_FVP 0x60010000
#define HOST_AXI_QSPI_CTRL_REG_BASE_SE_SECURE_FLASH 0x60010000
+#ifdef CORSTONE1000_DSU_120T
+#define HOST_DSU_120T_BASE 0x60910000
+#endif
+
+#ifdef CORSTONE1000_CORTEX_A320
+#define HOST_SECURE_SRAM_SIZE 0x400000
+#define HOST_NONSECURE_SRAM_BASE (HOST_TRUSTED_RAM_BASE + HOST_SECURE_SRAM_SIZE)
+#endif
+
#define HOST_DRAM_BASE 0x80000000
#define HOST_DRAM_UEFI_CAPSULE 0x80000000
@@ -286,6 +295,25 @@ static void setup_se_firewall(void)
fc_enable_regions();
#endif
+#ifdef CORSTONE1000_DSU_120T
+#if (PLATFORM_IS_FVP)
+ fc_select_region(7);
+ fc_disable_regions();
+ fc_disable_mpe(RGN_MPE0);
+ fc_prog_rgn(RGN_SIZE_16MB, CORSTONE1000_HOST_DSU_120T_BASE);
+ fc_prog_rgn_upper_addr(HOST_DSU_120T_BASE);
+ fc_enable_addr_trans();
+ fc_init_mpl(RGN_MPE0);
+
+ mpl_rights = (RGN_MPL_SECURE_READ_MASK |
+ RGN_MPL_SECURE_WRITE_MASK);
+
+ fc_enable_mpl(RGN_MPE0, mpl_rights);
+ fc_prog_mid(RGN_MPE0, SE_MID);
+ fc_enable_mpe(RGN_MPE0);
+ fc_enable_regions();
+#endif
+#endif
fc_pe_enable();
}
@@ -369,6 +397,26 @@ static void setup_host_firewall(void)
fc_enable_regions();
fc_rgn_lock();
+#ifdef CORSTONE1000_CORTEX_A320
+ /* CVM - Non Secure RAM */
+ fc_select_region(2);
+ fc_disable_regions();
+ fc_disable_mpe(RGN_MPE0);
+ fc_prog_rgn(RGN_SIZE_4MB, HOST_NONSECURE_SRAM_BASE);
+ fc_init_mpl(RGN_MPE0);
+
+ mpl_rights = (RGN_MPL_ANY_MST_MASK | RGN_MPL_NONSECURE_READ_MASK |
+ RGN_MPL_NONSECURE_WRITE_MASK |
+ RGN_MPL_NONSECURE_EXECUTE_MASK);
+
+ fc_enable_mpl(RGN_MPE0, mpl_rights);
+ fc_disable_mpl(RGN_MPE0, ~mpl_rights);
+
+ fc_enable_mpe(RGN_MPE0);
+ fc_enable_regions();
+ fc_rgn_lock();
+#endif
+
fc_pe_enable();
/* DDR */
diff --git a/platform/ext/target/arm/corstone1000/dsu-120t/ppu.c b/platform/ext/target/arm/corstone1000/dsu-120t/ppu.c
new file mode 100644
index 000000000000..d6be5982a8dd
--- /dev/null
+++ b/platform/ext/target/arm/corstone1000/dsu-120t/ppu.c
@@ -0,0 +1,40 @@
+/*
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include "ppu.h"
+
+void PPU_SetPowerPolicy(PPU_TypeDef *ppu, PPU_PowerPolicy_Type policy, bool isDynamic)
+{
+ uint32_t regval = ppu->PWPR;
+
+ regval &= ~(PPU_PWPR_PWR_POLICY_Msk | PPU_PWPR_PWR_DYN_EN_Msk);
+
+ regval |= ((policy << PPU_PWPR_PWR_POLICY_Pos) & PPU_PWPR_PWR_POLICY_Msk);
+
+ if (isDynamic) {
+ regval |= PPU_PWPR_PWR_DYN_EN_Msk;
+ }
+
+ ppu->PWPR = regval;
+}
+
+void PPU_SetOperatingPolicy(PPU_TypeDef *ppu, PPU_OperatingPolicy_Type policy, bool isDynamic)
+{
+ uint32_t regval = ppu->PWPR;
+
+ regval &= ~(PPU_PWPR_OP_POLICY_Msk | PPU_PWPR_OP_DYN_EN_Msk);
+
+ regval |= ((policy << PPU_PWPR_OP_POLICY_Pos) & PPU_PWPR_OP_POLICY_Msk);
+
+ if (isDynamic) {
+ regval |= PPU_PWPR_OP_DYN_EN_Msk;
+ }
+
+ ppu->PWPR = regval;
+}
+
diff --git a/platform/ext/target/arm/corstone1000/dsu-120t/ppu.h b/platform/ext/target/arm/corstone1000/dsu-120t/ppu.h
new file mode 100644
index 000000000000..05470df9a884
--- /dev/null
+++ b/platform/ext/target/arm/corstone1000/dsu-120t/ppu.h
@@ -0,0 +1,185 @@
+/*
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef PPU_H
+#define PPU_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform_base_address.h"
+
+// Bit definition for PPU_PWPR register
+#define PPU_PWPR_PWR_POLICY_Pos (0U) // Power mode policy
+#define PPU_PWPR_PWR_POLICY_Msk (0xFUL << PPU_PWPR_PWR_POLICY_Pos) // 4 bits
+#define PPU_PWPR_PWR_POLICY_OFF (0UL << PPU_PWPR_PWR_POLICY_Pos) // Logic off and RAM off.
+#define PPU_PWPR_PWR_POLICY_OFF_EMU (1UL << PPU_PWPR_PWR_POLICY_Pos) // Emulated Off. Logic on with RAM on. This mode is used to emulate the functional condition of OFF without removing
+#define PPU_PWPR_PWR_POLICY_MEM_RET (2UL << PPU_PWPR_PWR_POLICY_Pos) // Memory Retention. Logic off with RAM retained.
+#define PPU_PWPR_PWR_POLICY_MEM_RET_EMU (3UL << PPU_PWPR_PWR_POLICY_Pos) // Emulated Memory Retention. Logic on with RAM on. This mode is used to emulate the functional condition of
+#define PPU_PWPR_PWR_POLICY_FULL_RET (5UL << PPU_PWPR_PWR_POLICY_Pos) // Full Retention. Slice logic off with RAM contents retained.
+#define PPU_PWPR_PWR_POLICY_FUNC_RET (7UL << PPU_PWPR_PWR_POLICY_Pos) // Functional Retention. Logic on with L3 Cache and Snoop Filter retained.
+#define PPU_PWPR_PWR_POLICY_ON (8UL << PPU_PWPR_PWR_POLICY_Pos) // Logic on with RAM on, cluster is functional.
+#define PPU_PWPR_PWR_POLICY_WARM_RST (9UL << PPU_PWPR_PWR_POLICY_Pos) // Warm Reset. Warm reset application with logic and RAM on.
+#define PPU_PWPR_PWR_POLICY_DBG_RECOV (10UL << PPU_PWPR_PWR_POLICY_Pos) // Debug Recovery Reset. Warm reset application with logic and RAM on.
+#define PPU_PWPR_PWR_DYN_EN_Pos (8U) // Power mode dynamic transition enable.
+#define PPU_PWPR_PWR_DYN_EN_Msk (0x1UL << PPU_PWPR_PWR_DYN_EN_Pos) // 1 bit
+#define PPU_PWPR_LOCK_EN_Pos (12U) // Lock enable bit for OFF, OFF_EMU, MEM_RET and MEM_RET_EMU power modes.
+#define PPU_PWPR_LOCK_EN_Msk (0x1UL << PPU_PWPR_LOCK_EN_Pos) // 1 bit
+#define PPU_PWPR_OP_POLICY_Pos (16U) // Operating mode policy
+#define PPU_PWPR_OP_POLICY_Msk (0xFUL << PPU_PWPR_OP_POLICY_Pos) // 4 bits
+#define PPU_PWPR_OP_POLICY_OPMODE_00 (0UL << PPU_PWPR_OP_POLICY_Pos) // ONE_SLICE_SF_ONLY_ON: One L3 Cache slice is operational, the Cache RAM is powered down.
+#define PPU_PWPR_OP_POLICY_OPMODE_01 (1UL << PPU_PWPR_OP_POLICY_Pos) // ONE_SLICE_HALF_RAM_ON: One L3 Cache slice is operational, half of the Cache RAMs are powered on.
+#define PPU_PWPR_OP_POLICY_OPMODE_03 (3UL << PPU_PWPR_OP_POLICY_Pos) // ONE_SLICE_FULL_RAM_ON: One L3 Cache slice is operational, all of the Cache RAMs are powered on.
+#define PPU_PWPR_OP_POLICY_OPMODE_04 (4UL << PPU_PWPR_OP_POLICY_Pos) // ALL_SLICE_SF_ONLY_ON: All L3 Cache slices are operational, the Cache RAMs in each slice are powered down.
+#define PPU_PWPR_OP_POLICY_OPMODE_05 (5UL << PPU_PWPR_OP_POLICY_Pos) // ALL_SLICE_HALF_RAM_ON: All L3 Cache slices are operational, half of the Cache RAMs are powered on.
+#define PPU_PWPR_OP_POLICY_OPMODE_07 (7UL << PPU_PWPR_OP_POLICY_Pos) // ALL_SLICE_FULL_RAM_ON: All L3 Cache slices are operational, all of the Cache RAMs are powered on.
+#define PPU_PWPR_OP_POLICY_OPMODE_08 (8UL << PPU_PWPR_OP_POLICY_Pos) // HALF_SLICE_SF_ONLY_ON: Half L3 Cache slices are operational, the Cache RAMs in each slice are powered down.
+#define PPU_PWPR_OP_POLICY_OPMODE_09 (9UL << PPU_PWPR_OP_POLICY_Pos) // HALF_SLICE_HALF_RAM_ON: Half L3 Cache slices are operational, half of the Cache RAMs are powered on.
+#define PPU_PWPR_OP_POLICY_OPMODE_0B (11UL << PPU_PWPR_PWR_POLICY_Pos) // HALF_SLICE_FULL_RAM_ON: Half L3 Cache slices are operational, all of the Cache RAMs are powered on.
+#define PPU_PWPR_OP_DYN_EN_Pos (24U) // Operating mode dynamic transition enable.
+#define PPU_PWPR_OP_DYN_EN_Msk (0x1UL << PPU_PWPR_OP_DYN_EN_Pos) // 1 bit
+
+// Bit definition for PPU_PWSR register
+#define PPU_PWSR_PWR_STATUS_Pos (0U)
+#define PPU_PWSR_PWR_STATUS_Msk (0xFUL << PPU_PWSR_PWR_STATUS_Pos) // 4 bits
+#define PPU_PWSR_PWR_STATUS_OFF (0UL << PPU_PWSR_PWR_STATUS_Pos) // Logic off and RAM off.
+#define PPU_PWSR_PWR_STATUS_OFF_EMU (1UL << PPU_PWSR_PWR_STATUS_Pos) // Emulated Off. Logic on with RAM on. This mode is used to emulate the functional condition of OFF without removing
+#define PPU_PWSR_PWR_STATUS_MEM_RET (2UL << PPU_PWSR_PWR_STATUS_Pos) // Memory Retention. Logic off with RAM retained.
+#define PPU_PWSR_PWR_STATUS_MEM_RET_EMU (3UL << PPU_PWSR_PWR_STATUS_Pos) // Emulated Memory Retention. Logic on with RAM on. This mode is used to emulate the functional condition of
+#define PPU_PWSR_PWR_STATUS_FULL_RET (5UL << PPU_PWSR_PWR_STATUS_Pos) // Full Retention. Slice logic off with RAM contents retained.
+#define PPU_PWSR_PWR_STATUS_FUNC_RET (7UL << PPU_PWSR_PWR_STATUS_Pos) // Functional Retention. Logic on with L3 Cache and Snoop Filter retained.
+#define PPU_PWSR_PWR_STATUS_ON (8UL << PPU_PWSR_PWR_STATUS_Pos) // Logic on with RAM on, cluster is functional.
+#define PPU_PWSR_PWR_STATUS_WARM_RST (9UL << PPU_PWSR_PWR_STATUS_Pos) // Warm Reset. Warm reset application with logic and RAM on.
+#define PPU_PWSR_PWR_STATUS_DBG_RECOV (10UL << PPU_PWSR_PWR_STATUS_Pos) // Debug Recovery Reset. Warm reset application with logic and RAM on.
+#define PPU_PWSR_PWR_DYN_STATUS_Pos (8U) // Power mode dynamic transition enable.
+#define PPU_PWSR_PWR_DYN_STATUS_Msk (0x1UL << PPU_PWSR_PWR_DYN_STATUS_Pos) // 1 bit
+#define PPU_PWSR_LOCK_STATUS_Pos (12U) // Lock enable bit for OFF, OFF_EMU, MEM_RET and MEM_RET_EMU power modes.
+#define PPU_PWSR_LOCK_STATUS_Msk (0x1UL << PPU_PWSR_LOCK_STATUS_Pos) // 1 bit
+#define PPU_PWSR_OP_STATUS_Pos (16U) // Operating mode policy
+#define PPU_PWSR_OP_STATUS_Msk (0xFUL << PPU_PWSR_OP_STATUS_Pos) // 4 bits
+#define PPU_PWSR_OP_STATUS_OPMODE_00 (0UL << PPU_PWSR_OP_STATUS_Pos) // ONE_SLICE_SF_ONLY_ON: One L3 Cache slice is operational, only the snoop filter RAM instances are active in the slice
+#define PPU_PWSR_OP_STATUS_OPMODE_01 (1UL << PPU_PWSR_OP_STATUS_Pos) // ONE_SLICE_HALF_RAM_ON: One L3 Cache slice is operational, half of the Cache RAMs are powered on.
+#define PPU_PWSR_OP_STATUS_OPMODE_03 (3UL << PPU_PWSR_OP_STATUS_Pos) // ONE_SLICE_FULL_RAM_ON: One L3 Cache slice is operational, all of the Cache RAMs are powered on.
+#define PPU_PWSR_OP_STATUS_OPMODE_04 (4UL << PPU_PWSR_OP_STATUS_Pos) // ALL_SLICE_SF_ONLY_ON: All L3 Cache slices are operational, the Cache RAMs in each slice are powered down.
+#define PPU_PWSR_OP_STATUS_OPMODE_05 (5UL << PPU_PWSR_OP_STATUS_Pos) // ALL_SLICE_HALF_RAM_ON: All L3 Cache slices are operational, half of the Cache RAMs are powered on.
+#define PPU_PWSR_OP_STATUS_OPMODE_07 (7UL << PPU_PWSR_OP_STATUS_Pos) // ALL_SLICE_FULL_RAM_ON: All L3 Cache slices are operational, all of the Cache RAMs are powered on.
+#define PPU_PWSR_OP_STATUS_OPMODE_08 (8UL << PPU_PWSR_OP_STATUS_Pos) // HALF_SLICE_SF_ONLY_ON: Half L3 Cache slices are operational, the Cache RAMs in each slice are powered down.
+#define PPU_PWSR_OP_STATUS_OPMODE_09 (9UL << PPU_PWSR_OP_STATUS_Pos) // HALF_SLICE_HALF_RAM_ON: Half L3 Cache slices are operational, half of the Cache RAMs are powered on.
+#define PPU_PWSR_OP_STATUS_OPMODE_0B (11UL << PPU_PWSR_OP_STATUS_Pos) // HALF_SLICE_FULL_RAM_ON: Half L3 Cache slices are operational, all of the Cache RAMs are powered on.
+#define PPU_PWSR_OP_DYN_STATUS_Pos (24U) // Operating mode dynamic transition enable.
+#define PPU_PWSR_OP_DYN_STATUS_Msk (0x1UL << PPU_PWSR_OP_DYN_STATUS_Pos) // 1 bit
+
+/*!< PPU memory offsets */
+#define DSU_120T_CLUSTER_PPU_OFFSET 0x030000
+#define DSU_120T_CORE0_PPU_OFFSET 0x080000
+#define DSU_120T_CORE1_PPU_OFFSET 0x180000
+#define DSU_120T_CORE2_PPU_OFFSET 0x280000
+#define DSU_120T_CORE3_PPU_OFFSET 0x380000
+
+/*!< PPU memory map */
+#define CLUSTER_PPU_BASE (CORSTONE1000_HOST_DSU_120T_BASE + DSU_120T_CLUSTER_PPU_OFFSET)
+#define CORE0_PPU_BASE (CORSTONE1000_HOST_DSU_120T_BASE + DSU_120T_CORE0_PPU_OFFSET)
+#define CORE1_PPU_BASE (CORSTONE1000_HOST_DSU_120T_BASE + DSU_120T_CORE1_PPU_OFFSET)
+#define CORE2_PPU_BASE (CORSTONE1000_HOST_DSU_120T_BASE + DSU_120T_CORE2_PPU_OFFSET)
+#define CORE3_PPU_BASE (CORSTONE1000_HOST_DSU_120T_BASE + DSU_120T_CORE3_PPU_OFFSET)
+
+/*!< PPU declarations */
+#define CLUSTER_PPU ((PPU_TypeDef *) CLUSTER_PPU_BASE)
+#define CORE0_PPU ((PPU_TypeDef *) CORE0_PPU_BASE)
+#define CORE1_PPU ((PPU_TypeDef *) CORE1_PPU_BASE)
+#define CORE2_PPU ((PPU_TypeDef *) CORE2_PPU_BASE)
+#define CORE3_PPU ((PPU_TypeDef *) CORE3_PPU_BASE)
+
+typedef struct
+{
+ volatile uint32_t PWPR; /*!< PPU Power Policy Register, Address offset: 0x00 */
+ volatile uint32_t PMER; /*!< PPU Power Mode Emulation Enable Register, Address offset: 0x04 */
+ volatile uint32_t PWSR; /*!< PPU Power Status Register, Address offset: 0x08 */
+ volatile uint32_t RESERVED0; /*!< Reserved, Address offset: 0x0C */
+ volatile uint32_t DISR; /*!< PPU Device Interface Input Current Status Register, Address offset: 0x10 */
+ volatile uint32_t MISR; /*!< PPU Miscellaneous Input Current Status Register, Address offset: 0x14 */
+ volatile uint32_t STSR; /*!< PPU Stored Status Register, Address offset: 0x18 */
+ volatile uint32_t UNLK; /*!< PPU Unlock Register, Address offset: 0x1C */
+ volatile uint32_t PWCR; /*!< PPU Power Configuration Register, Address offset: 0x20 */
+ volatile uint32_t PTCR; /*!< PPU Power Mode Transition Register, Address offsets: 0x24 */
+ volatile uint32_t RESERVED1[2]; /*!< Reserved: Address offsets 0x28 - 0x2C */
+ volatile uint32_t IMR; /*!< PPU Interrupt Mask Register, Address offsets: 0x30 */
+ volatile uint32_t AIMR; /*!< PPU Additional Interrupt Mask Register, Address offsets: 0x34 */
+ volatile uint32_t ISR; /*!< PPU Interrupt Status Register, Address offsets: 0x38 */
+ volatile uint32_t AISR; /*!< PPU Additional Interrupt Status Register, Address offsets: 0x3C */
+ volatile uint32_t IESR; /*!< PPU Input Edge Sensitivity Register Address offsets: 0x040 */
+ volatile uint32_t OPSR; /*!< PPU Operating Mode Active Edge Sensitivity Register Address offsets: 0x044 */
+ volatile uint32_t RESERVED2[2]; /*!< Reserved: Address offsets 0x48 - 0x4C */
+ volatile uint32_t FUNRR; /*!< Functional Retention RAM Configuration Register Address offsets: 0x050 */
+ volatile uint32_t FULRR; /*!< Full Retention RAM Configuration Register Address offsets: 0x054 */
+ volatile uint32_t MEMRR; /*!< Memory Retention RAM Configuration Register Address offsets: 0x058 */
+ volatile uint32_t RESERVED3[69]; /*!< Reserved: Address offsets 0x5C - 0x16C */
+ volatile uint32_t DCDR0; /*!< Device Control Delay Configuration Register 0 Address offsets: 0x170 */
+ volatile uint32_t DCDR1; /*!< Device Control Delay Configuration Register 1 Address offsets: 0x174 */
+ volatile uint32_t RESERVED4[910]; /*!< Reserved, offsets 0x178 - 0xFAC */
+ volatile uint32_t IDR0; /*!< PPU Identification Register 0, Address offsets: 0xFB0 */
+ volatile uint32_t IDR1; /*!< PPU Identification Register 1, Address offsets: 0xFB4 */
+ volatile uint32_t RESERVED5[4]; /*!< Reserved, offsets 0xFB8 - 0xFC4 */
+ volatile uint32_t IIDR; /*!< PPU Implementation Identification Register, Address offsets: 0xFC8 */
+ volatile uint32_t AIDR; /*!< PPU Architecture Identification Register, Address offsets: 0xFCC */
+ volatile uint32_t PIDR4; /*!< PPU Peripheral Identification Register 4, Address offsets: 0xFD0 */
+ volatile uint32_t PIDR5; /*!< PPU Peripheral Identification Register 5, Address offsets: 0xFD4 */
+ volatile uint32_t PIDR6; /*!< PPU Peripheral Identification Register 6, Address offsets: 0xFD8 */
+ volatile uint32_t PIDR7; /*!< PPU Peripheral Identification Register 7, Address offsets: 0xFDC */
+ volatile uint32_t PIDR0; /*!< PPU Peripheral Identification Register 0, Address offsets: 0xFE0 */
+ volatile uint32_t PIDR1; /*!< PPU Peripheral Identification Register 1, Address offsets: 0xFE4 */
+ volatile uint32_t PIDR2; /*!< PPU Peripheral Identification Register 2, Address offsets: 0xFE8 */
+ volatile uint32_t PIDR3; /*!< PPU Peripheral Identification Register 3, Address offsets: 0xFEC */
+ volatile uint32_t CIDR0; /*!< PPU Component Identification Register 0, Address offsets: 0xFF0 */
+ volatile uint32_t CIDR1; /*!< PPU Component Identification Register 1, Address offsets: 0xFF4 */
+ volatile uint32_t CIDR2; /*!< PPU Component Identification Register 2, Address offsets: 0xFF8 */
+ volatile uint32_t CIDR3; /*!< PPU Component Identification Register 3, Address offsets: 0xFFC */
+} PPU_TypeDef;
+
+typedef enum {
+ PPU_PWR_MODE_OFF = 0, // Logic off and RAM off.
+ PPU_PWR_MODE_OFF_EMU = 1, // Emulated Off. Logic on with RAM on. This mode is used to emulate the functional condition of OFF without removing
+ PPU_PWR_MODE_MEM_RET = 2, // Memory Retention. Logic off with RAM retained.
+ PPU_PWR_MODE_MEM_RET_EMU = 3, // Emulated Memory Retention. Logic on with RAM on. This mode is used to emulate the functional condition of
+ PPU_PWR_MODE_FULL_RET = 5, // Full Retention. Slice logic off with RAM contents retained.
+ PPU_PWR_MODE_FUNC_RET = 7, // Functional Retention. Logic on with L3 Cache and Snoop Filter retained.
+ PPU_PWR_MODE_ON = 8, // Logic on with RAM on, cluster is functional.
+ PPU_PWR_MODE_WARM_RST = 9, // Warm Reset. Warm reset application with logic and RAM on.
+ PPU_PWR_MODE_DBG_RECOV = 10 // Debug Recovery Reset. Warm reset application with logic and RAM on.
+} PPU_PowerPolicy_Type;
+
+typedef enum {
+ PPU_OP_MODE_ONE_SLICE_SF_ONLY_ON = 0, // One L3 Cache slice is operational, only the snoop filter RAM instances are active in the slice
+ PPU_OP_MODE_ONE_SLICE_HALF_RAM_ON = 1, // One L3 Cache slice is operational, half of the Cache RAMs are powered on.
+ PPU_OP_MODE_ONE_SLICE_FULL_RAM_ON = 3, // One L3 Cache slice is operational, all of the Cache RAMs are powered on.
+ PPU_OP_MODE_ALL_SLICE_SF_ONLY_ON = 4, // All L3 Cache slices are operational, the Cache RAMs in each slice are powered down.
+ PPU_OP_MODE_ALL_SLICE_HALF_RAM_ON = 5, // All L3 Cache slices are operational, half of the Cache RAMs are powered on.
+ PPU_OP_MODE_ALL_SLICE_FULL_RAM_ON = 7, // All L3 Cache slices are operational, all of the Cache RAMs are powered on.
+ PPU_OP_MODE_HALF_SLICE_SF_ONLY_ON = 8, // Half L3 Cache slices are operational, the Cache RAMs in each slice are powered down.
+ PPU_OP_MODE_HALF_SLICE_HALF_RAM_ON = 9, // Half L3 Cache slices are operational, half of the Cache RAMs are powered on.
+ PPU_OP_MODE_HALF_SLICE_FULL_RAM_ON = 11 // Half L3 Cache slices are operational, all of the Cache RAMs are powered on.
+} PPU_OperatingPolicy_Type;
+
+/**
+ * @brief Set the power policy for a given PPU instance.
+ * Only modifies PWR_POLICY and PWR_DYN_EN bits.
+ * @param ppu: Pointer to the PPU instance (e.g., CLUSTER_PPU, CORE0_PPU1)
+ * @param policy: Power mode policy (e.g., PPU_PWR_MODE_ON)
+ * @param dynamic: Enable dynamic transitions enabled for power modes, allowing transitions to be initiated by changes on power mode DEVACTIVE inputs if non-zero
+ * @retval None
+ */
+void PPU_SetPowerPolicy(PPU_TypeDef *ppu, PPU_PowerPolicy_Type policy, bool isDynamic);
+
+/**
+ * @brief Set the operating mode policy for a given PPU instance.
+* Only modifies OP_POLICY and OP_DYN_EN bits.
+ * @param ppu: Pointer to the PPU instance (e.g., CLUSTER_PPU, CORE0_PPU)
+ * @param policy: Operating mode policy (e.g., PPU_OP_MODE_ONE_SLICE_SF_ONLY_ON)
+ * @param dynamic: Enable dynamic transitions enabled for operating modes, allowing transitions to be initiated by changes on operating mode DEVACTIVE inputs if non-zero
+ * @retval None
+ */
+void PPU_SetOperatingPolicy(PPU_TypeDef *ppu, PPU_OperatingPolicy_Type policy, bool isDynamic);
+
+#endif /* PPU_H */
diff --git a/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c b/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
index d0c6b8d590f9..10c66ac41ad2 100644
--- a/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
+++ b/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2024 Arm Limited. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -11,6 +11,10 @@
#include "tfm_hal_multi_core.h"
#include "fwu_agent.h"
+#ifdef CORSTONE1000_DSU_120T
+#include "ppu.h"
+#endif
+
#define HOST_SYS_RST_CTRL_OFFSET 0x000
#define HOST_CPU_PE0_CONFIG_OFFSET 0x010
#define HOST_CPU_PE1_CONFIG_OFFSET 0x020
@@ -98,6 +102,28 @@ void tfm_hal_boot_ns_cpu(uintptr_t start_addr)
(void) start_addr;
+#ifdef CORSTONE1000_DSU_120T
+ /* Power on DSU-120T cluster */
+ PPU_SetOperatingPolicy(CLUSTER_PPU, PPU_OP_MODE_ONE_SLICE_SF_ONLY_ON, false);
+ PPU_SetPowerPolicy(CLUSTER_PPU, PPU_PWR_MODE_ON, false);
+
+ /* Power on Cortex-A320 core0 in DSU-120T Cluster */
+ PPU_SetOperatingPolicy(CORE0_PPU, PPU_OP_MODE_ONE_SLICE_SF_ONLY_ON, false);
+ PPU_SetPowerPolicy(CORE0_PPU, PPU_PWR_MODE_ON, false);
+
+#if CORSTONE1000_FVP_MULTICORE
+ /* Power on all Cortex-A320 cores in DSU-120T Cluster */
+ PPU_SetOperatingPolicy(CORE1_PPU, PPU_OP_MODE_ONE_SLICE_SF_ONLY_ON, false);
+ PPU_SetPowerPolicy(CORE1_PPU, PPU_PWR_MODE_ON, false);
+
+ PPU_SetOperatingPolicy(CORE2_PPU, PPU_OP_MODE_ONE_SLICE_SF_ONLY_ON, false);
+ PPU_SetPowerPolicy(CORE2_PPU, PPU_PWR_MODE_ON, false);
+
+ PPU_SetOperatingPolicy(CORE3_PPU, PPU_OP_MODE_ONE_SLICE_SF_ONLY_ON, false);
+ PPU_SetPowerPolicy(CORE3_PPU, PPU_PWR_MODE_ON, false);
+#endif
+#endif
+
#ifdef EXTERNAL_SYSTEM_SUPPORT
/*release EXT SYS out of reset*/
tfm_external_system_boot();
@@ -0,0 +1,48 @@
From 3a9e209596ca0ae5850ae382c624adf9932b16b4 Mon Sep 17 00:00:00 2001
From: Devaraj Ranganna <devaraj.ranganna@arm.com>
Date: Mon, 22 Sep 2025 12:48:57 +0100
Subject: [PATCH] bl2: corstone-1000: Remove
`psa_adac_to_tfm_apply_permissions`
The API `psa_adac_to_tfm_apply_permissions` is added to `psa-adac`
library. Therefore, remove it from
`platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c`.
Upstream-Status: Pending [Not submitted to upstream yet]
Signed-off-by: Devaraj Ranganna <devaraj.ranganna@arm.com>
---
.../arm/corstone1000/bl2/boot_hal_bl2.c | 21 -------------------
1 file changed, 21 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c b/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c
index 2abcfb5fd39d..8c4eb80d032c 100644
--- a/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c
+++ b/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c
@@ -111,27 +111,6 @@ static bool fill_flash_map_with_fip_data(uint8_t boot_index) {
#endif /* !TFM_S_REG_TEST */
#ifdef PLATFORM_PSA_ADAC_SECURE_DEBUG
-int psa_adac_to_tfm_apply_permissions(uint8_t permissions_mask[16])
-{
- (void)permissions_mask;
-
- int ret;
- uint32_t dcu_reg_values[4];
-
- /* Below values provide same access as when platform is in development
- life cycle state */
- dcu_reg_values[0] = 0xffffe7fc;
- dcu_reg_values[1] = 0x800703ff;
- dcu_reg_values[2] = 0xffffffff;
- dcu_reg_values[3] = 0xffffffff;
-
- ret = crypto_hw_apply_debug_permissions((uint8_t*)dcu_reg_values, 16);
- BOOT_LOG_INF("%s: debug permission apply %s\n\r", __func__,
- (ret == 0) ? "success" : "fail");
-
- return ret;
-}
-
uint8_t secure_debug_rotpk[32];
#endif /* PLATFORM_PSA_ADAC_SECURE_DEBUG */
@@ -0,0 +1,53 @@
From 901a63f09369cfbed8eff8c450b8615bd4c361af Mon Sep 17 00:00:00 2001
From: Devaraj Ranganna <devaraj.ranganna@arm.com>
Date: Mon, 22 Sep 2025 12:59:43 +0100
Subject: [PATCH] bl2: corstone-1000: secure debug waiting in CM LCS
Currently, when the device is in Secure Enable (SE) LCS state, setting
`dcu_en` register causes CC-312 reset, which effectively resets the
device as they are both on same power domain. Therefore, temporarily
disable moving SE enable before waiting for secure debug notification.
The device will be in CM provisioned state.
Long-term solution is to implement a solution similar to RSE, secure
debug handshake is completed and then a reset is triggered and `dcu_en`
is applied during bl2.
Upstream-Status: Inappropriate [Need to be redesigned]
Signed-off-by: Devaraj Ranganna <devaraj.ranganna@arm.com>
---
.../ext/target/arm/corstone1000/bl2/boot_hal_bl2.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c b/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c
index 8c4eb80d032c..bf7b62881ad5 100644
--- a/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c
+++ b/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c
@@ -165,7 +165,18 @@ int32_t boot_platform_post_init(void)
}
#ifdef PLATFORM_PSA_ADAC_SECURE_DEBUG
+ /* TODO: Currently, when the device is in Secure Enable (SE) LCS state,
+ setting `dcu_en` register causes CC-312 reset, which effectively resets
+ the device as they are both on same power domain. Therefore, temporarily
+ disable moving SE enable before waiting for secure debug notification.
+ The device will be in CM provisioned state.
+
+ Long-term solution is to implement a solution similar to RSE, secure
+ debug handshake is completed and then a reset is triggered and `dcu_en`
+ is applied during bl2.
+
if (!tfm_plat_provisioning_is_required()) {
+ */
plat_err = tfm_plat_otp_read(PLAT_OTP_ID_SECURE_DEBUG_PK, 32, secure_debug_rotpk);
if (plat_err != TFM_PLAT_ERR_SUCCESS) {
@@ -176,7 +187,7 @@ int32_t boot_platform_post_init(void)
BOOT_LOG_INF("%s: Corstone-1000 Secure Debug is a %s.\r\n", __func__,
(result == 0) ? "success" : "failure");
- }
+ /*}*/
#endif
return 0;
@@ -0,0 +1,147 @@
From 14fff6df016dad1d76f1eda6f77dde1890836c3c Mon Sep 17 00:00:00 2001
From: Anton Komlev <anton.komlev@arm.com>
Date: Thu, 11 Sep 2025 17:16:43 +0100
Subject: [PATCH] Build: adjust CS1000 platform for GCC v14.2
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The latest GNUARM toolchain is more strict, converting some warnings
into errors. This change:
- adds missing function prototypes and header files
- explicitly typecasts incompatible types in secure side
- prevents integer–pointer conversion errors in
`tfm_test_suite_extra_s` CMake targets because a number of type
mismatch is too high.
Signed-off-by: Anton Komlev <anton.komlev@arm.com>
Change-Id: Ia803ebd5ceeab03ab7c7afc7c79c4e5836e03b26
Upstream-Status: Backport [05c174df157eac428a3e87a1c40170ed7a74af57]
Signed-off-by: Jon Mason <jon.mason@arm.com>
---
.../ext/target/arm/corstone1000/bl1/boot_hal_bl1_2.c | 1 +
.../corstone1000/ci_regression_tests/CMakeLists.txt | 2 ++
platform/ext/target/arm/corstone1000/io/io_block.c | 1 +
platform/ext/target/arm/corstone1000/io/io_flash.c | 10 +++++-----
platform/ext/target/arm/corstone1000/platform.c | 8 ++++----
.../target/arm/corstone1000/rse_comms/rse_comms_hal.h | 2 ++
6 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bl1/boot_hal_bl1_2.c b/platform/ext/target/arm/corstone1000/bl1/boot_hal_bl1_2.c
index 8d85d2b2c9b8..b81e14e03aa9 100644
--- a/platform/ext/target/arm/corstone1000/bl1/boot_hal_bl1_2.c
+++ b/platform/ext/target/arm/corstone1000/bl1/boot_hal_bl1_2.c
@@ -21,6 +21,7 @@
#include "uart_stdout.h"
#include "region_defs.h"
#include "tfm_log.h"
+#include "cc3xx_init.h"
#ifdef CRYPTO_HW_ACCELERATOR
#include "cc3xx_dev.h"
diff --git a/platform/ext/target/arm/corstone1000/ci_regression_tests/CMakeLists.txt b/platform/ext/target/arm/corstone1000/ci_regression_tests/CMakeLists.txt
index 405b2b370237..3b023c813e02 100644
--- a/platform/ext/target/arm/corstone1000/ci_regression_tests/CMakeLists.txt
+++ b/platform/ext/target/arm/corstone1000/ci_regression_tests/CMakeLists.txt
@@ -44,3 +44,5 @@ target_compile_definitions(tfm_test_suite_extra_s
TEST_FLASH_PAGE_SIZE=${TEST_FLASH_PAGE_SIZE}
TEST_FLASH_PROGRAM_UNIT=${TEST_FLASH_PROGRAM_UNIT}
)
+
+target_compile_options(tfm_test_suite_extra_s PRIVATE -Wno-int-conversion)
diff --git a/platform/ext/target/arm/corstone1000/io/io_block.c b/platform/ext/target/arm/corstone1000/io/io_block.c
index f7eaf7444c38..a5c021ac5a18 100644
--- a/platform/ext/target/arm/corstone1000/io/io_block.c
+++ b/platform/ext/target/arm/corstone1000/io/io_block.c
@@ -20,6 +20,7 @@
#include <assert.h>
#include <errno.h>
+#include <string.h>
#include "io_defs.h"
#include "io_driver.h"
diff --git a/platform/ext/target/arm/corstone1000/io/io_flash.c b/platform/ext/target/arm/corstone1000/io/io_flash.c
index ff4524e9c575..b90a81a48d82 100644
--- a/platform/ext/target/arm/corstone1000/io/io_flash.c
+++ b/platform/ext/target/arm/corstone1000/io/io_flash.c
@@ -71,7 +71,7 @@ static size_t flash_read(int lba, uintptr_t buf, size_t size, size_t flash_id) {
size_t rem = info->sector_count * info->sector_size - offset;
size_t cnt = size < rem ? size : rem;
- return flash_driver->ReadData(offset, buf, cnt);
+ return flash_driver->ReadData(offset, (void *)buf, cnt);
}
static size_t flash_write(int lba, const uintptr_t buf, size_t size,
@@ -86,7 +86,7 @@ static size_t flash_write(int lba, const uintptr_t buf, size_t size,
size_t cnt = size < rem ? size : rem;
flash_driver->EraseSector(offset);
- rc = flash_driver->ProgramData(offset, buf, cnt);
+ rc = flash_driver->ProgramData(offset, (const void *)buf, cnt);
return rc;
}
@@ -143,8 +143,8 @@ static int flash_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) {
/* Check if Flash ops functions are defined for this flash */
assert(flashs_ops[index].read && flashs_ops[index].write);
- flash_dev_specs[index] = dev_spec;
- flash_driver = flash_dev_specs[index]->flash_driver;
+ flash_dev_specs[index] = (io_flash_dev_spec_t *)dev_spec;
+ flash_driver = (const ARM_DRIVER_FLASH *)flash_dev_specs[index]->flash_driver;
block_dev_spec[index].block_size = flash_driver->GetInfo()->sector_size;
block_dev_spec[index].buffer.offset = flash_dev_specs[index]->buffer;
@@ -153,7 +153,7 @@ static int flash_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) {
flash_driver->Initialize(NULL);
- block_dev_connectors[index].dev_open(&block_dev_spec[index], dev_info);
+ block_dev_connectors[index].dev_open((uintptr_t)&block_dev_spec[index], dev_info);
return 0;
}
diff --git a/platform/ext/target/arm/corstone1000/platform.c b/platform/ext/target/arm/corstone1000/platform.c
index c686b403ff10..d0f30b72a76d 100644
--- a/platform/ext/target/arm/corstone1000/platform.c
+++ b/platform/ext/target/arm/corstone1000/platform.c
@@ -29,10 +29,10 @@ extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
static io_dev_connector_t *flash_dev_con;
static uint8_t local_block_flash[FLASH_SECTOR_SIZE];
static io_flash_dev_spec_t flash_dev_spec = {
- .buffer = local_block_flash,
+ .buffer = (uintptr_t)local_block_flash,
.bufferlen = FLASH_SECTOR_SIZE,
.base_addr = FLASH_BASE_ADDRESS,
- .flash_driver = &FLASH_DEV_NAME,
+ .flash_driver = (uintptr_t)&FLASH_DEV_NAME,
};
static io_block_spec_t flash_spec = {
.offset = FLASH_BASE_ADDRESS,
@@ -41,8 +41,8 @@ static io_block_spec_t flash_spec = {
static platform_image_source_t platform_image_source[] = {
[PLATFORM_GPT_IMAGE] = {
- .dev_handle = NULL,
- .image_spec = &flash_spec,
+ .dev_handle = (uintptr_t)NULL,
+ .image_spec = (uintptr_t)&flash_spec,
}
};
diff --git a/platform/ext/target/arm/corstone1000/rse_comms/rse_comms_hal.h b/platform/ext/target/arm/corstone1000/rse_comms/rse_comms_hal.h
index c4676cb2ef74..29be08ddb36e 100644
--- a/platform/ext/target/arm/corstone1000/rse_comms/rse_comms_hal.h
+++ b/platform/ext/target/arm/corstone1000/rse_comms/rse_comms_hal.h
@@ -49,6 +49,8 @@ enum tfm_plat_err_t tfm_multi_core_hal_receive(void *mhu_receiver_dev,
*/
enum tfm_plat_err_t tfm_multi_core_hal_reply(struct client_request_t *req);
+int32_t tfm_hal_client_id_translate(void *owner, int32_t client_id_in);
+
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,48 @@
From 949ecbcd29660225f42bdfc37bdff4b79917620a Mon Sep 17 00:00:00 2001
From: Jon Mason <jon.mason@arm.com>
Date: Mon, 23 Feb 2026 11:53:38 -0500
Subject: [PATCH] Workaround compile errors in AES
TF-M commit d7c4850d8ce3abeb2634e85631b4bbadeb343f23 removes support for
bl1_aes_256_ctr_decrypt() API. Since backporting that is more involved
than we want for this release. Simply do some casting to address the
issues until the next release (which will have the commit referenced
previously).
Upstream-Status: Inappropriate
Signed-off-by: Jon Mason <jon.mason@arm.com>
---
platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c b/platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c
index 542fc01bc7a8..5b34d90464eb 100644
--- a/platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c
+++ b/platform/ext/target/arm/corstone1000/bl1/cc312_rom_crypto.c
@@ -328,7 +328,7 @@ fih_int bl1_aes_256_ctr_decrypt(enum tfm_bl1_key_id_t key_id,
uint32_t key_buf[32 / sizeof(uint32_t)];
fih_int fih_rc;
int32_t rc = 0;
- const uint8_t *input_key = key_buf;
+ const uint8_t *input_key = (const uint8_t *)key_buf;
cc3xx_err_t err;
if (ciphertext_length == 0) {
@@ -356,7 +356,7 @@ fih_int bl1_aes_256_ctr_decrypt(enum tfm_bl1_key_id_t key_id,
}
err = cc3xx_lowlevel_aes_init(CC3XX_AES_DIRECTION_DECRYPT, CC3XX_AES_MODE_CTR,
- cc3xx_key_type, input_key, CC3XX_AES_KEYSIZE_256,
+ cc3xx_key_type, (const uint32_t *)input_key, CC3XX_AES_KEYSIZE_256,
(uint32_t *)counter, 16);
fih_rc = fih_int_encode_zero_equality(err);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
@@ -388,7 +388,7 @@ static int32_t aes_256_ecb_encrypt(enum tfm_bl1_key_id_t key_id,
return -1;
}
- rc = bl1_key_to_cc3xx_key(key_id, &cc3xx_key_type, key_buf, sizeof(key_buf));
+ rc = bl1_key_to_cc3xx_key(key_id, &cc3xx_key_type, (uint8_t *)key_buf, sizeof(key_buf));
if (rc) {
return rc;
}
@@ -0,0 +1,41 @@
From 3d2bdf81fee8832101fe47b633af5bdee251531a Mon Sep 17 00:00:00 2001
From: Michael Safwat <michael.safwat@arm.com>
Date: Fri, 13 Mar 2026 12:42:09 +0000
Subject: [PATCH] CC312: Add barrier before first AO lock write
On Corstone-1000 MPS3 with GCC 15.x, TF-M can HardFault in
CC_LibInit() on the first HOST_AO_LOCK_BITS write.
Add a compiler barrier before that write to keep the fix minimal and
local to the affected sequence.
Signed-off-by: Michael Safwat <michael.safwat@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49269]
---
lib/ext/cryptocell-312-runtime/host/src/cc3x_lib/cc_lib.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/ext/cryptocell-312-runtime/host/src/cc3x_lib/cc_lib.c b/lib/ext/cryptocell-312-runtime/host/src/cc3x_lib/cc_lib.c
index 4b08c02526..1e96fcac5b 100644
--- a/lib/ext/cryptocell-312-runtime/host/src/cc3x_lib/cc_lib.c
+++ b/lib/ext/cryptocell-312-runtime/host/src/cc3x_lib/cc_lib.c
@@ -33,6 +33,8 @@
#include "cc_rnd_common.h"
#include "cc_int_general_defs.h"
+#define CC_COMPILER_BARRIER() __asm volatile("" ::: "memory")
+
CC_PalMutex CCSymCryptoMutex;
CC_PalMutex CCAsymCryptoMutex;
CC_PalMutex *pCCRndCryptoMutex;
@@ -213,6 +215,7 @@ CClibRetCode_t CC_LibInit(CCRndContext_t *rndContext_ptr, CCRndWorkBuff_t *rndW
/* turn off the DFA since Cerberus doen't support it */
reg = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_AO_LOCK_BITS));
CC_REG_FLD_SET(0, HOST_AO_LOCK_BITS, HOST_FORCE_DFA_ENABLE, reg, 0x0);
+ CC_COMPILER_BARRIER();
CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_AO_LOCK_BITS) ,reg );
tempVal = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF,HOST_AO_LOCK_BITS));
if(tempVal != reg) {
--
2.43.0
@@ -1,32 +0,0 @@
From 9edcdd272a7d2d872f7e04b3a9db5185fd24fd97 Mon Sep 17 00:00:00 2001
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
Date: Tue, 28 Apr 2026 08:57:06 +0100
Subject: [PATCH] platform: corstone1000: Increase FIP partition size
Increase the FIP partition size from 2MB to 2.5MB in the
Corstone-1000 flash layout.
The previous size is insufficient for current FIP images,
which may lead to overflow during image generation or
deployment. Expanding the partition ensures adequate
space for firmware components packaged in the FIP.
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/50628]
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
platform/ext/target/arm/corstone1000/partition/flash_layout.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/platform/ext/target/arm/corstone1000/partition/flash_layout.h b/platform/ext/target/arm/corstone1000/partition/flash_layout.h
index e2219d80a..b7282beb2 100644
--- a/platform/ext/target/arm/corstone1000/partition/flash_layout.h
+++ b/platform/ext/target/arm/corstone1000/partition/flash_layout.h
@@ -139,7 +139,7 @@
#define TFM_PARTITION_SIZE (0x50000) /* 320 KB */
#define TFM_PARTITION_BANK_OFFSET (SE_BL2_PARTITION_SIZE)
-#define FIP_PARTITION_SIZE (0x200000) /* 2 MB */
+#define FIP_PARTITION_SIZE (0x280000) /* 2.5 MB */
#define FIP_PARTITION_BANK_OFFSET (TFM_PARTITION_BANK_OFFSET + TFM_PARTITION_SIZE)
#define INITRAMFS_PARTITION_SIZE (0xC00000) /* 12 MB */
@@ -0,0 +1,90 @@
From 9f86d644aa23589e5187f0a22394438cd525d574 Mon Sep 17 00:00:00 2001
From: Alex Chapman <alex.chapman@arm.com>
Date: Wed, 4 Mar 2026 13:41:59 +0000
Subject: [PATCH] Platform: CS1K: make mutlicore support platform generic
To improve portability, testing coverage, and future platform enablement.
- Replace FVP-only multicore checks with platform-generic checks.
Upstream-Status: Backport [71619253e03cc10cdd4527ab7e896e3ec10afabe]
Signed-off-by: Alex Chapman <alex.chapman@arm.com>
---
platform/ext/target/arm/corstone1000/CMakeLists.txt | 4 +---
.../target/arm/corstone1000/Device/Config/device_cfg.h | 2 +-
platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c | 8 ++++----
3 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/CMakeLists.txt b/platform/ext/target/arm/corstone1000/CMakeLists.txt
index 993c51591..a13f16fd7 100644
--- a/platform/ext/target/arm/corstone1000/CMakeLists.txt
+++ b/platform/ext/target/arm/corstone1000/CMakeLists.txt
@@ -407,12 +407,10 @@ target_sources(tfm_psa_rot_partition_ns_agent_mailbox
tfm_hal_multi_core.c
)
-if (PLATFORM_IS_FVP)
target_compile_definitions(tfm_psa_rot_partition_ns_agent_mailbox
PUBLIC
- $<$<BOOL:${ENABLE_MULTICORE}>:CORSTONE1000_FVP_MULTICORE>
+ $<$<BOOL:${ENABLE_MULTICORE}>:CORSTONE1000_MULTICORE>
)
-endif()
#========================= tfm_spm ============================================#
target_sources(tfm_spm
diff --git a/platform/ext/target/arm/corstone1000/Device/Config/device_cfg.h b/platform/ext/target/arm/corstone1000/Device/Config/device_cfg.h
index 544475a86..0c3a9088e 100644
--- a/platform/ext/target/arm/corstone1000/Device/Config/device_cfg.h
+++ b/platform/ext/target/arm/corstone1000/Device/Config/device_cfg.h
@@ -46,7 +46,7 @@
#define CFI_S
/* Total number of host cores */
-#if CORSTONE1000_FVP_MULTICORE
+#if CORSTONE1000_MULTICORE
#define PLATFORM_HOST_MAX_CORE_COUNT 4
#else
#define PLATFORM_HOST_MAX_CORE_COUNT 1
diff --git a/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c b/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
index 10c66ac41..9a785bfa0 100644
--- a/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
+++ b/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
@@ -62,7 +62,7 @@ void tfm_hal_boot_ns_cpu(uintptr_t start_addr)
volatile uint32_t *PE0_CONFIG =
(uint32_t *)(CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE
+ HOST_CPU_PE0_CONFIG_OFFSET);
-#if CORSTONE1000_FVP_MULTICORE
+#if CORSTONE1000_MULTICORE
volatile uint32_t *PE1_CONFIG =
(uint32_t *)(CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE
+ HOST_CPU_PE1_CONFIG_OFFSET);
@@ -80,7 +80,7 @@ void tfm_hal_boot_ns_cpu(uintptr_t start_addr)
#endif
/* Select host CPU architecture as AArch64 */
*PE0_CONFIG |= AA64nAA32_MASK; /* 0b1 – AArch64 */
-#if CORSTONE1000_FVP_MULTICORE
+#if CORSTONE1000_MULTICORE
*PE1_CONFIG |= AA64nAA32_MASK; /* 0b1 – AArch64 */
*PE2_CONFIG |= AA64nAA32_MASK; /* 0b1 – AArch64 */
*PE3_CONFIG |= AA64nAA32_MASK; /* 0b1 – AArch64 */
@@ -92,7 +92,7 @@ void tfm_hal_boot_ns_cpu(uintptr_t start_addr)
/* Clear HOST_SYS_RST_CTRL register to bring host out of RESET */
*reset_ctl_reg = 0;
-#if CORSTONE1000_FVP_MULTICORE
+#if CORSTONE1000_MULTICORE
/* Wake up secondary cores.
* This should be done after bringing the primary core out of reset.*/
for (int core_index=1; core_index < PLATFORM_HOST_MAX_CORE_COUNT; core_index++) {
@@ -111,7 +111,7 @@ void tfm_hal_boot_ns_cpu(uintptr_t start_addr)
PPU_SetOperatingPolicy(CORE0_PPU, PPU_OP_MODE_ONE_SLICE_SF_ONLY_ON, false);
PPU_SetPowerPolicy(CORE0_PPU, PPU_PWR_MODE_ON, false);
-#if CORSTONE1000_FVP_MULTICORE
+#if CORSTONE1000_MULTICORE
/* Power on all Cortex-A320 cores in DSU-120T Cluster */
PPU_SetOperatingPolicy(CORE1_PPU, PPU_OP_MODE_ONE_SLICE_SF_ONLY_ON, false);
PPU_SetPowerPolicy(CORE1_PPU, PPU_PWR_MODE_ON, false);
--
2.43.0
@@ -1,68 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ahmed Gomaa <ahmed.gomaa@arm.com>
Date: Wed, 2 Sep 2026 12:00:00 +0100
Subject: [PATCH] platform: corstone1000: keep CM during secure debug
Add a temporary Corstone-1000 Secure Debug workaround that skips runtime
TF-M provisioning when Secure Debug is enabled. This keeps the device in
the CM lifecycle state and avoids the provisioning reset, allowing the
authenticated debug session to remain active.
Keep this workaround until a reset-safe architecture is implemented to
preserve the authenticated DCU_EN value across reset and apply it from BL2.
Upstream-Status: Inappropriate [temporary platform workaround]
Signed-off-by: Ahmed Gomaa <ahmed.gomaa@arm.com>
---
secure_fw/spm/CMakeLists.txt | 1 +
secure_fw/spm/core/main.c | 10 ++++++++++
2 files changed, 11 insertions(+)
diff --git a/secure_fw/spm/CMakeLists.txt b/secure_fw/spm/CMakeLists.txt
--- a/secure_fw/spm/CMakeLists.txt
+++ b/secure_fw/spm/CMakeLists.txt
@@ -111,6 +111,7 @@ target_compile_definitions(tfm_spm
$<$<STREQUAL:${CONFIG_TFM_BRANCH_PROTECTION_FEAT},BRANCH_PROTECTION_PACRET_LEAF>:BRANCH_PROTECTION_CONTROL=2>
$<$<STREQUAL:${CONFIG_TFM_BRANCH_PROTECTION_FEAT},BRANCH_PROTECTION_BTI>:BRANCH_PROTECTION_CONTROL=3>
$<$<BOOL:${PLATFORM_PSA_ADAC_SECURE_DEBUG}>:PLATFORM_PSA_ADAC_SECURE_DEBUG>
+ $<$<BOOL:${CORSTONE1000_SKIP_PROVISIONING_FOR_DEBUG}>:CORSTONE1000_SKIP_PROVISIONING_FOR_DEBUG>
$<$<BOOL:${CONFIG_TFM_REUSE_COPY_AREA_FOR_SP_STACKS}>:CONFIG_TFM_REUSE_COPY_AREA_FOR_SP_STACKS>
$<$<BOOL:${TFM_TZ_REENTRANCY_CHECK}>:TFM_TZ_REENTRANCY_CHECK>
)
diff --git a/secure_fw/spm/core/main.c b/secure_fw/spm/core/main.c
--- a/secure_fw/spm/core/main.c
+++ b/secure_fw/spm/core/main.c
@@ -31,7 +31,9 @@ static fih_ret tfm_core_init(void)
{
enum tfm_plat_err_t plat_err = TFM_PLAT_ERR_SYSTEM_ERR;
FIH_DECLARE(fih_rc, FIH_FAILURE);
+#ifndef CORSTONE1000_SKIP_PROVISIONING_FOR_DEBUG
bool provisioning_required;
+#endif
/*
* Access to any peripheral should be performed after programming
@@ -65,6 +67,7 @@ static fih_ret tfm_core_init(void)
FIH_RET(SPM_ERROR_GENERIC);
}
+#ifndef CORSTONE1000_SKIP_PROVISIONING_FOR_DEBUG
/* Perform provisioning. */
plat_err = tfm_plat_provisioning_is_required(&provisioning_required);
if (plat_err != TFM_PLAT_ERR_SUCCESS) {
@@ -77,6 +80,12 @@ static fih_ret tfm_core_init(void)
FIH_RET(SPM_ERROR_GENERIC);
}
}
+#else
+ /* Temporary workaround: retain CM and avoid the provisioning reset. */
+ WARN("Skipping TF-M provisioning for Secure Debug workaround. "
+ "Device remains unprovisioned and must not be used in "
+ "production.\n");
+#endif
TFM_COVERITY_DEVIATE_LINE(MISRA_C_2023_Rule_2_2, "Parameters can be changed by user and this code will make effect")
tfm_plat_provisioning_check_for_dummy_keys();
--
2.43.0
@@ -0,0 +1,217 @@
From 5fc4f3857739a9fe93819cedc4a8108d33bf8241 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Thu, 27 Nov 2025 10:35:58 +0000
Subject: [PATCH] lib: efi_guid: Added EFI GUID library
This library can be used to generate version 4 UUID/GUIDs according to
RFC 4122 by using a PSA crypto driver. A separate header is provided to
give access to the struct without the need of a PSA config.
Change-Id: Ief35b2a4f565889ba2ea0de82e20dc12f6e824e8
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [3bdd2562ebad3115457ea75e58d0554802e12dba]
---
CMakeLists.txt | 1 +
lib/efi_guid/CMakeLists.txt | 26 ++++++++++++
lib/efi_guid/inc/efi_guid.h | 36 +++++++++++++++++
lib/efi_guid/inc/efi_guid_structs.h | 62 +++++++++++++++++++++++++++++
lib/efi_guid/src/efi_guid.c | 33 +++++++++++++++
5 files changed, 158 insertions(+)
create mode 100644 lib/efi_guid/CMakeLists.txt
create mode 100644 lib/efi_guid/inc/efi_guid.h
create mode 100644 lib/efi_guid/inc/efi_guid_structs.h
create mode 100644 lib/efi_guid/src/efi_guid.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2560dd15e..b120de697 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,6 +44,7 @@ project("Trusted Firmware M" VERSION ${TFM_VERSION} LANGUAGES C CXX ASM)
add_subdirectory(lib/backtrace)
add_subdirectory(lib/ext)
+add_subdirectory(lib/efi_guid)
add_subdirectory(lib/fih)
add_subdirectory(lib/tfm_log)
add_subdirectory(lib/tfm_log_unpriv)
diff --git a/lib/efi_guid/CMakeLists.txt b/lib/efi_guid/CMakeLists.txt
new file mode 100644
index 000000000..656eb72ea
--- /dev/null
+++ b/lib/efi_guid/CMakeLists.txt
@@ -0,0 +1,26 @@
+#-------------------------------------------------------------------------------
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+add_library(tfm_efi_guid STATIC)
+
+target_sources(tfm_efi_guid
+ PRIVATE
+ src/efi_guid.c
+)
+
+target_include_directories(tfm_efi_guid
+ PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
+ PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+)
+
+target_link_libraries(tfm_efi_guid
+ PUBLIC
+ psa_interface
+ psa_crypto_config
+)
diff --git a/lib/efi_guid/inc/efi_guid.h b/lib/efi_guid/inc/efi_guid.h
new file mode 100644
index 000000000..81f6ad507
--- /dev/null
+++ b/lib/efi_guid/inc/efi_guid.h
@@ -0,0 +1,36 @@
+/*
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_EFI_GUID_H__
+#define __TFM_EFI_GUID_H__
+
+#include "psa/crypto.h"
+#include "efi_guid_structs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Generates a random version 4 UUID/GUID using a PSA crypto driver.
+ *
+ * \note See RFC 4112 for details on UUID/GUIDs.
+ *
+ * \note See psa_generate_random for possible failures.
+ *
+ * \param[out] guid Pointer populated with the generated UUID/GUID.
+ *
+ * \return PSA_SUCCESS on success or a PSA error code on failure.
+ *
+ */
+psa_status_t efi_guid_generate_random(struct efi_guid_t *guid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_EFI_GUID_H__ */
diff --git a/lib/efi_guid/inc/efi_guid_structs.h b/lib/efi_guid/inc/efi_guid_structs.h
new file mode 100644
index 000000000..c89e8f692
--- /dev/null
+++ b/lib/efi_guid/inc/efi_guid_structs.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021, Linaro Limited
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_EFI_GUID_STRUCTS_H__
+#define __TFM_EFI_GUID_STRUCTS_H__
+
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EFI_GUID_NODE_LEN 6
+
+/**
+ * \brief Representation that makes creating GUIDs slightly easier.
+ */
+struct efi_guid_t {
+ uint32_t time_low; /**< Low 32-bits of timestamp. */
+ uint16_t time_mid; /**< Middle 16-bits of timestamp. */
+ uint16_t time_hi_and_version; /**< High 12-bits of timestamp with 4-bit version. */
+ uint8_t clock_seq_hi_and_reserved; /**< High 4-bits of clock sequence with 4-bit variant. */
+ uint8_t clock_seq_low; /**< Low 8-bits of clock sequence. */
+ uint8_t node[EFI_GUID_NODE_LEN]; /**< 48-bit spatially unique node identifier. */
+};
+
+static inline int efi_guid_cmp(const struct efi_guid_t *g1,
+ const struct efi_guid_t *g2)
+{
+ return memcmp(g1, g2, sizeof(struct efi_guid_t));
+}
+
+static inline void *efi_guid_cpy(const struct efi_guid_t *src,
+ struct efi_guid_t *dst)
+{
+ return memcpy(dst, src, sizeof(struct efi_guid_t));
+}
+
+/** \brief Helper macro to build an EFI GUID structure from individual values. */
+#define MAKE_EFI_GUID(a, b, c, d0, d1, e0, e1, e2, e3, e4, e5) \
+ { \
+ (a) & 0xffffffff, (b)&0xffff, (c)&0xffff, d0, d1, { \
+ (e0), (e1), (e2), (e3), (e4), (e5) \
+ } \
+ }
+
+/** \brief Helper macro to build the EFI GUID 00000000-0000-0000-0000-0000000000. */
+#define NULL_GUID \
+ MAKE_EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_EFI_GUID_STRUCTS_H__ */
diff --git a/lib/efi_guid/src/efi_guid.c b/lib/efi_guid/src/efi_guid.c
new file mode 100644
index 000000000..cb8730a51
--- /dev/null
+++ b/lib/efi_guid/src/efi_guid.c
@@ -0,0 +1,33 @@
+/*
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include "psa/crypto.h"
+
+#include "efi_guid_structs.h"
+#include "efi_guid.h"
+
+psa_status_t efi_guid_generate_random(struct efi_guid_t *guid)
+{
+ const psa_status_t ret = psa_generate_random((uint8_t *)guid, sizeof(*guid));
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* According to RFC 4122, counting bits from the right:
+ * - Bits 6 and 7 of clock_seq_hi_and_reserved need to be set to
+ * 0 and 1 respecitively
+ * - Bits 12 through 15 of time_hi_and_version need to be set to
+ * 0b0100
+ */
+ guid->clock_seq_hi_and_reserved &= 0x3F;
+ guid->clock_seq_hi_and_reserved |= 0x80;
+ guid->time_hi_and_version &= 0x0FFF;
+ guid->time_hi_and_version |= 0x4000;
+
+ return PSA_SUCCESS;
+}
@@ -0,0 +1,136 @@
From 4a47d926420bfec4a0e687b6ecc4cf52419e4f58 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Thu, 27 Nov 2025 10:37:28 +0000
Subject: [PATCH] lib: efi_soft_crc: Added EFI CRC library
This library can be used to perform CRC32 calculations using the
standard CRC32 polynomial specified by the UEFI spec 2.10. It does not
use a lookup table to save on memory. The polynomial used is in reverse
order to match little-endian machines.
Change-Id: Ifce5a1cbbb3ab394bc748305be213a8467610015
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [3f2b707eaadef8008f333bd5c519c1b2544458ab]
---
lib/ext/CMakeLists.txt | 1 +
lib/ext/efi_soft_crc/CMakeLists.txt | 18 ++++++++++++++
lib/ext/efi_soft_crc/inc/efi_soft_crc.h | 33 +++++++++++++++++++++++++
lib/ext/efi_soft_crc/src/efi_soft_crc.c | 32 ++++++++++++++++++++++++
4 files changed, 84 insertions(+)
create mode 100644 lib/ext/efi_soft_crc/CMakeLists.txt
create mode 100644 lib/ext/efi_soft_crc/inc/efi_soft_crc.h
create mode 100644 lib/ext/efi_soft_crc/src/efi_soft_crc.c
diff --git a/lib/ext/CMakeLists.txt b/lib/ext/CMakeLists.txt
index 05f6b8f14..1dffbacfb 100644
--- a/lib/ext/CMakeLists.txt
+++ b/lib/ext/CMakeLists.txt
@@ -10,6 +10,7 @@ add_subdirectory(qcbor)
add_subdirectory(t_cose)
add_subdirectory(mbedcrypto)
add_subdirectory(cmsis)
+add_subdirectory(efi_soft_crc)
if(BL2)
add_subdirectory(mcuboot)
endif()
diff --git a/lib/ext/efi_soft_crc/CMakeLists.txt b/lib/ext/efi_soft_crc/CMakeLists.txt
new file mode 100644
index 000000000..47fd2d507
--- /dev/null
+++ b/lib/ext/efi_soft_crc/CMakeLists.txt
@@ -0,0 +1,18 @@
+#-------------------------------------------------------------------------------
+# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+add_library(tfm_efi_soft_crc STATIC)
+
+target_sources(tfm_efi_soft_crc
+ PRIVATE
+ src/efi_soft_crc.c
+)
+
+target_include_directories(tfm_efi_soft_crc
+ PUBLIC
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
+)
diff --git a/lib/ext/efi_soft_crc/inc/efi_soft_crc.h b/lib/ext/efi_soft_crc/inc/efi_soft_crc.h
new file mode 100644
index 000000000..77baa8987
--- /dev/null
+++ b/lib/ext/efi_soft_crc/inc/efi_soft_crc.h
@@ -0,0 +1,33 @@
+/*
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_EFI_SOFT_CRC_H__
+#define __TFM_EFI_SOFT_CRC_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Updates a CRC32 calculation using ISO 3309 CRC-32.
+ *
+ * \param[in] old_crc Existing CRC value (0 for the first calculation).
+ * \param[in] buf Buffer of bytes to perform the calculation over.
+ * \param[in] len Length of \p buf in bytes.
+ *
+ * \return The calculated CRC32 value.
+ */
+uint32_t efi_soft_crc32_update(uint32_t old_crc, const uint8_t *buf, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_EFI_SOFT_CRC_H__ */
diff --git a/lib/ext/efi_soft_crc/src/efi_soft_crc.c b/lib/ext/efi_soft_crc/src/efi_soft_crc.c
new file mode 100644
index 000000000..041a321cd
--- /dev/null
+++ b/lib/ext/efi_soft_crc/src/efi_soft_crc.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 2013 Henry S. Warren Jr. You are free to use, copy,
+ * and distribute any of the code on this web site, whether modified
+ * by you or not.
+ */
+
+#include "efi_soft_crc.h"
+
+/* The standard polynomial, in reverse */
+#define POLYNOMIAL 0xEDB88320
+
+/* Algorithmic approach to CRC calculation: avoids lookup tables, slow. Byte
+ * reversal is avoided by shifting the crc register right instead of left and
+ * by using a reversed 32-bit word to represent the polynomial.
+ *
+ * Derived from work by Henry S. Warren Jr.
+ */
+uint32_t efi_soft_crc32_update(uint32_t old_crc32, const uint8_t *buf, size_t len)
+{
+ register uint32_t crc32 = ~old_crc32;
+ uint32_t mask;
+
+ for ( ; len; --len, ++buf)
+ {
+ crc32 ^= *buf;
+ for (size_t i = 0; i < 8; ++i) {
+ mask = -(crc32 & 1);
+ crc32 = (crc32 >> 1) ^ (POLYNOMIAL & mask);
+ }
+ }
+
+ return ~crc32;
+}
@@ -0,0 +1,308 @@
From b3775fd8aa2078e5e86d5cdb4164e6fc31fabbfc Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Wed, 11 Feb 2026 11:16:13 +0000
Subject: [PATCH] lib: gpt: Expanded how GPT partition can be identified
The GUID of a partition is not always known, particularly for tables
that have been created outside the control of the user. Therefore,
allowing the name or type to be used to identify a partition gives the
user greater flexibility. These may not be unique, however, and so must
be indexed. A single entry is returned rather than a list so as to not
dynamically allocate such memory.
Change-Id: I7687bfc737b244f6e589c4fe6b61c370daf1b062
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [aede42c1c58b5681fe50bbec3a797f69256d108e]
---
lib/gpt/inc/gpt.h | 34 +++++++++
lib/gpt/src/gpt.c | 68 +++++++++++++++--
lib/gpt/unittests/gpt/test_gpt.c | 127 +++++++++++++++++++++++++++++++
3 files changed, 223 insertions(+), 6 deletions(-)
diff --git a/lib/gpt/inc/gpt.h b/lib/gpt/inc/gpt.h
index d98abe980..947a6b341 100644
--- a/lib/gpt/inc/gpt.h
+++ b/lib/gpt/inc/gpt.h
@@ -48,6 +48,40 @@ __attribute__((nonnull(1,2)))
psa_status_t gpt_entry_read(const struct efi_guid_t *guid,
struct partition_entry_t *partition_entry);
+/**
+ * \brief Reads the contents of a partition entry identified by name.
+ *
+ * \param[in] name Name of the partition to read in unicode.
+ * \param[in] index Index to read when multiple entries share the same name.
+ * \param[out] partition_entry Populated partition entry on success.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_DOES_NOT_EXIST No entry found with the provided name at \p index. For example,
+ * \p index was 1 (second entry) but only one entry was found.
+ */
+__attribute__((nonnull(1,3)))
+psa_status_t gpt_entry_read_by_name(const char name[GPT_ENTRY_NAME_LENGTH],
+ const uint32_t index,
+ struct partition_entry_t *partition_entry);
+
+/**
+ * \brief Reads the contents of a partition entry identified by type.
+ *
+ * \param[in] type Type of the partition to read.
+ * \param[in] index Index to read when multiple entries share the same type.
+ * \param[out] partition_entry Populated partition entry on success.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_DOES_NOT_EXIST No entry found with the provided type at \p index. For example,
+ * \p index was 1 (second entry) but only one entry was found.
+ */
+__attribute__((nonnull(1,3)))
+psa_status_t gpt_entry_read_by_type(const struct efi_guid_t *type,
+ const uint32_t index,
+ struct partition_entry_t *partition_entry);
+
/**
* \brief Reads the GPT header from the second block (LBA 1).
*
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index 99d735797..1662b81c2 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -177,6 +177,8 @@ static inline uint64_t partition_entry_lba(const struct gpt_t *table,
static inline uint64_t gpt_entry_per_lba_count(void);
static psa_status_t count_used_partitions(const struct gpt_t *table,
uint32_t *num_used);
+static inline void parse_entry(struct gpt_entry_t *entry,
+ struct partition_entry_t *partition_entry);
static psa_status_t read_from_flash(uint64_t required_lba);
static psa_status_t read_entry_from_flash(const struct gpt_t *table,
uint32_t array_index,
@@ -190,6 +192,8 @@ static psa_status_t find_gpt_entry(const struct gpt_t *table,
uint32_t *array_index);
static psa_status_t mbr_load(struct mbr_t *mbr);
static bool gpt_entry_cmp_guid(const struct gpt_entry_t *entry, const void *guid);
+static bool gpt_entry_cmp_name(const struct gpt_entry_t *entry, const void *name);
+static bool gpt_entry_cmp_type(const struct gpt_entry_t *entry, const void *type);
/* PUBLIC API FUNCTIONS */
@@ -202,12 +206,37 @@ psa_status_t gpt_entry_read(const struct efi_guid_t *guid,
return ret;
}
- partition_entry->start = cached_entry.start;
- partition_entry->size = cached_entry.end - cached_entry.start + 1;
- memcpy(partition_entry->name, cached_entry.name, GPT_ENTRY_NAME_LENGTH);
- partition_entry->attr = cached_entry.attr;
- partition_entry->partition_guid = cached_entry.unique_guid;
- partition_entry->type_guid = cached_entry.partition_type;
+ parse_entry(&cached_entry, partition_entry);
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t gpt_entry_read_by_name(const char name[GPT_ENTRY_NAME_LENGTH],
+ const uint32_t index,
+ struct partition_entry_t *partition_entry)
+{
+ struct gpt_entry_t cached_entry;
+ const psa_status_t ret = find_gpt_entry(&primary_gpt, gpt_entry_cmp_name, name, index, &cached_entry, NULL);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ parse_entry(&cached_entry, partition_entry);
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t gpt_entry_read_by_type(const struct efi_guid_t *type,
+ const uint32_t index,
+ struct partition_entry_t *partition_entry)
+{
+ struct gpt_entry_t cached_entry;
+ const psa_status_t ret = find_gpt_entry(&primary_gpt, gpt_entry_cmp_type, type, index, &cached_entry, NULL);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ parse_entry(&cached_entry, partition_entry);
return PSA_SUCCESS;
}
@@ -322,6 +351,18 @@ static inline uint64_t gpt_entry_per_lba_count(void)
return num_entries;
}
+/* Copies information from the entry to the user visible structure */
+static inline void parse_entry(struct gpt_entry_t *entry,
+ struct partition_entry_t *partition_entry)
+{
+ partition_entry->start = entry->start;
+ partition_entry->size = entry->end - entry->start + 1;
+ memcpy(partition_entry->name, entry->name, GPT_ENTRY_NAME_LENGTH);
+ partition_entry->attr = entry->attr;
+ partition_entry->partition_guid = entry->unique_guid;
+ partition_entry->type_guid = entry->partition_type;
+}
+
/* Compare the entry with the given guid */
static bool gpt_entry_cmp_guid(const struct gpt_entry_t *entry, const void *guid)
{
@@ -331,6 +372,21 @@ static bool gpt_entry_cmp_guid(const struct gpt_entry_t *entry, const void *guid
return efi_guid_cmp(&entry_guid, cmp_guid) == 0;
}
+/* Compare the entry with the given name */
+static bool gpt_entry_cmp_name(const struct gpt_entry_t *entry, const void *name)
+{
+ return memcmp(name, entry->name, GPT_ENTRY_NAME_LENGTH) == 0;
+}
+
+/* Compare the entry with the given type */
+static bool gpt_entry_cmp_type(const struct gpt_entry_t *entry, const void *type)
+{
+ const struct efi_guid_t *cmp_type = (const struct efi_guid_t *)type;
+ const struct efi_guid_t entry_type = entry->partition_type;
+
+ return efi_guid_cmp(&entry_type, cmp_type) == 0;
+}
+
/* Read entry with given GUID from given table and return it if found. */
static psa_status_t find_gpt_entry(const struct gpt_t *table,
gpt_entry_cmp_t compare,
diff --git a/lib/gpt/unittests/gpt/test_gpt.c b/lib/gpt/unittests/gpt/test_gpt.c
index 325887fae..d6671f3fc 100644
--- a/lib/gpt/unittests/gpt/test_gpt.c
+++ b/lib/gpt/unittests/gpt/test_gpt.c
@@ -381,3 +381,130 @@ void test_gpt_entry_read_should_failWhenEntryNotExisting(void)
register_mocked_read(&test_partition_array, sizeof(test_partition_array));
TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read(&non_existing, &entry));
}
+
+void test_gpt_entry_read_by_name_should_populateEntry(void)
+{
+ /* Start with a populated GPT */
+ setup_valid_gpt();
+
+ /* Ensure an entry is found, even with repeat names */
+ struct partition_entry_t entry;
+ struct gpt_entry_t *desired1 = &(test_partition_array[0]);
+ struct efi_guid_t test_guid1 = desired1->guid;
+ struct efi_guid_t test_type1 = desired1->type;
+
+ /* Change the name of something else and ensure it is found */
+ struct gpt_entry_t *desired2 = &(test_partition_array[1]);
+ struct efi_guid_t test_guid2 = desired2->guid;
+ struct efi_guid_t test_type2 = desired2->type;
+ memcpy(desired2->name, desired1->name, GPT_ENTRY_NAME_LENGTH);
+
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_read_by_name(desired1->name, 0, &entry));
+
+ /* Ensure this is the correct entry */
+ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_guid1, &(entry.partition_guid)));
+ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_type1, &(entry.type_guid)));
+ TEST_ASSERT_EQUAL(desired1->start, entry.start);
+ TEST_ASSERT_EQUAL(desired1->end, entry.start + entry.size - 1);
+
+ TEST_ASSERT_EQUAL_MEMORY(desired1->name, entry.name, GPT_ENTRY_NAME_LENGTH);
+
+ /* Do again but the next entry */
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_read_by_name(desired1->name, 1, &entry));
+
+ /* Ensure this is the correct entry */
+ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_guid2, &(entry.partition_guid)));
+ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_type2, &(entry.type_guid)));
+ TEST_ASSERT_EQUAL(desired2->start, entry.start);
+ TEST_ASSERT_EQUAL(desired2->end, entry.start + entry.size - 1);
+
+ TEST_ASSERT_EQUAL_MEMORY(desired2->name, entry.name, GPT_ENTRY_NAME_LENGTH);
+}
+
+void test_gpt_entry_read_by_name_should_failWhenEntryNotExisting(void)
+{
+ /* Start with an empty GPT */
+ setup_empty_gpt();
+
+ /* Try to read something */
+ struct partition_entry_t entry;
+ char test_name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read_by_name(test_name, 0, &entry));
+
+ /* Now, have a non-empty GPT but search for a name that won't exist */
+ setup_valid_gpt();
+
+ /* Each entry should be read */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read_by_name(test_name, 0, &entry));
+
+ /* Finally, search for the second entry of a name that appears only once */
+ memcpy(test_name, test_partition_array[0].name, GPT_ENTRY_NAME_LENGTH);
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read_by_name(test_name, 1, &entry));
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read_by_name(test_name, TEST_DEFAULT_NUM_PARTITIONS, &entry));
+}
+
+void test_gpt_entry_read_by_type_should_populateEntry(void)
+{
+ /* Start with a populated GPT */
+ setup_valid_gpt();
+
+ /* Ensure an entry is found, even with repeat types */
+ struct partition_entry_t entry;
+ struct gpt_entry_t *desired1 = &(test_partition_array[0]);
+ struct efi_guid_t test_guid1 = desired1->guid;
+ struct efi_guid_t test_type1 = desired1->type;
+
+ struct gpt_entry_t *desired2 = &(test_partition_array[1]);
+ struct efi_guid_t test_guid2 = desired2->guid;
+ struct efi_guid_t test_type2 = test_type1;
+ desired2->type = test_type2;
+
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_read_by_type(&test_type1, 0, &entry));
+
+ /* Ensure this is the correct entry */
+ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_guid1, &(entry.partition_guid)));
+ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_type1, &(entry.type_guid)));
+ TEST_ASSERT_EQUAL(desired1->start, entry.start);
+ TEST_ASSERT_EQUAL(desired1->end, entry.start + entry.size - 1);
+
+ /* Name is unicode */
+ TEST_ASSERT_EQUAL_MEMORY(desired1->name, entry.name, GPT_ENTRY_NAME_LENGTH);
+
+ /* Do again but the next entry */
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_read_by_type(&test_type1, 1, &entry));
+
+ /* Ensure this is the correct entry */
+ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_guid2, &(entry.partition_guid)));
+ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_type2, &(entry.type_guid)));
+ TEST_ASSERT_EQUAL(desired2->start, entry.start);
+ TEST_ASSERT_EQUAL(desired2->end, entry.start + entry.size - 1);
+
+ TEST_ASSERT_EQUAL_MEMORY(desired2->name, entry.name, GPT_ENTRY_NAME_LENGTH);
+}
+
+void test_gpt_entry_read_by_type_should_failWhenEntryNotExisting(void)
+{
+ /* Start with an empty GPT */
+ setup_empty_gpt();
+
+ /* Try to read something */
+ struct partition_entry_t entry;
+ struct efi_guid_t test_type = MAKE_EFI_GUID(11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read_by_type(&test_type, 0, &entry));
+
+ /* Now, have a non-empty GPT but search for a type that won't exist */
+ setup_valid_gpt();
+
+ /* Each entry should be read */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read_by_type(&test_type, 0, &entry));
+
+ /* Finally, search for the second entry of a type that appears only once */
+ struct efi_guid_t existing_type = test_partition_array[0].type;
+ efi_guid_cpy(&existing_type, &test_type);
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read_by_type(&test_type, 1, &entry));
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read_by_type(&test_type, TEST_DEFAULT_NUM_PARTITIONS, &entry));
+}
@@ -0,0 +1,961 @@
From 02ec696240d0225ed6473ea5b01ec6617d897a41 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Wed, 11 Feb 2026 11:23:31 +0000
Subject: [PATCH] lib: gpt: Added operations to modify partitions
The operations added allow the user to modify existing GPT partitions,
apart from moving them; that is, they are all metadata changes. The
library also handles updating both primary and backup partition entry
arrays and headers after each modification.
Each modification on an entry is buffered in order to reduce the number
of flash erase operations. A simple heuristic of "write on every n
operations" is used to prevent infinite buffering. The buffering is most
effective when consecutive entries are operated on. If the mapping of
LBA to flash sector is not 1:1, the flash driver the platform registers
with the library may implement its own buffering for further
optimisation.
Change-Id: Ie358464427d66883e1681497a2630a8ef281e528
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [ab942ecb7cb62bcfe1e5701f3f3adbf1eebd330a]
---
lib/gpt/CMakeLists.txt | 1 +
lib/gpt/inc/gpt.h | 69 +++++
lib/gpt/inc/gpt_flash.h | 41 ++-
lib/gpt/src/gpt.c | 419 +++++++++++++++++++++++++++++-
lib/gpt/unittests/gpt/test_gpt.c | 187 +++++++++++++
lib/gpt/unittests/gpt/utcfg.cmake | 2 +
6 files changed, 712 insertions(+), 7 deletions(-)
diff --git a/lib/gpt/CMakeLists.txt b/lib/gpt/CMakeLists.txt
index 2b5d6af8f..25d0de9cd 100644
--- a/lib/gpt/CMakeLists.txt
+++ b/lib/gpt/CMakeLists.txt
@@ -37,4 +37,5 @@ target_link_libraries(tfm_gpt
tfm_log_headers
PRIVATE
tfm_efi_guid
+ tfm_efi_soft_crc
)
diff --git a/lib/gpt/inc/gpt.h b/lib/gpt/inc/gpt.h
index 947a6b341..6e7bb360e 100644
--- a/lib/gpt/inc/gpt.h
+++ b/lib/gpt/inc/gpt.h
@@ -82,6 +82,75 @@ psa_status_t gpt_entry_read_by_type(const struct efi_guid_t *type,
const uint32_t index,
struct partition_entry_t *partition_entry);
+/**
+ * \brief Renames a partition entry.
+ *
+ * \param[in] guid Entry to rename.
+ * \param[in] name New unicode name for the entry.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_DOES_NOT_EXIST No entry found with the provided GUID.
+ * \retval PSA_ERROR_INVALID_ARGUMENT Empty name.
+ */
+__attribute__((nonnull(1,2)))
+psa_status_t gpt_entry_rename(const struct efi_guid_t *guid,
+ const char name[GPT_ENTRY_NAME_LENGTH]);
+
+/**
+ * \brief Changes the type of a partition.
+ *
+ * \param[in] guid Entry to update.
+ * \param[in] type New type GUID.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_INVALID_ARGUMENT \p type is the null GUID.
+ * \retval PSA_ERROR_DOES_NOT_EXIST No entry found with the provided GUID.
+ */
+__attribute__((nonnull(1,2)))
+psa_status_t gpt_entry_change_type(const struct efi_guid_t *guid,
+ const struct efi_guid_t *type);
+
+/**
+ * \brief Adds attributes to a partition entry.
+ *
+ * \param[in] guid Entry to modify.
+ * \param[in] attr Attributes to add.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_DOES_NOT_EXIST No entry found with the provided GUID.
+ */
+__attribute__((nonnull(1)))
+psa_status_t gpt_attr_add(const struct efi_guid_t *guid, const uint64_t attr);
+
+/**
+ * \brief Removes attributes from a partition entry.
+ *
+ * \param[in] guid Entry to modify.
+ * \param[in] attr Attributes to remove.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_DOES_NOT_EXIST No entry found with the provided GUID.
+ */
+__attribute__((nonnull(1)))
+psa_status_t gpt_attr_remove(const struct efi_guid_t *guid, const uint64_t attr);
+
+/**
+ * \brief Sets attributes for a partition entry.
+ *
+ * \param[in] guid Entry to modify.
+ * \param[in] attr Attributes to set.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_DOES_NOT_EXIST No entry found with the provided GUID.
+ */
+__attribute__((nonnull(1)))
+psa_status_t gpt_attr_set(const struct efi_guid_t *guid, const uint64_t attr);
+
/**
* \brief Reads the GPT header from the second block (LBA 1).
*
diff --git a/lib/gpt/inc/gpt_flash.h b/lib/gpt/inc/gpt_flash.h
index 2b43390c1..ada5f6932 100644
--- a/lib/gpt/inc/gpt_flash.h
+++ b/lib/gpt/inc/gpt_flash.h
@@ -57,13 +57,48 @@ __attribute__((nonnull(2)))
typedef ssize_t (*gpt_flash_read_t)(uint64_t lba,
void *buf);
+/**
+ * \brief Function that writes to a logical block address.
+ *
+ * \param[in] lba Logical block address to write to.
+ * \param[in] buf Buffer to write from. Must be at least the size of an LBA.
+ *
+ * \return Number of bytes written on success or a negative error code on failure.
+ * \retval GPT_FLASH_NOT_INIT The flash driver has not been initialised.
+ * \retval GPT_FLASH_UNAVAILABLE The flash driver is unavailable.
+ * \retval GPT_FLASH_BAD_PARAM \p lba is not a valid address (for example larger than the flash size).
+ * \retval GPT_FLASH_GENERIC_ERROR Unspecified error.
+ */
+__attribute__((nonnull(2)))
+typedef ssize_t (*gpt_flash_write_t)(uint64_t lba,
+ const void *buf);
+
+/**
+ * \brief Function that erases consecutive logical blocks.
+ *
+ * \param[in] lba Starting logical block address.
+ * \param[in] num_blocks Number of blocks to erase.
+ *
+ * \return Number of blocks erased on success or a negative error code on failure.
+ * \retval GPT_FLASH_NOT_INIT The flash driver has not been initialised.
+ * \retval GPT_FLASH_UNAVAILABLE The flash driver is unavailable.
+ * \retval GPT_FLASH_BAD_PARAM \p num_blocks is zero.
+ * \retval GPT_FLASH_BAD_PARAM One of the requested blocks is invalid (for example,
+ * \p lba + \p num_blocks exceeds the flash size).
+ * \retval GPT_FLASH_BAD_PARAM \p lba is not a valid address (for example larger than the flash size).
+ * \retval GPT_FLASH_GENERIC_ERROR Unspecified error.
+ */
+typedef ssize_t (*gpt_flash_erase_t)(uint64_t lba, size_t num_blocks);
+
/**
* \brief Interface for interacting with the flash driver.
*/
struct gpt_flash_driver_t {
- gpt_flash_init_t init; /**< Flash initialisation routine. */
- gpt_flash_uninit_t uninit; /**< Flash deinitialisation routine. */
- gpt_flash_read_t read; /**< Routine used to read a logical block. */
+ gpt_flash_init_t init; /**< Flash initialisation routine. */
+ gpt_flash_uninit_t uninit; /**< Flash deinitialisation routine. */
+ gpt_flash_read_t read; /**< Routine used to read a logical block. */
+ gpt_flash_write_t write; /**< Routine used to write a logical block. */
+ gpt_flash_erase_t erase; /**< Routine used to erase logical blocks. */
};
#ifdef __cplusplus
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index 1662b81c2..2cfcdff07 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -14,6 +14,7 @@
#include "gpt_flash.h"
#include "tfm_log.h"
#include "efi_guid_structs.h"
+#include "efi_soft_crc.h"
/* This needs to be defined by the platform and is used by the GPT library as
* the number of bytes in a Logical Block Address (LBA)
@@ -146,6 +147,15 @@ typedef bool (*gpt_entry_cmp_t)(const struct gpt_entry_t *, const void *);
/* The LBA for the backup table */
static uint64_t backup_gpt_lba = 0;
+/* The LBA for the partition array for the backup table. Rather than storing
+ * the entire table header in memory, just this is stored so that updates can
+ * be done without reading from flash
+ */
+static uint64_t backup_gpt_array_lba = 0;
+
+/* CRC for backup header. Because the LBAs differ, so too will the CRC */
+static uint32_t backup_crc32 = 0;
+
/* The flash driver, used to perform I/O */
static struct gpt_flash_driver_t *plat_flash_driver = NULL;
@@ -165,6 +175,9 @@ static uint8_t lba_buf[TFM_GPT_BLOCK_SIZE] = {0};
*/
static uint64_t cached_lba = 0;
+/* True if write was buffered */
+static bool write_buffered = false;
+
/* Helper function prototypes */
__attribute__((unused))
static void print_guid(struct efi_guid_t guid);
@@ -174,7 +187,9 @@ __attribute__((unused))
static psa_status_t unicode_to_ascii(const char *unicode, char *ascii);
static inline uint64_t partition_entry_lba(const struct gpt_t *table,
uint32_t array_index);
+static inline uint64_t partition_array_last_lba(const struct gpt_t *table);
static inline uint64_t gpt_entry_per_lba_count(void);
+static inline void swap_headers(const struct gpt_header_t *src, struct gpt_header_t *dst);
static psa_status_t count_used_partitions(const struct gpt_t *table,
uint32_t *num_used);
static inline void parse_entry(struct gpt_entry_t *entry,
@@ -184,6 +199,15 @@ static psa_status_t read_entry_from_flash(const struct gpt_t *table,
uint32_t array_index,
struct gpt_entry_t *entry);
static psa_status_t read_table_from_flash(struct gpt_t *table, bool is_primary);
+static psa_status_t flush_lba_buf(void);
+static psa_status_t write_to_flash(uint64_t lba);
+static psa_status_t write_entries_to_flash(uint32_t lbas_into_array, bool no_header_update);
+static psa_status_t write_entry(uint32_t array_index,
+ const struct gpt_entry_t *entry,
+ bool no_header_update);
+static psa_status_t write_header_to_flash(const struct gpt_t *table);
+static psa_status_t write_headers_to_flash(void);
+static psa_status_t update_header(uint32_t num_partitions);
static psa_status_t find_gpt_entry(const struct gpt_t *table,
gpt_entry_cmp_t compare,
const void *attr,
@@ -241,16 +265,146 @@ psa_status_t gpt_entry_read_by_type(const struct efi_guid_t *type,
return PSA_SUCCESS;
}
+psa_status_t gpt_entry_rename(const struct efi_guid_t *guid, const char name[GPT_ENTRY_NAME_LENGTH])
+{
+ if (name[0] == '\0') {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ struct gpt_entry_t cached_entry;
+ uint32_t cached_index;
+ const psa_status_t ret = find_gpt_entry(
+ &primary_gpt,
+ gpt_entry_cmp_guid,
+ guid,
+ 0,
+ &cached_entry,
+ &cached_index);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* NOOP if no name change. Prevents header update. */
+ if (memcmp(cached_entry.name, name, GPT_ENTRY_NAME_LENGTH) == 0) {
+ return PSA_SUCCESS;
+ }
+
+ memcpy(cached_entry.name, name, GPT_ENTRY_NAME_LENGTH);
+ cached_entry.name[GPT_ENTRY_NAME_LENGTH - 1] = '\0';
+ cached_entry.name[GPT_ENTRY_NAME_LENGTH - 2] = '\0';
+ return write_entry(cached_index, &cached_entry, false);
+}
+
+psa_status_t gpt_entry_change_type(const struct efi_guid_t *guid, const struct efi_guid_t *type)
+{
+ struct efi_guid_t null_type = NULL_GUID;
+ if (efi_guid_cmp(&null_type, type) == 0) {
+ ERROR("Cannot set type to null-GUID; delete instead\n");
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ struct gpt_entry_t cached_entry;
+ uint32_t cached_index;
+ const psa_status_t ret = find_gpt_entry(
+ &primary_gpt,
+ gpt_entry_cmp_guid,
+ guid,
+ 0,
+ &cached_entry,
+ &cached_index);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ cached_entry.partition_type = *type;
+
+ return write_entry(cached_index, &cached_entry, false);
+}
+
+psa_status_t gpt_attr_add(const struct efi_guid_t *guid, const uint64_t attr)
+{
+ /* This quick check prevents I/O from happening for a no-op */
+ if (attr == 0) {
+ return PSA_SUCCESS;
+ }
+
+ struct gpt_entry_t cached_entry;
+ uint32_t cached_index;
+ const psa_status_t ret = find_gpt_entry(
+ &primary_gpt,
+ gpt_entry_cmp_guid,
+ guid,
+ 0,
+ &cached_entry,
+ &cached_index);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ cached_entry.attr |= attr;
+
+ return write_entry(cached_index, &cached_entry, false);
+}
+
+psa_status_t gpt_attr_remove(const struct efi_guid_t *guid, const uint64_t attr)
+{
+ /* This quick check prevents I/O from happening for a no-op */
+ if (attr == 0) {
+ return PSA_SUCCESS;
+ }
+
+ struct gpt_entry_t cached_entry;
+ uint32_t cached_index;
+ const psa_status_t ret = find_gpt_entry(
+ &primary_gpt,
+ gpt_entry_cmp_guid,
+ guid,
+ 0,
+ &cached_entry,
+ &cached_index);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ cached_entry.attr &= ~(attr);
+
+ return write_entry(cached_index, &cached_entry, false);
+}
+
+psa_status_t gpt_attr_set(const struct efi_guid_t *guid, const uint64_t attr)
+{
+ struct gpt_entry_t cached_entry;
+ uint32_t cached_index;
+ const psa_status_t ret = find_gpt_entry(
+ &primary_gpt,
+ gpt_entry_cmp_guid,
+ guid,
+ 0,
+ &cached_entry,
+ &cached_index);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ cached_entry.attr = attr;
+
+ return write_entry(cached_index, &cached_entry, false);
+}
+
/* Initialises GPT from first block. */
psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_partitions)
{
cached_lba = 0;
+ write_buffered = false;
if (max_partitions < GPT_MIN_PARTITIONS) {
ERROR("Minimum number of partitions is %d\n", GPT_MIN_PARTITIONS);
return PSA_ERROR_INVALID_ARGUMENT;
}
- if (flash_driver->read == NULL) {
+ if (flash_driver->read == NULL ||
+ flash_driver->write == NULL ||
+ flash_driver->erase == NULL)
+ {
ERROR("I/O functions must be defined\n");
return PSA_ERROR_INVALID_ARGUMENT;
}
@@ -303,6 +457,7 @@ psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_part
if (ret != PSA_SUCCESS) {
goto fail_load;
}
+ backup_gpt_array_lba = backup_gpt.header.array_lba;
} else {
WARN("Backup GPT location is unknown!\n");
}
@@ -314,7 +469,9 @@ fail_load:
plat_flash_driver = NULL;
plat_max_partitions = 0;
backup_gpt_lba = 0;
+ backup_gpt_array_lba = 0;
cached_lba = 0;
+ write_buffered = false;
return ret;
}
@@ -324,6 +481,11 @@ psa_status_t gpt_uninit(void)
psa_status_t ret = PSA_SUCCESS;
if (plat_flash_driver) {
+ /* Flush the in-memory buffer */
+ if (write_buffered) {
+ ret = flush_lba_buf();
+ }
+
/* Uninitialise driver if function provided */
if (plat_flash_driver->uninit != NULL) {
if (plat_flash_driver->uninit() != 0) {
@@ -336,7 +498,9 @@ psa_status_t gpt_uninit(void)
plat_flash_driver = NULL;
plat_max_partitions = 0;
backup_gpt_lba = 0;
+ backup_gpt_array_lba = 0;
cached_lba = 0;
+ write_buffered = false;
return ret;
}
@@ -422,6 +586,47 @@ static psa_status_t find_gpt_entry(const struct gpt_t *table,
return io_failure ? PSA_ERROR_STORAGE_FAILURE : PSA_ERROR_DOES_NOT_EXIST;
}
+/* Updates the header of the GPT based on new number of partitions */
+static psa_status_t update_header(uint32_t num_partitions)
+{
+ primary_gpt.num_used_partitions = num_partitions;
+ struct gpt_header_t *header = &(primary_gpt.header);
+
+ /* Take the CRC of the partition array */
+ uint32_t crc = 0;
+ for (uint32_t i = 0; i < header->num_partitions; ++i) {
+ uint8_t entry_buf[header->entry_size];
+ memset(entry_buf, 0, header->entry_size);
+ struct gpt_entry_t *entry = (struct gpt_entry_t *)entry_buf;
+
+ psa_status_t ret = read_entry_from_flash(&primary_gpt, i, entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ crc = efi_soft_crc32_update(crc, entry_buf, header->entry_size);
+ }
+ header->array_crc = crc;
+
+ /* Calculate new CRC32 for primary header */
+ header->header_crc = 0;
+ header->header_crc = efi_soft_crc32_update(0, (uint8_t *)header, GPT_HEADER_SIZE);
+
+ /* Calculate new CRC32 for backup header */
+ struct gpt_header_t backup_header = {0};
+ swap_headers(header, &backup_header);
+ backup_header.header_crc = 0;
+ backup_crc32 = efi_soft_crc32_update(0, (uint8_t *)&backup_header, GPT_HEADER_SIZE);
+
+ /* Write headers */
+ const psa_status_t ret = write_headers_to_flash();
+ if (ret != PSA_SUCCESS) {
+ ERROR("Unable to write headers to flash\n");
+ return ret;
+ }
+
+ return PSA_SUCCESS;
+}
+
/* Load MBR from flash */
static psa_status_t mbr_load(struct mbr_t *mbr)
{
@@ -452,10 +657,16 @@ static psa_status_t mbr_load(struct mbr_t *mbr)
*/
static psa_status_t read_from_flash(uint64_t required_lba)
{
- ssize_t ret;
-
if (required_lba != cached_lba) {
- ret = plat_flash_driver->read(required_lba, lba_buf);
+ if (write_buffered && cached_lba != 0) {
+ psa_status_t ret = flush_lba_buf();
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ }
+ write_buffered = false;
+
+ ssize_t ret = plat_flash_driver->read(required_lba, lba_buf);
if (ret != TFM_GPT_BLOCK_SIZE) {
ERROR("Unable to read from flash at block 0x%08x%08x\n",
(uint32_t)(required_lba >> 32),
@@ -477,6 +688,14 @@ static uint64_t inline partition_entry_lba(const struct gpt_t *table,
return table->header.array_lba + (array_index / gpt_entry_per_lba_count());
}
+/* Returns the last LBA used by the partition entry array */
+static uint64_t inline partition_array_last_lba(const struct gpt_t *table)
+{
+ return (table->num_used_partitions == 0 ?
+ table->header.array_lba :
+ partition_entry_lba(table, table->num_used_partitions - 1));
+}
+
/* Returns the number of partition entries used in the array, assuming the
* array is not sparse
*/
@@ -539,6 +758,198 @@ static psa_status_t read_table_from_flash(struct gpt_t *table, bool is_primary)
return PSA_SUCCESS;
}
+/* Writes the in-memory LBA buffer to flash, taking care of multiple writes if
+ * needed.
+ */
+static psa_status_t flush_lba_buf(void)
+{
+ /* Prevent recursive calls, as the various writes below may attempt to
+ * flush, particularly those making multiple writes
+ */
+ static bool in_flush = false;
+ if (in_flush) {
+ return PSA_SUCCESS;
+ }
+ in_flush = true;
+ write_buffered = false;
+ psa_status_t ret = PSA_SUCCESS;
+
+ /* Commit to flash what is in the buffer. Also update the backup table if
+ * the cached LBA was part of the primary table (or vise-versa)
+ */
+ uint64_t array_size = partition_array_last_lba(&primary_gpt) - primary_gpt.header.array_lba + 1;
+
+ if (cached_lba == PRIMARY_GPT_LBA || (backup_gpt_lba != 0 && cached_lba == backup_gpt_lba)) {
+ /* Write both backup and primary headers */
+ ret = write_headers_to_flash();
+ } else if (PRIMARY_GPT_ARRAY_LBA <= cached_lba &&
+ cached_lba <= partition_array_last_lba(&primary_gpt))
+ {
+ /* Primary array entry. Write to backup and primary array */
+ ret = write_entries_to_flash(cached_lba - PRIMARY_GPT_ARRAY_LBA, false);
+ } else if (backup_gpt_array_lba != 0 &&
+ backup_gpt_array_lba <= cached_lba &&
+ cached_lba <= backup_gpt_array_lba + array_size - 1)
+ {
+ /* Backup array entry. Write to backup and primary array */
+ ret = write_entries_to_flash(cached_lba - backup_gpt_array_lba, false);
+ } else {
+ /* Shouldn't be possible */
+ ERROR("Unknown data in LBA cache, discarding\n");
+ }
+
+ in_flush = false;
+ return ret;
+}
+
+/* Write to the flash at the specified LBA */
+static psa_status_t write_to_flash(uint64_t lba)
+{
+ if (plat_flash_driver->erase(lba, 1) != 1) {
+ ERROR("Unable to erase flash at LBA 0x%08x%08x\n",
+ (uint32_t)(lba >> 32),
+ (uint32_t)lba);
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+
+ if (plat_flash_driver->write(lba, lba_buf) != TFM_GPT_BLOCK_SIZE) {
+ ERROR("Unable to program flash at LBA 0x%08x%08x\n",
+ (uint32_t)(lba >> 32),
+ (uint32_t)lba);
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+
+ return PSA_SUCCESS;
+}
+
+/* Writes the in-memory buffer to both the primary and backup partition arrays.
+ * This should only be used when it is certain that the cached lba is part of
+ * either the primary or backup partition array
+ */
+static psa_status_t write_entries_to_flash(uint32_t lbas_into_array, bool no_header_update)
+{
+ psa_status_t ret;
+
+ if (backup_gpt_array_lba != 0) {
+ ret = write_to_flash(backup_gpt_array_lba + lbas_into_array);
+ if (ret != PSA_SUCCESS) {
+ ERROR("Unable to write entry to backup partition array\n");
+ return ret;
+ }
+ } else {
+ WARN("Backup array LBA unknown!\n");
+ }
+
+ ret = write_to_flash(PRIMARY_GPT_ARRAY_LBA + lbas_into_array);
+ if (ret != PSA_SUCCESS) {
+ ERROR("Unable to write entry to primary partition array\n");
+ return ret;
+ }
+
+ /* Update the header unless the user specifies not to, This might be useful
+ * if it is known that multiple entries are being written, such as on removal
+ * or defragmentation operations
+ */
+ if (!no_header_update) {
+ return update_header(primary_gpt.num_used_partitions);
+ }
+
+ return PSA_SUCCESS;
+}
+
+/* Writes a GPT entry to flash or the in-memory buffer. The buffer is flushed
+ * to both the primary and backup partition entry arrays ocassionally. When the
+ * buffer is flushed, the header is updated unless no_header_update is true.
+ */
+static psa_status_t write_entry(uint32_t array_index,
+ const struct gpt_entry_t *entry,
+ bool no_header_update)
+{
+ /* Use this for a very simple, very dumb buffering heuristic. Flush every
+ * time an LBA's worth of entries have been written (flush every nth
+ * operation).
+ */
+ static uint32_t num_writes = 0;
+
+ /* First, ensure the entry is part of the buffered block. In most cases,
+ * this will be a no-op
+ */
+ psa_status_t ret = read_from_flash(partition_entry_lba(&primary_gpt, array_index));
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* Copy into buffer */
+ uint32_t index_in_lba = array_index % gpt_entry_per_lba_count();
+ memcpy(lba_buf + index_in_lba * primary_gpt.header.entry_size, entry, GPT_ENTRY_SIZE);
+
+ /* Write on every nth operation. */
+ if (++num_writes == gpt_entry_per_lba_count()) {
+ /* Write the buffer to flash */
+ num_writes = 0;
+ write_buffered = false;
+
+ ret = write_entries_to_flash(cached_lba - PRIMARY_GPT_ARRAY_LBA, no_header_update);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ } else {
+ write_buffered = true;
+ }
+
+ return PSA_SUCCESS;
+}
+
+/* Writes GPT header to flash. Returns PSA_SUCCESS on success or a PSA error on failure */
+static psa_status_t write_header_to_flash(const struct gpt_t *table)
+{
+ /* Ensure the in-memory LBA buffer has the header. Because the header is
+ * also in memory, there is no need to read it again before writing.
+ */
+ uint8_t temp_buf[GPT_HEADER_SIZE];
+ memcpy(temp_buf, lba_buf, GPT_HEADER_SIZE);
+ memcpy(lba_buf, &(table->header), GPT_HEADER_SIZE);
+ const psa_status_t ret = write_to_flash(table->header.current_lba);
+ memcpy(lba_buf, temp_buf, GPT_HEADER_SIZE);
+
+ return ret;
+}
+
+/* Writes GPT headers for backup and primary tables to flash. */
+static psa_status_t write_headers_to_flash(void)
+{
+ /* Backup table first, then primary */
+ struct gpt_t backup_gpt;
+ swap_headers(&(primary_gpt.header), &(backup_gpt.header));
+ backup_gpt.header.header_crc = backup_crc32;
+ psa_status_t ret = write_header_to_flash(&backup_gpt);
+ if (ret != PSA_SUCCESS) {
+ ERROR("Unable to write backup GPT header\n");
+ return ret;
+ }
+
+ ret = write_header_to_flash(&primary_gpt);
+ if (ret != PSA_SUCCESS) {
+ ERROR("Unable to write primary GPT header\n");
+ }
+
+ return ret;
+}
+
+/* Copies one header to another and swaps the fields referring to self
+ * and alternate headers. This is useful for primary to backup copies
+ * and vice-versa.
+ */
+static inline void swap_headers(const struct gpt_header_t *src, struct gpt_header_t *dst)
+{
+ memcpy(dst, src, GPT_HEADER_SIZE);
+ dst->backup_lba = src->current_lba;
+ dst->current_lba = src->backup_lba;
+ dst->array_lba = (src->current_lba == PRIMARY_GPT_LBA ?
+ backup_gpt_array_lba :
+ primary_gpt.header.array_lba);
+}
+
/* Converts unicode string to valid ascii */
static psa_status_t unicode_to_ascii(const char *unicode, char *ascii)
{
diff --git a/lib/gpt/unittests/gpt/test_gpt.c b/lib/gpt/unittests/gpt/test_gpt.c
index d6671f3fc..1121f7c73 100644
--- a/lib/gpt/unittests/gpt/test_gpt.c
+++ b/lib/gpt/unittests/gpt/test_gpt.c
@@ -10,6 +10,7 @@
#include "unity.h"
+#include "mock_efi_soft_crc.h"
#include "mock_tfm_log.h"
#include "mock_tfm_vprintf.h"
@@ -133,12 +134,16 @@ struct gpt_header_t {
static void register_mocked_read(void *buf, size_t num_bytes);
static ssize_t test_driver_read(uint64_t lba, void *buf);
+static ssize_t test_driver_write(uint64_t lba, const void *buf);
+static ssize_t test_driver_erase(uint64_t lba, size_t num_blocks);
/* LBA driver used in test module */
static struct gpt_flash_driver_t mock_driver = {
.init = NULL,
.uninit = NULL,
.read = test_driver_read,
+ .write = test_driver_write,
+ .erase = test_driver_erase,
};
/* Valid MBR. Only signature is required to be valid */
@@ -227,6 +232,17 @@ static ssize_t test_driver_read(uint64_t lba, void *buf)
return TEST_BLOCK_SIZE;
}
+/* Driver function that always succeeds in writing all data */
+static ssize_t test_driver_write(uint64_t lba, const void *buf)
+{
+ return TEST_BLOCK_SIZE;
+}
+
+static ssize_t test_driver_erase(uint64_t lba, size_t num_blocks)
+{
+ return num_blocks;
+}
+
/* Creates backup table from test table and registers a read for it */
static void setup_backup_gpt(void)
{
@@ -285,6 +301,9 @@ void setUp(void)
test_mbr.partitions[0].os_type = TEST_MBR_TYPE_GPT;
+ /* Any time this is called, return the same number and ignore the arguments */
+ efi_soft_crc32_update_IgnoreAndReturn(test_header.header_crc);
+
/* Ignore all logging calls */
tfm_log_Ignore();
@@ -337,6 +356,174 @@ void test_gpt_init_should_failWhenFlashDriverNotFullyDefined(void)
mock_driver.read = NULL;
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_init(&mock_driver, TEST_MAX_PARTITIONS));
mock_driver.read = read_fn;
+
+ gpt_flash_write_t write_fn = mock_driver.write;
+ mock_driver.write = NULL;
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_init(&mock_driver, TEST_MAX_PARTITIONS));
+ mock_driver.write = write_fn;
+
+ gpt_flash_erase_t erase_fn = mock_driver.erase;
+ mock_driver.erase = NULL;
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_init(&mock_driver, TEST_MAX_PARTITIONS));
+ mock_driver.erase = erase_fn;
+}
+
+void test_gpt_attr_set_should_setAttributes(void)
+{
+ /* Start with a populated GPT */
+ setup_valid_gpt();
+
+ /* Entries are read */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t guid = test_partition_array[0].guid;
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_attr_set(&guid, 0x1));
+}
+
+void test_gpt_attr_set_should_failWhenEntryNotExisting(void)
+{
+ setup_valid_gpt();
+
+ /* Read every entry */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t non_existing = NULL_GUID;
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_attr_set(&non_existing, 0x1));
+}
+
+void test_gpt_attr_remove_should_removeAttributes(void)
+{
+ /* Start with a populated GPT */
+ struct gpt_entry_t *test_entry = &(test_partition_array[0]);
+ uint64_t test_attr = 0x1;
+ test_entry->attr = test_attr;
+ setup_valid_gpt();
+
+ /* First entry is read */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t test_guid = test_entry->guid;
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_attr_set(&test_guid, test_attr));
+}
+
+void test_gpt_attr_remove_should_failWhenEntryNotExisting(void)
+{
+ setup_valid_gpt();
+
+ /* Read every entry */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t non_existing = NULL_GUID;
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_attr_remove(&non_existing, 0x1));
+}
+
+void test_gpt_attr_add_should_addAttributes(void)
+{
+ /* Start with a populated GPT */
+ struct gpt_entry_t *test_entry = &(test_partition_array[0]);
+ setup_valid_gpt();
+
+ /* First entry is read */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t test_guid = test_entry->guid;
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_attr_add(&test_guid, 0x1));
+}
+
+void test_gpt_attr_add_should_failWhenEntryNotExisting(void)
+{
+ setup_valid_gpt();
+
+ /* Read every entry */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t non_existing = NULL_GUID;
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_attr_add(&non_existing, 0x1));
+}
+
+void test_gpt_entry_change_type_should_setNewType(void)
+{
+ /* Start with a populated GPT */
+ struct gpt_entry_t *test_entry = &(test_partition_array[0]);
+ setup_valid_gpt();
+
+ /* First entry is read */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t test_guid = test_entry->guid;
+
+ /* Type validation is not a function of the library, as this is OS
+ * dependent, so anything will do here.
+ */
+ struct efi_guid_t new_type = MAKE_EFI_GUID(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_change_type(&test_guid, &new_type));
+}
+
+void test_gpt_entry_change_type_should_failWhenEntryNotExisting(void)
+{
+ setup_valid_gpt();
+
+ /* Read every entry */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t non_existing = NULL_GUID;
+ struct efi_guid_t new_type = MAKE_EFI_GUID(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_change_type(&non_existing, &new_type));
+}
+
+void test_gpt_entry_change_type_should_failWhenSettingTypeToNullGuid(void)
+{
+ setup_valid_gpt();
+
+ struct gpt_entry_t *test_entry = &(test_partition_array[0]);
+
+ /* First entry is read */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t test_guid = test_entry->guid;
+ struct efi_guid_t new_type = NULL_GUID;
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_change_type(&test_guid, &new_type));
+}
+
+void test_gpt_entry_rename_should_renameEntry(void)
+{
+ /* Start with a populated GPT */
+ struct gpt_entry_t *test_entry = &(test_partition_array[0]);
+ setup_valid_gpt();
+
+ /* First entry is read */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ char new_name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ new_name[0] = 'a';
+ struct efi_guid_t test_guid = test_entry->guid;
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_rename(&test_guid, new_name));
+}
+
+void test_gpt_entry_rename_should_failWhenNameIsEmpty(void)
+{
+ /* Start with a populated GPT */
+ struct gpt_entry_t *test_entry = &(test_partition_array[0]);
+ setup_valid_gpt();
+
+ /* Try to change name to an empty string */
+ struct efi_guid_t test_guid = test_entry->guid;
+ char name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_rename(&test_guid, name));
+}
+
+void test_gpt_entry_rename_should_failWhenEntryNotExisting(void)
+{
+ setup_valid_gpt();
+
+ /* Read every entry */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t non_existing = NULL_GUID;
+ char new_name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ new_name[0] = 'a';
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_rename(&non_existing, new_name));
}
void test_gpt_entry_read_should_populateEntry(void)
diff --git a/lib/gpt/unittests/gpt/utcfg.cmake b/lib/gpt/unittests/gpt/utcfg.cmake
index 37d72d138..620d15b4c 100644
--- a/lib/gpt/unittests/gpt/utcfg.cmake
+++ b/lib/gpt/unittests/gpt/utcfg.cmake
@@ -15,12 +15,14 @@ set(UNIT_TEST_SUITE ${CMAKE_CURRENT_LIST_DIR}/test_gpt.c)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/interface/include)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/efi_guid/inc)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/gpt/inc)
+list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/ext/efi_soft_crc/inc)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/tfm_log/inc)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/tfm_vprintf/inc)
# Headers to be mocked
list(APPEND MOCK_HEADERS ${TFM_ROOT_DIR}/lib/tfm_log/inc/tfm_log.h)
list(APPEND MOCK_HEADERS ${TFM_ROOT_DIR}/lib/tfm_vprintf/inc/tfm_vprintf.h)
+list(APPEND MOCK_HEADERS ${TFM_ROOT_DIR}/lib/ext/efi_soft_crc/inc/efi_soft_crc.h)
# Compile-time definitions
list(APPEND UNIT_TEST_COMPILE_DEFS LOG_LEVEL=LOG_LEVEL_VERBOSE)
@@ -0,0 +1,374 @@
From 7a453edd736c919eccc40eec567e8e97c0597bba Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Tue, 30 Dec 2025 09:13:07 +0000
Subject: [PATCH] lib: gpt: Added operation to move entry
The operation to move or resize an entry is not just a metadata change
and actually moves the data the partition entry points to as well.
Change-Id: Id6b98dcb3d77366db19e453acfbe4af59697eaf6
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [cbab5fd7757e9c06952c15ac7d30b0809b21406c]
---
lib/gpt/inc/gpt.h | 19 ++++
lib/gpt/src/gpt.c | 156 ++++++++++++++++++++++++++++++-
lib/gpt/unittests/gpt/test_gpt.c | 128 +++++++++++++++++++++++++
3 files changed, 301 insertions(+), 2 deletions(-)
diff --git a/lib/gpt/inc/gpt.h b/lib/gpt/inc/gpt.h
index 6e7bb360e..85f9bed9c 100644
--- a/lib/gpt/inc/gpt.h
+++ b/lib/gpt/inc/gpt.h
@@ -151,6 +151,25 @@ psa_status_t gpt_attr_remove(const struct efi_guid_t *guid, const uint64_t attr)
__attribute__((nonnull(1)))
psa_status_t gpt_attr_set(const struct efi_guid_t *guid, const uint64_t attr);
+/**
+ * \brief Moves (or resizes) a partition entry.
+ *
+ * \param[in] guid Entry to move.
+ * \param[in] start New start LBA.
+ * \param[in] end New end LBA.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_DOES_NOT_EXIST No entry found with the provided GUID.
+ * \retval PSA_ERROR_INVALID_ARGUMENT Move would overlap with an existing partition.
+ * \retval PSA_ERROR_INVALID_ARGUMENT \p end is less than \p start.
+ * \retval PSA_ERROR_INVALID_ARGUMENT Part of the partition would move off flash.
+ */
+__attribute__((nonnull(1)))
+psa_status_t gpt_entry_move(const struct efi_guid_t *guid,
+ const uint64_t start,
+ const uint64_t end);
+
/**
* \brief Reads the GPT header from the second block (LBA 1).
*
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index 2cfcdff07..40b73f3e9 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -214,6 +214,10 @@ static psa_status_t find_gpt_entry(const struct gpt_t *table,
const uint32_t repeat_index,
struct gpt_entry_t *entry,
uint32_t *array_index);
+static psa_status_t move_lba(const uint64_t old_lba, const uint64_t new_lba);
+static psa_status_t move_partition(const uint64_t old_lba,
+ const uint64_t new_lba,
+ const uint64_t num_blocks);
static psa_status_t mbr_load(struct mbr_t *mbr);
static bool gpt_entry_cmp_guid(const struct gpt_entry_t *entry, const void *guid);
static bool gpt_entry_cmp_name(const struct gpt_entry_t *entry, const void *name);
@@ -391,6 +395,111 @@ psa_status_t gpt_attr_set(const struct efi_guid_t *guid, const uint64_t attr)
return write_entry(cached_index, &cached_entry, false);
}
+psa_status_t gpt_entry_move(const struct efi_guid_t *guid,
+ const uint64_t start,
+ const uint64_t end)
+{
+ if (end < start) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Must fit on flash */
+ if (start < primary_gpt.header.first_lba ||
+ end < primary_gpt.header.first_lba ||
+ start > primary_gpt.header.last_lba ||
+ end > primary_gpt.header.last_lba)
+ {
+ ERROR("Requested move would not be on disk\n");
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ struct gpt_entry_t cached_entry;
+ uint32_t cached_index;
+ psa_status_t ret = find_gpt_entry(
+ &primary_gpt,
+ gpt_entry_cmp_guid,
+ guid,
+ 0,
+ &cached_entry,
+ &cached_index);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* Prevent unecessary I/O */
+ if (start == cached_entry.start && end == cached_entry.end) {
+ return PSA_SUCCESS;
+ }
+
+ /* It is not possible to move a partition such that it overlaps with an
+ * existing partition (other than itself). Check the currently cached LBA
+ * first, then the others to avoid reading this LBA twice
+ */
+ struct gpt_entry_t entry;
+ const uint64_t checked_lba = cached_lba;
+ const uint64_t array_end_lba = partition_array_last_lba(&primary_gpt);
+ uint32_t num_entries_in_cached_lba;
+ if (cached_lba == array_end_lba) {
+ /* If this is 0, then the last LBA is full */
+ uint32_t num_entries_in_last_lba = primary_gpt.num_used_partitions % gpt_entry_per_lba_count();
+ if (num_entries_in_last_lba == 0) {
+ num_entries_in_cached_lba = gpt_entry_per_lba_count();
+ } else {
+ num_entries_in_cached_lba = num_entries_in_last_lba;
+ }
+ } else {
+ num_entries_in_cached_lba = gpt_entry_per_lba_count();
+ }
+
+ /* Cached LBA */
+ for (uint32_t i = 0; i < num_entries_in_cached_lba; ++i) {
+ memcpy(&entry, lba_buf + (i * primary_gpt.header.entry_size), GPT_ENTRY_SIZE);
+
+ const struct efi_guid_t ent_guid = entry.unique_guid;
+ if (efi_guid_cmp(&ent_guid, guid) == 0) {
+ continue;
+ }
+
+ if ((start >= entry.start && start <= entry.end) ||
+ (end >= entry.start && end <= entry.end) ||
+ (start <= entry.start && end >= entry.end))
+ {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ /* All the rest */
+ for (uint32_t i = 0; i < primary_gpt.num_used_partitions; ++i) {
+ if (partition_entry_lba(&primary_gpt, i) == checked_lba) {
+ continue;
+ }
+
+ ret = read_entry_from_flash(&primary_gpt, i, &entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ if ((start >= entry.start && start <= entry.end) ||
+ (end >= entry.start && end <= entry.end) ||
+ (start <= entry.start && end >= entry.end))
+ {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ ret = move_partition(
+ cached_entry.start,
+ start,
+ end - start + 1);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ cached_entry.start = start;
+ cached_entry.end = end;
+
+ return write_entry(cached_index, &cached_entry, false);
+}
+
/* Initialises GPT from first block. */
psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_partitions)
{
@@ -586,6 +695,49 @@ static psa_status_t find_gpt_entry(const struct gpt_t *table,
return io_failure ? PSA_ERROR_STORAGE_FAILURE : PSA_ERROR_DOES_NOT_EXIST;
}
+/* Move a single LBAs data to somewhere else */
+static psa_status_t move_lba(const uint64_t old_lba, const uint64_t new_lba)
+{
+ const psa_status_t ret = read_from_flash(old_lba);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ return write_to_flash(new_lba);
+}
+
+/* Moves a partition's data to start from one logical block to another */
+static psa_status_t move_partition(const uint64_t old_lba,
+ const uint64_t new_lba,
+ const uint64_t num_blocks)
+{
+ if (old_lba == new_lba) {
+ return PSA_SUCCESS;
+ }
+
+ if (old_lba < new_lba) {
+ /* Move block by block backwards */
+ for (uint64_t block = num_blocks; block > 0; --block) {
+ const psa_status_t ret = move_lba(old_lba + block - 1, new_lba + block - 1);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ }
+ } else {
+ /* Move block by block forwards */
+ for (uint64_t block = 0; block < num_blocks; ++block) {
+ const psa_status_t ret = move_lba(old_lba + block, new_lba + block);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ }
+ }
+
+ write_buffered = false;
+
+ return PSA_SUCCESS;
+}
+
/* Updates the header of the GPT based on new number of partitions */
static psa_status_t update_header(uint32_t num_partitions)
{
@@ -794,8 +946,8 @@ static psa_status_t flush_lba_buf(void)
/* Backup array entry. Write to backup and primary array */
ret = write_entries_to_flash(cached_lba - backup_gpt_array_lba, false);
} else {
- /* Shouldn't be possible */
- ERROR("Unknown data in LBA cache, discarding\n");
+ /* Some other LBA is cached, possibly data. Write it anyway */
+ ret = write_to_flash(cached_lba);
}
in_flush = false;
diff --git a/lib/gpt/unittests/gpt/test_gpt.c b/lib/gpt/unittests/gpt/test_gpt.c
index 1121f7c73..251b04ee9 100644
--- a/lib/gpt/unittests/gpt/test_gpt.c
+++ b/lib/gpt/unittests/gpt/test_gpt.c
@@ -368,6 +368,134 @@ void test_gpt_init_should_failWhenFlashDriverNotFullyDefined(void)
mock_driver.erase = erase_fn;
}
+void test_gpt_entry_move_should_moveEntry(void)
+{
+ /* Start with a populated GPT */
+ setup_valid_gpt();
+ struct gpt_entry_t *test_entry = &(test_partition_array[TEST_DEFAULT_NUM_PARTITIONS - 1]);
+ struct efi_guid_t test_guid = test_entry->guid;
+
+ /* First all entries are read to determine for overlap */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ /* Move the partition. Read each block to then write. It doesn't matter what
+ * the data is
+ */
+ char unused_read_data = 'X';
+ register_mocked_read(&unused_read_data, sizeof(unused_read_data));
+
+ /* Header update - reads partition array to calculate crc32 and also then
+ * reads the header to modify and write back
+ */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ register_mocked_read(&test_header, sizeof(test_header));
+
+ /* Do a valid move and resize in one */
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_move(
+ &test_guid,
+ TEST_GPT_THIRD_PARTITION_END + 1,
+ TEST_GPT_THIRD_PARTITION_END + 1));
+}
+
+void test_gpt_entry_move_should_failWhenEntryNotExisting(void)
+{
+ setup_valid_gpt();
+
+ /* Read every entry */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ struct efi_guid_t non_existing = NULL_GUID;
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_move(
+ &non_existing,
+ TEST_GPT_THIRD_PARTITION_END + 1,
+ TEST_GPT_THIRD_PARTITION_END + 1));
+}
+
+void test_gpt_entry_move_should_failWhenEndLessThanStart(void)
+{
+ setup_valid_gpt();
+
+ struct efi_guid_t test_guid = test_partition_array[0].guid;
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_move(
+ &test_guid,
+ TEST_GPT_THIRD_PARTITION_END + 2,
+ TEST_GPT_THIRD_PARTITION_END + 1));
+}
+
+void test_gpt_entry_move_should_failWhenLbaOverlapping(void)
+{
+ setup_valid_gpt();
+
+ /* Try to move an entry. Each entry is read to determine for overlap */
+ size_t test_index = 1;
+ struct gpt_entry_t *test_entry = &(test_partition_array[test_index]);
+ struct efi_guid_t test_guid = test_entry->guid;
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ /* Try to move the test entry into the middle of the entry just read.
+ * Starting at the same LBA
+ */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_move(
+ &test_guid,
+ TEST_GPT_FIRST_PARTITION_START,
+ TEST_GPT_SECOND_PARTITION_END));
+
+ /* Try to move the test entry into the middle of the entry just read.
+ * Starting in the middle
+ */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_move(
+ &test_guid,
+ TEST_GPT_FIRST_PARTITION_START + 1,
+ TEST_GPT_SECOND_PARTITION_END));
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_move(
+ &test_guid,
+ TEST_GPT_SECOND_PARTITION_START,
+ TEST_GPT_THIRD_PARTITION_START));
+
+ /* Try to move the test entry into the middle of the entry just read.
+ * Starting and ending in the middle.
+ */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_move(
+ &test_guid,
+ TEST_GPT_FIRST_PARTITION_START + 1,
+ TEST_GPT_FIRST_PARTITION_START + 1));
+}
+
+void test_gpt_entry_move_should_failWhenLbaOffDisk(void)
+{
+ setup_valid_gpt();
+
+ /* Try to move an entry. */
+ size_t test_index = 1;
+ struct gpt_entry_t *test_entry = &(test_partition_array[test_index]);
+ struct efi_guid_t test_guid = test_entry->guid;
+
+ /* First start on disk, then go off the disk */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_move(
+ &test_guid,
+ TEST_GPT_THIRD_PARTITION_END + 1,
+ TEST_DISK_NUM_BLOCKS + 1));
+
+ /* Second, start off the disk entirely */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_move(
+ &test_guid,
+ TEST_DISK_NUM_BLOCKS + 1,
+ TEST_DISK_NUM_BLOCKS + 2));
+
+ /* Third, do the same but in the header area */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_move(
+ &test_guid,
+ TEST_GPT_PRIMARY_LBA,
+ TEST_GPT_THIRD_PARTITION_END + 2));
+
+ /* Fourth, start in the backup header area */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_move(
+ &test_guid,
+ TEST_GPT_BACKUP_LBA,
+ TEST_GPT_BACKUP_LBA + 1));
+}
+
void test_gpt_attr_set_should_setAttributes(void)
{
/* Start with a populated GPT */
@@ -0,0 +1,713 @@
From bec8f44a2732c20e8f69a06841637673af90c37e Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Tue, 30 Dec 2025 10:16:21 +0000
Subject: [PATCH] lib: gpt: Added ability to create and remove partitions
With this change, new GPT partitions can be created and added to the
table and old partitions can be removed. Both of these are metadata
changes and only make changes to the partition entry array and header
(primary and backup).
New partitions must be created in empty space only. The data that the
partition points to is not cleared and if desired this should be done by
the caller before or after creation.
When a partition is removed, the data it pointed to is not cleared so
this should be done by the caller if desired. After removal, that data
is considered empty space.
Change-Id: Iecccb814aaf8f48cbdd8e29b3d2b54fb5b58aae8
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [4d69babc99917e3cc2df284a311ec37004c3ee3f]
---
lib/gpt/CMakeLists.txt | 1 +
lib/gpt/inc/gpt.h | 37 +++
lib/gpt/src/gpt.c | 249 ++++++++++++++-
lib/gpt/unittests/gpt/test_gpt.c | 284 ++++++++++++++++++
lib/gpt/unittests/gpt/utcfg.cmake | 2 +
.../include/mbedtls/mbedtls_config.h | 18 ++
6 files changed, 590 insertions(+), 1 deletion(-)
create mode 100644 lib/gpt/unittests/include/mbedtls/mbedtls_config.h
diff --git a/lib/gpt/CMakeLists.txt b/lib/gpt/CMakeLists.txt
index 25d0de9cd..5befc346f 100644
--- a/lib/gpt/CMakeLists.txt
+++ b/lib/gpt/CMakeLists.txt
@@ -23,6 +23,7 @@ target_sources(tfm_gpt
target_include_directories(tfm_gpt
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
+ $<INSTALL_INTERFACE:inc>
)
target_compile_definitions(tfm_gpt
diff --git a/lib/gpt/inc/gpt.h b/lib/gpt/inc/gpt.h
index 85f9bed9c..f04643957 100644
--- a/lib/gpt/inc/gpt.h
+++ b/lib/gpt/inc/gpt.h
@@ -170,6 +170,43 @@ psa_status_t gpt_entry_move(const struct efi_guid_t *guid,
const uint64_t start,
const uint64_t end);
+/**
+ * \brief Creates a partition entry in the table.
+ *
+ * \param[in] type Partition type.
+ * \param[in] start Starting LBA (0 uses the lowest free LBA possible).
+ * \param[in] size Size of the partition in LBAs.
+ * \param[in] attr Attributes for the partition.
+ * \param[in] name Partition name in unicode.
+ * \param[out] guid GUID populated on success for subsequent API calls.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_INSUFFICIENT_STORAGE Maximum number of partitions reached.
+ * \retval PSA_ERROR_INVALID_ARGUMENT Partition would extend beyond the flash.
+ * \retval PSA_ERROR_INVALID_ARGUMENT New entry would overlap an existing partition, the name is empty,
+ * or \p size is zero.
+ */
+__attribute__((nonnull(1,5,6)))
+psa_status_t gpt_entry_create(const struct efi_guid_t *type,
+ const uint64_t start,
+ const uint64_t size,
+ const uint64_t attr,
+ const char name[GPT_ENTRY_NAME_LENGTH],
+ struct efi_guid_t *guid);
+
+/**
+ * \brief Removes a partition entry from the table.
+ *
+ * \param[in] guid Entry to remove.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_DOES_NOT_EXIST No entry found with the provided GUID.
+ */
+__attribute__((nonnull(1)))
+psa_status_t gpt_entry_remove(const struct efi_guid_t *guid);
+
/**
* \brief Reads the GPT header from the second block (LBA 1).
*
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index 40b73f3e9..676f04fd6 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -9,11 +9,12 @@
#include <string.h>
#include <inttypes.h>
-#include "psa/error.h"
+#include "psa/crypto.h"
#include "gpt.h"
#include "gpt_flash.h"
#include "tfm_log.h"
#include "efi_guid_structs.h"
+#include "efi_guid.h"
#include "efi_soft_crc.h"
/* This needs to be defined by the platform and is used by the GPT library as
@@ -500,6 +501,252 @@ psa_status_t gpt_entry_move(const struct efi_guid_t *guid,
return write_entry(cached_index, &cached_entry, false);
}
+psa_status_t gpt_entry_create(const struct efi_guid_t *type,
+ const uint64_t start,
+ const uint64_t size,
+ const uint64_t attr,
+ const char name[GPT_ENTRY_NAME_LENGTH],
+ struct efi_guid_t *guid)
+{
+ /* Using inequlity here handles when reading an initial GPT has more than
+ * the maximum defined number of partitions.
+ */
+ if (primary_gpt.num_used_partitions >= plat_max_partitions) {
+ ERROR("Maximum number of partitions reached\n");
+ return PSA_ERROR_INSUFFICIENT_STORAGE;
+ }
+ if (size == 0) {
+ ERROR("Cannot create entry of size 0\n");
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ if (name[0] == '\0') {
+ ERROR("Cannot create entry with no name\n");
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ uint64_t start_lba = start;
+ psa_status_t ret = PSA_SUCCESS;
+ if (start_lba == 0) {
+ /* Use the lowest free LBA possible. Each partition uses contiguous space,
+ * so if there is a gap between partitions, that will be shown by the end
+ * and start not being contiguous.
+ */
+ uint64_t prev_end = primary_gpt.header.first_lba;
+ for (uint32_t i = 0; i < primary_gpt.header.num_partitions; ++i) {
+ struct gpt_entry_t entry = {0};
+ ret = read_entry_from_flash(&primary_gpt, i, &entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ if (entry.start - 1 > prev_end) {
+ start_lba = prev_end + 1;
+ break;
+ }
+ prev_end = entry.end;
+ }
+
+ if (start_lba != prev_end + 1) {
+ /* No free space */
+ ERROR("No free space on device!\n");
+ return PSA_ERROR_INSUFFICIENT_STORAGE;
+ }
+ }
+
+ /* Must fit on flash */
+ const uint64_t end_lba = start_lba + size - 1;
+ if (start_lba < primary_gpt.header.first_lba ||
+ end_lba < primary_gpt.header.first_lba ||
+ start_lba > primary_gpt.header.last_lba ||
+ end_lba > primary_gpt.header.last_lba)
+ {
+ ERROR("Requested partition would not be on disk\n");
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Do not allow overlapping partitions */
+ struct gpt_entry_t entry;
+ for (uint32_t i = 0; i < primary_gpt.num_used_partitions; ++i) {
+ ret = read_entry_from_flash(&primary_gpt, i, &entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ if ((start_lba >= entry.start && start_lba <= entry.end) ||
+ (end_lba >= entry.start && end_lba <= entry.end) ||
+ (start_lba <= entry.start && end_lba >= entry.end))
+ {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ /* Generate the new random GUID */
+ if (efi_guid_generate_random(guid) != PSA_SUCCESS) {
+ ERROR("Unable to generate GUID\n");
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+
+ /* Set new entry's metadata */
+ struct gpt_entry_t new_entry = {0};
+ new_entry.start = start_lba;
+ new_entry.end = end_lba;
+ new_entry.attr = attr;
+ memcpy(new_entry.name, name, GPT_ENTRY_NAME_LENGTH);
+ new_entry.partition_type = *type;
+ new_entry.unique_guid = *guid;
+
+ /* Write the new entry. Skip header update as it is explicitely called
+ * below with new number of partitions
+ */
+ ret = write_entry(primary_gpt.num_used_partitions++, &new_entry, true);
+ if (ret != PSA_SUCCESS) {
+ --primary_gpt.num_used_partitions;
+ return ret;
+ }
+
+ /* Flush the buffered LBA if not done so. This will cause the header to be
+ * updated
+ */
+ if (write_buffered) {
+ /* flush_lba_buf will update the header */
+ ret = flush_lba_buf();
+ } else {
+ ret = update_header(primary_gpt.num_used_partitions);
+ }
+
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t gpt_entry_remove(const struct efi_guid_t *guid)
+{
+ struct gpt_entry_t cached_entry;
+ uint32_t cached_index;
+ psa_status_t ret = find_gpt_entry(
+ &primary_gpt,
+ gpt_entry_cmp_guid,
+ guid,
+ 0,
+ &cached_entry,
+ &cached_index);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* Shuffle the remainder of the array up. This will overwrite the
+ * most previous entry.
+ *
+ * The first LBA to potentially modify is in memory. It doesn't need
+ * to be modified if the last entry in the array was moved or if it is
+ * the only LBA used by the partition array
+ */
+ if (cached_index != primary_gpt.num_used_partitions - 1 ||
+ cached_index < gpt_entry_per_lba_count())
+ {
+ /* Shuffle up the remainder of the LBA. If it was the last entry
+ * in the LBA, there is nothing to do.
+ */
+ const uint32_t lba_index = cached_index % gpt_entry_per_lba_count();
+ if (lba_index + 1 != gpt_entry_per_lba_count()) {
+ memmove(
+ lba_buf + lba_index * primary_gpt.header.entry_size,
+ lba_buf + (lba_index + 1) * primary_gpt.header.entry_size,
+ (gpt_entry_per_lba_count() - lba_index - 1) * primary_gpt.header.entry_size);
+ }
+
+ /* If this is not the last LBA, then read the next LBA into memory and
+ * place it's first element in the final slot of the currently modified
+ * LBA. Repeat this for each LBA read.
+ *
+ * Use a second buffer to read each consecutive LBA and copy that to
+ * the global LBA buffer to then write afterwards.
+ */
+ const uint64_t array_end_lba = partition_array_last_lba(&primary_gpt);
+ for (uint64_t i = partition_entry_lba(&primary_gpt, cached_index) + 1;
+ i <= array_end_lba;
+ ++i)
+ {
+ uint8_t array_buf[TFM_GPT_BLOCK_SIZE] = {0};
+ int read_ret = plat_flash_driver->read(i, array_buf);
+ if (read_ret != TFM_GPT_BLOCK_SIZE) {
+ ERROR("Unable to read LBA 0x%08x%08x\n",
+ (uint32_t)(i >> 32), (uint32_t)i);
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+
+ memcpy(
+ lba_buf + primary_gpt.header.entry_size * (gpt_entry_per_lba_count() - 1),
+ array_buf,
+ GPT_ENTRY_SIZE);
+
+ /* Write to backup first, then primary partition array */
+ if (backup_gpt_array_lba != 0) {
+ ret = write_to_flash(backup_gpt_array_lba + i - 1 - PRIMARY_GPT_ARRAY_LBA);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ }
+ ret = write_to_flash(i - 1);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ memmove(
+ array_buf,
+ array_buf + primary_gpt.header.entry_size,
+ sizeof(array_buf) - primary_gpt.header.entry_size);
+ memcpy(lba_buf, array_buf, TFM_GPT_BLOCK_SIZE);
+ }
+
+ /* What was the final LBA is now cached and may be empty or partially-filled */
+ cached_lba = array_end_lba;
+ write_buffered = false;
+ uint32_t entries_in_last_lba = (--primary_gpt.num_used_partitions) % gpt_entry_per_lba_count();
+ if (entries_in_last_lba == 0) {
+ /* There's nothing left in this LBA, so zero it all and write it out.
+ * There is also no need to do an erase just to zero afterwards.
+ */
+ memset(lba_buf, 0, TFM_GPT_BLOCK_SIZE);
+ if (backup_gpt_array_lba != 0) {
+ int write_ret = plat_flash_driver->write(
+ backup_gpt_array_lba + array_end_lba - PRIMARY_GPT_ARRAY_LBA,
+ lba_buf);
+ if (write_ret != TFM_GPT_BLOCK_SIZE) {
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+ }
+ int write_ret = plat_flash_driver->write(array_end_lba, lba_buf);
+ if (write_ret != TFM_GPT_BLOCK_SIZE) {
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+ } else {
+ /* Zero what is not needed anymore */
+ memset(
+ lba_buf + primary_gpt.header.entry_size * entries_in_last_lba,
+ 0,
+ (gpt_entry_per_lba_count() - entries_in_last_lba) * primary_gpt.header.entry_size);
+ if (backup_gpt_array_lba != 0) {
+ ret = write_to_flash(backup_gpt_array_lba + array_end_lba - PRIMARY_GPT_ARRAY_LBA);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ }
+ ret = write_to_flash(array_end_lba);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ }
+ }
+
+ /* Update the header after flash changes */
+ ret = update_header(primary_gpt.num_used_partitions);
+
+ return ret;
+}
+
/* Initialises GPT from first block. */
psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_partitions)
{
diff --git a/lib/gpt/unittests/gpt/test_gpt.c b/lib/gpt/unittests/gpt/test_gpt.c
index 251b04ee9..18cf2c8f3 100644
--- a/lib/gpt/unittests/gpt/test_gpt.c
+++ b/lib/gpt/unittests/gpt/test_gpt.c
@@ -10,6 +10,7 @@
#include "unity.h"
+#include "mock_efi_guid.h"
#include "mock_efi_soft_crc.h"
#include "mock_tfm_log.h"
#include "mock_tfm_vprintf.h"
@@ -368,6 +369,260 @@ void test_gpt_init_should_failWhenFlashDriverNotFullyDefined(void)
mock_driver.erase = erase_fn;
}
+void test_gpt_entry_create_should_createNewEntry(void)
+{
+ /* Add an entry. It must not overlap with an existing entry and must also
+ * fit on the storage device. The GUID should be populated with something.
+ */
+ setup_valid_gpt();
+
+ /* Each entry will be read in order to check that it doesn't overlap with
+ * any of them
+ */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ /* Update header. Read each entry for CRC calculation. */
+ struct gpt_entry_t new_entry = {
+ .type = NULL_GUID,
+ .start = TEST_GPT_THIRD_PARTITION_END + 1,
+ .end = TEST_GPT_THIRD_PARTITION_END + 1,
+ .attr = 0,
+ .name = "Fourth partition"
+ };
+
+ /* Mock out the call to create a new GUID */
+ struct efi_guid_t expected_guid = MAKE_EFI_GUID(5, 5, 5, 5, 5, 6, 7, 8, 9, 10, 11);
+ efi_guid_generate_random_ExpectAnyArgsAndReturn(PSA_SUCCESS);
+ efi_guid_generate_random_ReturnThruPtr_guid(&expected_guid);
+
+ /* Ensure also the that a new GUID is assigned */
+ struct efi_guid_t new_guid = MAKE_EFI_GUID(4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11);
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_create(
+ &expected_guid,
+ new_entry.start,
+ new_entry.end - new_entry.start + 1,
+ new_entry.attr,
+ new_entry.name,
+ &new_guid));
+ TEST_ASSERT_EQUAL_MEMORY(&expected_guid, &new_guid, sizeof(new_guid));
+}
+
+void test_gpt_entry_create_should_createNewEntryNextToLastEntry(void)
+{
+ /* Add an entry, allowing the library to choose the start LBA.
+ * The GUID should be populated with something.
+ */
+ setup_valid_gpt();
+
+ /* Each entry will be read in order to check that it doesn't overlap with
+ * any of them
+ */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ /* Update header. Read each entry for CRC calculation. */
+ struct gpt_entry_t new_entry = {
+ .type = NULL_GUID,
+ .start = TEST_GPT_THIRD_PARTITION_END + 1,
+ .end = TEST_GPT_THIRD_PARTITION_END + 1,
+ .attr = 0,
+ .name = "Fourth partition"
+ };
+
+ /* Mock out the call to create a new GUID */
+ struct efi_guid_t expected_guid = MAKE_EFI_GUID(5, 5, 5, 5, 5, 6, 7, 8, 9, 10, 11);
+ efi_guid_generate_random_ExpectAnyArgsAndReturn(PSA_SUCCESS);
+ efi_guid_generate_random_ReturnThruPtr_guid(&expected_guid);
+
+ /* Ensure also the that a new GUID is assigned */
+ struct efi_guid_t new_guid = MAKE_EFI_GUID(4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11);
+ char name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ name[0] = 'a';
+
+ /* Ensure also the that a new GUID is assigned */
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_create(
+ &expected_guid,
+ 0,
+ 1,
+ new_entry.attr,
+ name,
+ &new_guid));
+ TEST_ASSERT_EQUAL_MEMORY(&expected_guid, &new_guid, sizeof(new_guid));
+}
+
+void test_gpt_entry_create_should_failToCreateEntryWhenLowestFreeLbaDoesNotHaveSpace(void)
+{
+ /* Add an entry, allowing the library to choose the start LBA.
+ * The GUID should be populated with something.
+ */
+ setup_valid_gpt();
+
+ /* Each entry will be read in order to check that it doesn't overlap with
+ * any of them
+ */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ /* Ensure also the that a new GUID is assigned */
+ struct efi_guid_t existing_guid = MAKE_EFI_GUID(4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11);
+ struct efi_guid_t new_guid;
+ char name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ name[0] = 'a';
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_create(
+ &(existing_guid),
+ 0,
+ TEST_DISK_NUM_BLOCKS,
+ 0,
+ name,
+ &(new_guid)));
+}
+
+void test_gpt_entry_create_should_failWhenTableFull(void)
+{
+ /* Start with a full array of entries */
+ struct gpt_entry_t new_entry = {
+ .type = MAKE_EFI_GUID(4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11),
+ .start = TEST_GPT_THIRD_PARTITION_END + 1,
+ .end = TEST_GPT_THIRD_PARTITION_END + 1,
+ .attr = 0,
+ .guid = MAKE_EFI_GUID(4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11),
+ .name = "Fourth partition"
+ };
+ test_partition_array[TEST_MAX_PARTITIONS - 1] = new_entry;
+ setup_valid_gpt();
+
+ struct efi_guid_t type = MAKE_EFI_GUID(5, 5, 5, 5, 5, 6, 7, 8, 9, 10, 11);
+ struct efi_guid_t guid;
+ char name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ name[0] = 'a';
+ TEST_ASSERT_EQUAL(PSA_ERROR_INSUFFICIENT_STORAGE, gpt_entry_create(
+ &type,
+ TEST_GPT_THIRD_PARTITION_END + 4,
+ 1,
+ 0,
+ name,
+ &guid));
+}
+
+void test_gpt_entry_create_should_failWhenLbaOffDisk(void)
+{
+ setup_valid_gpt();
+
+ /* First start on disk, then go off the disk */
+ struct efi_guid_t type = NULL_GUID;
+ struct efi_guid_t guid;
+ char name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ name[0] = 'a';
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_create(
+ &type,
+ TEST_GPT_THIRD_PARTITION_END + 1,
+ 1000,
+ 0,
+ name,
+ &guid));
+
+ /* Second, start off the disk entirely */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_create(
+ &type,
+ TEST_DISK_NUM_BLOCKS + 100,
+ 1,
+ 0,
+ name,
+ &guid));
+
+ /* Third, do the same but in the header area */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_create(
+ &type,
+ TEST_GPT_PRIMARY_LBA,
+ 1,
+ 0,
+ name,
+ &guid));
+
+ /* Fourth, start in the backup header area */
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_create(
+ &type,
+ TEST_GPT_BACKUP_LBA,
+ 1,
+ 0,
+ name,
+ &guid));
+}
+
+void test_gpt_entry_create_should_failWhenOverlapping(void)
+{
+ setup_valid_gpt();
+
+ /* Since the disk is not fragmented by default, there are two test cases:
+ * 1. start in the middle of a partition and end in the middle of a partition
+ * 2. start in the middle of a partition and end in free space
+ */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ struct efi_guid_t type = NULL_GUID;
+ struct efi_guid_t guid;
+ char name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ name[0] = 'a';
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_create(
+ &type,
+ TEST_GPT_FIRST_PARTITION_START,
+ TEST_GPT_FIRST_PARTITION_END - TEST_GPT_FIRST_PARTITION_START + 1,
+ 0,
+ name,
+ &guid));
+
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_create(
+ &type,
+ TEST_GPT_FIRST_PARTITION_START,
+ TEST_GPT_LAST_USABLE_LBA - TEST_GPT_FIRST_PARTITION_START,
+ 0,
+ name,
+ &guid));
+}
+
+void test_gpt_entry_create_should_failWhenNameIsEmpty(void)
+{
+ /* Start with a populated GPT */
+ setup_valid_gpt();
+
+ struct efi_guid_t type = NULL_GUID;
+ struct gpt_entry_t new_entry = {
+ .type = type,
+ .start = TEST_GPT_THIRD_PARTITION_END + 1,
+ .end = TEST_GPT_THIRD_PARTITION_END + 1,
+ .attr = 0,
+ };
+
+ /* Make an entry with an empty name */
+ char name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ struct efi_guid_t new_guid;
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_create(
+ &type,
+ new_entry.start,
+ 1,
+ 0,
+ name,
+ &new_guid));
+}
+
+void test_gpt_entry_create_should_failWhenSizeIsZero(void)
+{
+ /* Start with a populated GPT */
+ setup_valid_gpt();
+
+ struct efi_guid_t type = NULL_GUID;
+
+ /* Make the size zero */
+ struct efi_guid_t new_guid;
+ char name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ name[0] = 'a';
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_entry_create(
+ &type,
+ TEST_GPT_THIRD_PARTITION_END + 1,
+ 0,
+ 0,
+ name,
+ &new_guid));
+}
+
void test_gpt_entry_move_should_moveEntry(void)
{
/* Start with a populated GPT */
@@ -654,6 +909,35 @@ void test_gpt_entry_rename_should_failWhenEntryNotExisting(void)
TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_rename(&non_existing, new_name));
}
+void test_gpt_entry_remove_should_removeEntry(void)
+{
+ /* Start with a populated GPT */
+ setup_valid_gpt();
+
+ /* Each entry is read */
+ struct gpt_entry_t *test_entry = &(default_partition_array[TEST_DEFAULT_NUM_PARTITIONS - 1]);
+ struct efi_guid_t test_guid = test_entry->guid;
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_remove(&test_guid));
+}
+
+void test_gpt_entry_remove_should_failWhenEntryNotExisting(void)
+{
+ /* Start by trying to remove from an empty table */
+ setup_empty_gpt();
+
+ struct efi_guid_t non_existing = NULL_GUID;
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_remove(&non_existing));
+
+ /* Now, have a non-empty GPT but search for a non-existing GUID */
+ setup_valid_gpt();
+
+ /* Each entry should be read. */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_remove(&non_existing));
+}
+
void test_gpt_entry_read_should_populateEntry(void)
{
/* Start with a populated GPT */
diff --git a/lib/gpt/unittests/gpt/utcfg.cmake b/lib/gpt/unittests/gpt/utcfg.cmake
index 620d15b4c..f3f4e7dcc 100644
--- a/lib/gpt/unittests/gpt/utcfg.cmake
+++ b/lib/gpt/unittests/gpt/utcfg.cmake
@@ -15,11 +15,13 @@ set(UNIT_TEST_SUITE ${CMAKE_CURRENT_LIST_DIR}/test_gpt.c)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/interface/include)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/efi_guid/inc)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/gpt/inc)
+list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/gpt/unittests/include)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/ext/efi_soft_crc/inc)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/tfm_log/inc)
list(APPEND UNIT_TEST_INCLUDE_DIRS ${TFM_ROOT_DIR}/lib/tfm_vprintf/inc)
# Headers to be mocked
+list(APPEND MOCK_HEADERS ${TFM_ROOT_DIR}/lib/efi_guid/inc/efi_guid.h)
list(APPEND MOCK_HEADERS ${TFM_ROOT_DIR}/lib/tfm_log/inc/tfm_log.h)
list(APPEND MOCK_HEADERS ${TFM_ROOT_DIR}/lib/tfm_vprintf/inc/tfm_vprintf.h)
list(APPEND MOCK_HEADERS ${TFM_ROOT_DIR}/lib/ext/efi_soft_crc/inc/efi_soft_crc.h)
diff --git a/lib/gpt/unittests/include/mbedtls/mbedtls_config.h b/lib/gpt/unittests/include/mbedtls/mbedtls_config.h
new file mode 100644
index 000000000..5144daae3
--- /dev/null
+++ b/lib/gpt/unittests/include/mbedtls/mbedtls_config.h
@@ -0,0 +1,18 @@
+/*
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MBEDTLS_CONFIG_H
+#define MBEDTLS_CONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
@@ -0,0 +1,412 @@
From c0037dc1779d181ce7d7dbd5871519c9d218440a Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Tue, 30 Dec 2025 10:29:47 +0000
Subject: [PATCH] lib: gpt: Added table validation operations
Added validate and restore operations. Both of these operate on the
entirety of the table and allow the caller to:
1. determine if the GPT is valid or not.
2. restore a GPT from the alternative at the other end of the storage
device.
Both of these operations can be performed on either the primary or
backup table to allow full recovery.
Change-Id: Ie5ac2fdc42858cb439a2dcd08f4203eb181d4e88
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [62a038e80574e094e64617953748633737cd760d]
---
lib/gpt/inc/gpt.h | 22 ++++
lib/gpt/src/gpt.c | 184 +++++++++++++++++++++++++++++++
lib/gpt/unittests/gpt/test_gpt.c | 135 +++++++++++++++++++++++
3 files changed, 341 insertions(+)
diff --git a/lib/gpt/inc/gpt.h b/lib/gpt/inc/gpt.h
index f04643957..0ce4d04ab 100644
--- a/lib/gpt/inc/gpt.h
+++ b/lib/gpt/inc/gpt.h
@@ -207,6 +207,28 @@ psa_status_t gpt_entry_create(const struct efi_guid_t *type,
__attribute__((nonnull(1)))
psa_status_t gpt_entry_remove(const struct efi_guid_t *guid);
+/**
+ * \brief Validates the GPT.
+ *
+ * \param[in] is_primary True to validate the primary table, false to validate the backup.
+ *
+ * \retval PSA_SUCCESS GPT is valid.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_INVALID_SIGNATURE GPT is invalid.
+ */
+psa_status_t gpt_validate(bool is_primary);
+
+/**
+ * \brief Restores either the primary or backup GPT from the other copy.
+ *
+ * \param[in] is_primary True to restore the primary table, false to restore the backup.
+ *
+ * \retval PSA_SUCCESS GPT restored.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_INVALID_SIGNATURE Restoring GPT invalid; cannot restore.
+ */
+psa_status_t gpt_restore(bool is_primary);
+
/**
* \brief Reads the GPT header from the second block (LBA 1).
*
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index 676f04fd6..1bc592bb3 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -223,6 +223,8 @@ static psa_status_t mbr_load(struct mbr_t *mbr);
static bool gpt_entry_cmp_guid(const struct gpt_entry_t *entry, const void *guid);
static bool gpt_entry_cmp_name(const struct gpt_entry_t *entry, const void *name);
static bool gpt_entry_cmp_type(const struct gpt_entry_t *entry, const void *type);
+static psa_status_t validate_table(struct gpt_t *table, bool is_primary);
+static psa_status_t restore_table(struct gpt_t *restore_from, bool is_primary);
/* PUBLIC API FUNCTIONS */
@@ -747,6 +749,76 @@ psa_status_t gpt_entry_remove(const struct efi_guid_t *guid)
return ret;
}
+psa_status_t gpt_validate(bool is_primary)
+{
+ if (!is_primary && (backup_gpt_lba == 0 || backup_gpt_array_lba == 0)) {
+ ERROR("Backup GPT location unknown!\n");
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+
+ /* Flush and invalidate the in-memory buffer before attempting to validate
+ * a table. The in-memory header needs to be updated if the flushed LBA was
+ * part of the entry array
+ */
+ psa_status_t ret;
+ if (write_buffered) {
+ ret = flush_lba_buf();
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ write_buffered = false;
+ }
+ cached_lba = 0;
+
+ if (is_primary) {
+ return validate_table(&primary_gpt, true);
+ } else {
+ struct gpt_t backup_gpt;
+ ret = read_table_from_flash(&backup_gpt, false);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ return validate_table(&backup_gpt, false);
+ }
+}
+
+psa_status_t gpt_restore(bool is_primary)
+{
+ if (!is_primary && (backup_gpt_lba == 0 || backup_gpt_array_lba == 0)) {
+ ERROR("Backup GPT location unknown!\n");
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+
+ /* Flush and invalidate the in-memory buffer before attempting to restore a
+ * table. The in-memory header needs to be updated if the flushed LBA was
+ * part of the entry array
+ */
+ psa_status_t ret;
+ if (write_buffered) {
+ ret = flush_lba_buf();
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ write_buffered = false;
+ }
+ cached_lba = 0;
+
+ if (is_primary) {
+ struct gpt_t backup_gpt;
+ ret = read_table_from_flash(&backup_gpt, false);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ ret = count_used_partitions(&backup_gpt, &backup_gpt.num_used_partitions);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ return restore_table(&backup_gpt, false);
+ } else {
+ return restore_table(&primary_gpt, true);
+ }
+}
+
/* Initialises GPT from first block. */
psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_partitions)
{
@@ -1349,6 +1421,118 @@ static inline void swap_headers(const struct gpt_header_t *src, struct gpt_heade
primary_gpt.header.array_lba);
}
+/* Validates a specific GPT. */
+static psa_status_t validate_table(struct gpt_t *table, bool is_primary)
+{
+ struct gpt_header_t *header = &(table->header);
+
+ /* Check signature */
+ if (strncmp(header->signature, GPT_SIG, GPT_SIG_LEN) != 0) {
+ ERROR("Invalid GPT signature\n");
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ /* Check header CRC */
+ uint32_t calc_crc = 0;
+ uint32_t old_crc = header->header_crc;
+ header->header_crc = 0;
+ calc_crc = efi_soft_crc32_update(calc_crc, (uint8_t *)header, GPT_HEADER_SIZE);
+ header->header_crc = old_crc;
+
+ if (old_crc != calc_crc) {
+ ERROR("CRC of header does not match, expected 0x%x got 0x%x\n",
+ old_crc, calc_crc);
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ /* Check MyLBA field points to this table */
+ const uint64_t table_lba = (is_primary ? PRIMARY_GPT_LBA : backup_gpt_lba);
+ if (table_lba != header->current_lba) {
+ ERROR("MyLBA not pointing to this GPT, expected 0x%08x%08x, got 0x%08x%08x\n",
+ (uint32_t)(table_lba >> 32),
+ (uint32_t)table_lba,
+ (uint32_t)(header->current_lba >> 32),
+ (uint32_t)(header->current_lba));
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ /* Check the CRC of the partition array */
+ calc_crc = 0;
+ for (uint32_t i = 0; i < header->num_partitions; ++i) {
+ uint8_t entry_buf[header->entry_size];
+ memset(entry_buf, 0, header->entry_size);
+ struct gpt_entry_t *entry = (struct gpt_entry_t *)entry_buf;
+
+ psa_status_t ret = read_entry_from_flash(table, i, entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ calc_crc = efi_soft_crc32_update(calc_crc, (uint8_t *)entry, header->entry_size);
+ }
+
+ if (calc_crc != header->array_crc) {
+ ERROR("CRC of partition array does not match, expected 0x%x got 0x%x\n",
+ calc_crc, header->array_crc);
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ if (is_primary) {
+ /* Any time the primary table is considered valid, cache the backup
+ * LBA field
+ */
+ backup_gpt_lba = header->backup_lba;
+ } else {
+ /* Any time backup table is considered valid, cache its array LBA
+ * field and crc32
+ */
+ backup_gpt_array_lba = header->array_lba;
+ backup_crc32 = header->header_crc;
+ }
+ return PSA_SUCCESS;
+}
+
+/* Restore a table from another. The second parameter indicates whether the
+ * restoring table is the primary GPT or not
+ */
+static psa_status_t restore_table(struct gpt_t *restore_from, bool is_primary)
+{
+ /* Determine if the restoring GPT is valid */
+ psa_status_t ret = validate_table(restore_from, is_primary);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ struct gpt_t restore_to;
+ swap_headers(&(restore_from->header), &(restore_to.header));
+
+ /* Copy the partition array as well */
+ ret = move_partition(
+ restore_from->header.array_lba,
+ restore_to.header.array_lba,
+ (restore_from->header.num_partitions +
+ gpt_entry_per_lba_count() - 1) / gpt_entry_per_lba_count());
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* Write the header */
+ ret = write_header_to_flash(&restore_to);
+ if (ret != PSA_SUCCESS) {
+ ERROR("Unable to write %s GPT header\n", is_primary ? "backup" : "primary");
+ return ret;
+ }
+
+ /* The primary GPT is cached in memory */
+ if (!is_primary) {
+ memcpy(&(primary_gpt.header), &(restore_to.header), GPT_HEADER_SIZE);
+ primary_gpt.num_used_partitions = restore_from->num_used_partitions;
+ }
+
+ INFO("Successfully restored %s GPT table\n", is_primary ? "backup" : "primary");
+
+ return 0;
+}
+
/* Converts unicode string to valid ascii */
static psa_status_t unicode_to_ascii(const char *unicode, char *ascii)
{
diff --git a/lib/gpt/unittests/gpt/test_gpt.c b/lib/gpt/unittests/gpt/test_gpt.c
index 18cf2c8f3..f15a0a737 100644
--- a/lib/gpt/unittests/gpt/test_gpt.c
+++ b/lib/gpt/unittests/gpt/test_gpt.c
@@ -369,6 +369,141 @@ void test_gpt_init_should_failWhenFlashDriverNotFullyDefined(void)
mock_driver.erase = erase_fn;
}
+void test_gpt_validate_should_validateWhenGptGood(void)
+{
+ setup_test_gpt();
+
+ /* Each entry will be read in order to check the partition array CRC */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_validate(true));
+
+ /* Now do the backup */
+ setup_backup_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_validate(false));
+}
+
+void test_gpt_validate_should_failWhenGptSigBad(void)
+{
+ test_header.signature[0] = '\0';
+ setup_test_gpt();
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* Now do the backup */
+ setup_backup_gpt();
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+}
+
+void test_gpt_validate_should_failWhenHeaderCrcBad(void)
+{
+ test_header.header_crc--;
+ setup_test_gpt();
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* Now do the backup */
+ struct gpt_header_t backup_header;
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+ backup_header.header_crc--;
+ register_mocked_read(&backup_header, sizeof(backup_header));
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+}
+
+void test_gpt_validate_should_failWhenLbaPointerBad(void)
+{
+ test_header.current_lba = 2;
+ test_header.backup_lba = 3;
+ setup_test_gpt();
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* Now set the backup LBA to be something different that what it should be
+ * to force a mismatch
+ */
+ test_header.current_lba = default_header.current_lba;
+ test_header.backup_lba = default_header.backup_lba - 1;
+
+ /* Now do the backup */
+ struct gpt_header_t backup_header;
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+ register_mocked_read(&backup_header, sizeof(backup_header));
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+}
+
+void test_gpt_validate_should_failWhenArrayCrcBad(void)
+{
+ test_header.array_crc--;
+ setup_test_gpt();
+
+ /* Each entry will be read in order to check the partition array CRC */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* Now do the backup */
+ struct gpt_header_t backup_header;
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+ backup_header.array_crc--;
+ register_mocked_read(&backup_header, sizeof(test_partition_array));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+}
+
+void test_gpt_restore_should_restorePrimaryFromBackup(void)
+{
+ /* Start with a valid GPT */
+ setup_valid_gpt();
+
+ /* The backup table is read and checked for validity, including taking
+ * CRC32 of partition array
+ */
+ setup_backup_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_restore(true));
+}
+
+void test_gpt_restore_should_failToRestoreWhenBackupIsBad(void)
+{
+ /* Start with a valid GPT */
+ setup_valid_gpt();
+
+ /* The backup table is read and checked for validity. Corrupt it in
+ * various ways
+ */
+ struct gpt_header_t backup_header;
+
+ /* Bad signature */
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+ backup_header.signature[0] = '\0';
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_restore(true));
+
+ /* Bad header CRC */
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+ backup_header.header_crc = 0;
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_restore(true));
+
+ /* Bad LBA */
+ test_header.backup_lba = 2;
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_restore(true));
+ test_header.backup_lba = default_header.backup_lba;
+
+ /* Bad array CRC. Will involve reading array entries */
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+ backup_header.array_crc = 0;
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_restore(true));
+}
+
void test_gpt_entry_create_should_createNewEntry(void)
{
/* Add an entry. It must not overlap with an existing entry and must also
@@ -0,0 +1,280 @@
From ba38f0f304ad69047ce9830b81a4f9cfbccb8fcb Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Tue, 30 Dec 2025 10:51:57 +0000
Subject: [PATCH] lib: gpt: Added defragmentation operation
Defragmentation moves all of used data of the device to the beginning
such that all of the free space is afterwards towards the end. This is
less meaningful on flash devices however is still provided as an
operation for completeness. This is done by ordering the partition entry
array first, so that it is safe to shuffle data in one direction without
risk of data loss/overwriting.
Change-Id: Ic401c79ac8c1fba2489ab2680efc02139c759c66
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [21ff1f85c0b5463c1ea75fd61d872c0029eed902]
---
lib/gpt/inc/gpt.h | 8 ++
lib/gpt/src/gpt.c | 190 +++++++++++++++++++++++++++++++
lib/gpt/unittests/gpt/test_gpt.c | 7 ++
3 files changed, 205 insertions(+)
diff --git a/lib/gpt/inc/gpt.h b/lib/gpt/inc/gpt.h
index 0ce4d04ab..baf4767f9 100644
--- a/lib/gpt/inc/gpt.h
+++ b/lib/gpt/inc/gpt.h
@@ -229,6 +229,14 @@ psa_status_t gpt_validate(bool is_primary);
*/
psa_status_t gpt_restore(bool is_primary);
+/**
+ * \brief Defragments the GPT, ensuring free space becomes contiguous.
+ *
+ * \retval PSA_SUCCESS Success.
+ * \retval PSA_ERROR_STORAGE_FAILURE I/O failure.
+ */
+psa_status_t gpt_defragment(void);
+
/**
* \brief Reads the GPT header from the second block (LBA 1).
*
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index 1bc592bb3..b1d4597cd 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -6,6 +6,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
@@ -225,6 +226,7 @@ static bool gpt_entry_cmp_name(const struct gpt_entry_t *entry, const void *name
static bool gpt_entry_cmp_type(const struct gpt_entry_t *entry, const void *type);
static psa_status_t validate_table(struct gpt_t *table, bool is_primary);
static psa_status_t restore_table(struct gpt_t *restore_from, bool is_primary);
+static psa_status_t sort_partition_array(struct gpt_t *table);
/* PUBLIC API FUNCTIONS */
@@ -819,6 +821,66 @@ psa_status_t gpt_restore(bool is_primary)
}
}
+psa_status_t gpt_defragment(void)
+{
+ /* First, sort the partition array according to start LBA. This means that
+ * moving partitions towards the start of the flash sequentially is safe
+ * and will not result in lost data.
+ */
+ psa_status_t ret = sort_partition_array(&primary_gpt);
+ if (ret != PSA_SUCCESS) {
+ WARN("Unable to defragment flash!\n");
+ return ret;
+ }
+
+ uint64_t prev_end = primary_gpt.header.first_lba;
+ struct gpt_entry_t entry;
+
+ for (uint32_t i = 0; i < primary_gpt.num_used_partitions; ++i) {
+ ret = read_entry_from_flash(&primary_gpt, i, &entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* Move to be next to previous entry. Continue if already where it
+ * needs to be.
+ */
+ if (prev_end == entry.start) {
+ prev_end = entry.end + 1;
+ continue;
+ }
+
+ const uint64_t num_blocks = entry.end - entry.start + 1;
+ ret = move_partition(entry.start, prev_end, num_blocks);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* Update header information */
+ entry.start = prev_end;
+ entry.end = entry.start + num_blocks - 1;
+ prev_end = entry.end + 1;
+
+ /* Write the entry change, skipping header update until every entry
+ * written
+ */
+ ret = write_entry(i, &entry, true);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ }
+
+ /* Write everything to flash after defragmentation if not done so already.
+ * The previous loop will write the last entry to the LBA buffer, which may
+ * or not may not be flushed
+ */
+ if (write_buffered) {
+ return flush_lba_buf();
+ }
+
+ return update_header(primary_gpt.num_used_partitions);
+}
+
/* Initialises GPT from first block. */
psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_partitions)
{
@@ -1533,6 +1595,134 @@ static psa_status_t restore_table(struct gpt_t *restore_from, bool is_primary)
return 0;
}
+/* Comparison function to pass to qsort */
+static int cmp_u64(const void *a, const void *b)
+{
+ const uint64_t *a_u64 = (const uint64_t *)a;
+ const uint64_t *b_u64 = (const uint64_t *)b;
+ return (*a_u64 > *b_u64) - (*a_u64 < *b_u64);
+}
+
+/* bsearch but returns the index rather than the item */
+static int64_t bsearch_index(uint64_t arr[], uint32_t len, uint64_t key)
+{
+ uint32_t l = 0;
+ uint32_t r = len;
+
+ while (l < r) {
+ uint32_t m = l + (r - l) / 2;
+ uint64_t item = arr[m];
+
+ if (item < key) {
+ l = m + 1;
+ } else if (item > key) {
+ r = m;
+ } else {
+ return (int64_t)m;
+ }
+ }
+
+ return -1;
+}
+
+/* Sorts the partition array for the given table by the start LBA for each
+ * partition. This makes defragmentation easier.
+ */
+static psa_status_t sort_partition_array(struct gpt_t *table)
+{
+ /* To avoid as much I/O as possible, the LBA's for each entry are sorted in
+ * memory and then the entries rearranged on flash after
+ */
+ uint64_t lba_arr[table->num_used_partitions];
+ psa_status_t ret;
+ for (uint32_t i = 0; i < table->num_used_partitions; ++i) {
+ struct gpt_entry_t entry;
+ ret = read_entry_from_flash(table, i, &entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ lba_arr[i] = entry.start;
+ }
+
+ qsort(lba_arr, table->num_used_partitions, sizeof(uint64_t), cmp_u64);
+
+ /* Now read and place the entries in the correct spot, starting with the
+ * first. Each entry is dealt with as it is encountered. When an entry is
+ * found and already in the correct spot, the next smallest index not yet
+ * handled becomes the next.
+ */
+ struct gpt_entry_t saved_entry = {0};
+ struct gpt_entry_t curr_entry;
+ uint8_t handled_indices[table->num_used_partitions];
+ memset(handled_indices, 0, table->num_used_partitions);
+
+ ret = read_entry_from_flash(table, 0, &curr_entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ for (uint32_t i = 0; i < table->num_used_partitions; ++i) {
+ const int64_t new_index = bsearch_index(
+ lba_arr,
+ table->num_used_partitions,
+ curr_entry.start);
+ if (new_index < 0) {
+ ERROR("Encountered unknown partition entry!\n");
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+
+ /* For final entry, just write it out */
+ if (i == table->num_used_partitions - 1) {
+ ret = write_entry((uint32_t)new_index, &curr_entry, false);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ break;
+ }
+
+ /* Replace the entry in the new_index place with the current entry */
+ ret = read_entry_from_flash(table, (uint32_t)new_index, &saved_entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ struct efi_guid_t saved_guid = saved_entry.unique_guid;
+ struct efi_guid_t curr_guid = curr_entry.unique_guid;
+ if (efi_guid_cmp(&saved_guid, &curr_guid) == 0) {
+ /* This entry is already where it needs to be, so try the smallest
+ * index not yet handled next
+ */
+ handled_indices[new_index] = 1;
+ uint32_t next_entry = 0;
+ while(next_entry < table->num_used_partitions && handled_indices[next_entry]) {
+ ++next_entry;
+ }
+
+ if (next_entry == table->num_used_partitions) {
+ /* Done everything */
+ break;
+ }
+
+ ret = read_entry_from_flash(table, next_entry, &saved_entry);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ } else {
+ /* Write, skipping header update until very end */
+ ret = write_entry((uint32_t)new_index, &curr_entry, true);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ }
+
+ /* Ready up for the next loop */
+ curr_entry = saved_entry;
+ handled_indices[new_index] = 1;
+ }
+
+ return PSA_SUCCESS;
+}
+
/* Converts unicode string to valid ascii */
static psa_status_t unicode_to_ascii(const char *unicode, char *ascii)
{
diff --git a/lib/gpt/unittests/gpt/test_gpt.c b/lib/gpt/unittests/gpt/test_gpt.c
index f15a0a737..2f05a6b4a 100644
--- a/lib/gpt/unittests/gpt/test_gpt.c
+++ b/lib/gpt/unittests/gpt/test_gpt.c
@@ -504,6 +504,13 @@ void test_gpt_restore_should_failToRestoreWhenBackupIsBad(void)
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_restore(true));
}
+void test_gpt_defragment_should_succeedWhenNoIOFailure(void)
+{
+ setup_valid_gpt();
+
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_defragment());
+}
+
void test_gpt_entry_create_should_createNewEntry(void)
{
/* Add an entry. It must not overlap with an existing entry and must also
@@ -0,0 +1,74 @@
From f9e4d1f48a4553278dc4de82b0d2f4d82b1e5193 Mon Sep 17 00:00:00 2001
From: Antonio de Angelis <antonio.deangelis@arm.com>
Date: Wed, 4 Mar 2026 13:05:51 +0000
Subject: [PATCH] lib: GPT: Fix cppcheck warnings
Change-Id: Ia9e99dc59cbf869b804a24ba029f19f7170860b4
Signed-off-by: Antonio de Angelis <antonio.deangelis@arm.com>
Upstream-Status: Backport [92d5b6b7d296c174364e684508089c0a0678e3bb]
---
lib/gpt/src/gpt.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index b1d4597cd..a9dbb918e 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
@@ -194,7 +195,7 @@ static inline uint64_t gpt_entry_per_lba_count(void);
static inline void swap_headers(const struct gpt_header_t *src, struct gpt_header_t *dst);
static psa_status_t count_used_partitions(const struct gpt_t *table,
uint32_t *num_used);
-static inline void parse_entry(struct gpt_entry_t *entry,
+static inline void parse_entry(const struct gpt_entry_t *entry,
struct partition_entry_t *partition_entry);
static psa_status_t read_from_flash(uint64_t required_lba);
static psa_status_t read_entry_from_flash(const struct gpt_t *table,
@@ -226,7 +227,7 @@ static bool gpt_entry_cmp_name(const struct gpt_entry_t *entry, const void *name
static bool gpt_entry_cmp_type(const struct gpt_entry_t *entry, const void *type);
static psa_status_t validate_table(struct gpt_t *table, bool is_primary);
static psa_status_t restore_table(struct gpt_t *restore_from, bool is_primary);
-static psa_status_t sort_partition_array(struct gpt_t *table);
+static psa_status_t sort_partition_array(const struct gpt_t *table);
/* PUBLIC API FUNCTIONS */
@@ -1006,7 +1007,7 @@ static inline uint64_t gpt_entry_per_lba_count(void)
}
/* Copies information from the entry to the user visible structure */
-static inline void parse_entry(struct gpt_entry_t *entry,
+static inline void parse_entry(const struct gpt_entry_t *entry,
struct partition_entry_t *partition_entry)
{
partition_entry->start = entry->start;
@@ -1604,7 +1605,7 @@ static int cmp_u64(const void *a, const void *b)
}
/* bsearch but returns the index rather than the item */
-static int64_t bsearch_index(uint64_t arr[], uint32_t len, uint64_t key)
+static int64_t bsearch_index(const uint64_t arr[], uint32_t len, uint64_t key)
{
uint32_t l = 0;
uint32_t r = len;
@@ -1628,8 +1629,12 @@ static int64_t bsearch_index(uint64_t arr[], uint32_t len, uint64_t key)
/* Sorts the partition array for the given table by the start LBA for each
* partition. This makes defragmentation easier.
*/
-static psa_status_t sort_partition_array(struct gpt_t *table)
+static psa_status_t sort_partition_array(const struct gpt_t *table)
{
+ if (table->num_used_partitions == 0) {
+ assert(table->num_used_partitions > 0);
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
/* To avoid as much I/O as possible, the LBA's for each entry are sorted in
* memory and then the entries rearranged on flash after
*/
@@ -0,0 +1,28 @@
From 31cd6d9eb82792efd5af7d99802581eace13a083 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 13 Mar 2026 17:10:25 +0000
Subject: [PATCH] lib: efi_guid: Remove unecessary include folder
There are no header files in the src folder, so there is nothing to
include. This line was redundant.
Change-Id: I5289932119629fc1ef6a71f0a0ceb63e5a466c96
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [e74a1f467317c16487b9d41f43f147dd41985cb9]
---
lib/efi_guid/CMakeLists.txt | 2 --
1 file changed, 2 deletions(-)
diff --git a/lib/efi_guid/CMakeLists.txt b/lib/efi_guid/CMakeLists.txt
index 656eb72ea..9c4771cba 100644
--- a/lib/efi_guid/CMakeLists.txt
+++ b/lib/efi_guid/CMakeLists.txt
@@ -15,8 +15,6 @@ target_sources(tfm_efi_guid
target_include_directories(tfm_efi_guid
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
- PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_link_libraries(tfm_efi_guid
@@ -0,0 +1,28 @@
From 0b6a2e681b0f76c425896990ebc4afcbc65419d3 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 13 Mar 2026 17:11:05 +0000
Subject: [PATCH] lib: efi_guid: Correct included folder
The use of the variables is unecessary and has no real effect. This
change is therefore simplified.
Change-Id: I0811b4768502d15b62f1af3ef90a56db3e9df525
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [7bb11e81cd69718df3b11a3f8b42a3b5edf4c42d]
---
lib/efi_guid/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/efi_guid/CMakeLists.txt b/lib/efi_guid/CMakeLists.txt
index 9c4771cba..95d7b8f1e 100644
--- a/lib/efi_guid/CMakeLists.txt
+++ b/lib/efi_guid/CMakeLists.txt
@@ -14,7 +14,7 @@ target_sources(tfm_efi_guid
target_include_directories(tfm_efi_guid
PUBLIC
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
+ inc
)
target_link_libraries(tfm_efi_guid
@@ -0,0 +1,25 @@
From f1862245d39a726c8e37f58498dd433c6fd99d1b Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 13 Mar 2026 17:13:07 +0000
Subject: [PATCH] lib: efi_soft_crc: Correct include directory
The variables had no real effect, so this is therefore simplified.
Change-Id: Ifa03bc23e0419f9d6d598e7753f23dfde57c7bf6
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [3856d55117b727c6c21bb821fa4236b113fb08ef]
---
lib/ext/efi_soft_crc/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/ext/efi_soft_crc/CMakeLists.txt b/lib/ext/efi_soft_crc/CMakeLists.txt
index 47fd2d507..d77310167 100644
--- a/lib/ext/efi_soft_crc/CMakeLists.txt
+++ b/lib/ext/efi_soft_crc/CMakeLists.txt
@@ -14,5 +14,5 @@ target_sources(tfm_efi_soft_crc
target_include_directories(tfm_efi_soft_crc
PUBLIC
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
+ inc
)
@@ -0,0 +1,27 @@
From 343bba6c20802555dfb92c3e2b22a7e07c10a57a Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 13 Mar 2026 17:16:00 +0000
Subject: [PATCH] lib: gpt: Add missing link library
tfm_log requires tfm_vprintf. When building for a platform with logging
enabled, these headers are therefore required.
Change-Id: I63b35d5af818ea5ad7b1fe76200250ad98584a63
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [92a3738634fe121766705599d66e4a8b772ce06e]
---
lib/gpt/CMakeLists.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/gpt/CMakeLists.txt b/lib/gpt/CMakeLists.txt
index 5befc346f..ed31adfbe 100644
--- a/lib/gpt/CMakeLists.txt
+++ b/lib/gpt/CMakeLists.txt
@@ -36,6 +36,7 @@ target_compile_definitions(tfm_gpt
target_link_libraries(tfm_gpt
PUBLIC
tfm_log_headers
+ tfm_vprintf_headers
PRIVATE
tfm_efi_guid
tfm_efi_soft_crc
@@ -0,0 +1,24 @@
From 1ae97df8db8babcaa999e47d9641c83c4ee8424a Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 13 Mar 2026 17:17:33 +0000
Subject: [PATCH] lib: gpt: Correct variable name used
Change-Id: I86d616b3c86cf0a1fd053b732565477278030d89
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [bc9522f5c47c7e3f3a92189073166e73323010e9]
---
lib/gpt/unittests/gpt/utcfg.cmake | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/gpt/unittests/gpt/utcfg.cmake b/lib/gpt/unittests/gpt/utcfg.cmake
index f3f4e7dcc..69a1d10bd 100644
--- a/lib/gpt/unittests/gpt/utcfg.cmake
+++ b/lib/gpt/unittests/gpt/utcfg.cmake
@@ -27,6 +27,6 @@ list(APPEND MOCK_HEADERS ${TFM_ROOT_DIR}/lib/tfm_vprintf/inc/tfm_vprintf.h)
list(APPEND MOCK_HEADERS ${TFM_ROOT_DIR}/lib/ext/efi_soft_crc/inc/efi_soft_crc.h)
# Compile-time definitions
-list(APPEND UNIT_TEST_COMPILE_DEFS LOG_LEVEL=LOG_LEVEL_VERBOSE)
+list(APPEND UNIT_TEST_COMPILE_DEFS GPT_LOG_LEVEL=LOG_LEVEL_VERBOSE)
list(APPEND UNIT_TEST_COMPILE_DEFS TFM_GPT_BLOCK_SIZE=512)
@@ -0,0 +1,27 @@
From eb934a532bbc8385cd9b062fc80cece61350f086 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 13 Mar 2026 17:19:50 +0000
Subject: [PATCH] lib: gpt: Correct include directory
The variables have no real effect, so therefore this is simplified.
Change-Id: Ie912941f8eafd9cd5bf4dd88927640ad70d0676a
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [369c897be0b9102cec8141c53b3d3fe6abb56b6e]
---
lib/gpt/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/gpt/CMakeLists.txt b/lib/gpt/CMakeLists.txt
index ed31adfbe..19cfe5bc2 100644
--- a/lib/gpt/CMakeLists.txt
+++ b/lib/gpt/CMakeLists.txt
@@ -22,7 +22,7 @@ target_sources(tfm_gpt
target_include_directories(tfm_gpt
PUBLIC
- $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
+ inc
$<INSTALL_INTERFACE:inc>
)
@@ -0,0 +1,51 @@
From ce3a4f3dd8900c068f2bfe951d55b895e3c10d43 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 13 Mar 2026 17:29:04 +0000
Subject: [PATCH] lib: gpt: Move contents of CMake config file
A config.cmake used in a library can be a little confusing, especially
considering that such files are used for platform configurations. The
contents of the file are placed directly in the CMakeLists.txt that was
including it.
Change-Id: I8a88971feebaf37498828af5854de94e74e16f2c
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [4b569b02b98a577e45e833f4dd9886e54df71a7d]
---
lib/gpt/CMakeLists.txt | 6 +++---
lib/gpt/config.cmake | 8 --------
2 files changed, 3 insertions(+), 11 deletions(-)
delete mode 100644 lib/gpt/config.cmake
diff --git a/lib/gpt/CMakeLists.txt b/lib/gpt/CMakeLists.txt
index 19cfe5bc2..4a15173fd 100644
--- a/lib/gpt/CMakeLists.txt
+++ b/lib/gpt/CMakeLists.txt
@@ -9,10 +9,10 @@ cmake_minimum_required(VERSION 3.21)
add_library(tfm_gpt STATIC)
-include(./config.cmake)
+set(GPT_LOG_LEVEL LOG_LEVEL_INFO CACHE STRING "Set default log level for the GPT library")
-if(NOT DEFINED TFM_GPT_BLOCK_SIZE OR NOT DEFINED GPT_LOG_LEVEL)
- message(FATAL_ERROR "TFM_GPT_BLOCK_SIZE and GPT_LOG_LEVEL must be defined to use GPT library")
+if(NOT DEFINED TFM_GPT_BLOCK_SIZE)
+ message(FATAL_ERROR "TFM_GPT_BLOCK_SIZE must be defined to use GPT library")
endif()
target_sources(tfm_gpt
diff --git a/lib/gpt/config.cmake b/lib/gpt/config.cmake
deleted file mode 100644
index 9575aa8a8..000000000
--- a/lib/gpt/config.cmake
+++ /dev/null
@@ -1,8 +0,0 @@
-#-------------------------------------------------------------------------------
-# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-
-set(GPT_LOG_LEVEL LOG_LEVEL_INFO CACHE STRING "Set default log level for the GPT library")
@@ -0,0 +1,261 @@
From 9402dd67413e74284bc598225b4c5399fbd1a099 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Wed, 19 Nov 2025 17:12:13 +0000
Subject: [PATCH] plat: cs1k: Fixed formatting errors
Many of these were tab characters, however the style guide for this repo
is clear that spaces shall be used.
Sometimes the wrong number of spaces was used and that is fixed here as
well.
Change-Id: I4c797d1de9723961eac707476e249062653aece0
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49423]
---
.../target/arm/corstone1000/CMakeLists.txt | 6 +-
.../bootloader/mcuboot/tfm_mcuboot_fwu.c | 60 +++++++++----------
2 files changed, 33 insertions(+), 33 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/CMakeLists.txt b/platform/ext/target/arm/corstone1000/CMakeLists.txt
index 993c51591..58edae74e 100644
--- a/platform/ext/target/arm/corstone1000/CMakeLists.txt
+++ b/platform/ext/target/arm/corstone1000/CMakeLists.txt
@@ -242,7 +242,7 @@ target_include_directories(platform_bl1_1_interface
${PLATFORM_DIR}/ext/target/arm/drivers/usart/pl011
$<$<BOOL:${CRYPTO_HW_ACCELERATOR}>:${CMAKE_SOURCE_DIR}/platform/ext/accelerator/interface>
${PLATFORM_DIR}/ext/accelerator/cc312/
- ${CMAKE_SOURCE_DIR}/lib/fih/inc/
+ ${CMAKE_SOURCE_DIR}/lib/fih/inc/
)
target_link_libraries(platform_bl1_1
@@ -289,7 +289,7 @@ target_include_directories(platform_bl1_2
${PLATFORM_DIR}/ext/target/arm/drivers/flash/n25q256a/
${PLATFORM_DIR}/ext/target/arm/drivers/flash/sst26vf064b/
${PLATFORM_DIR}/ext/accelerator/cc312/
- ${CMAKE_SOURCE_DIR}/interface/include # for psa/error.h
+ ${CMAKE_SOURCE_DIR}/interface/include # for psa/error.h
)
#========================= Platform BL2 =======================================#
@@ -397,7 +397,7 @@ target_include_directories(platform_bl2
${MCUBOOT_PATH}/boot/bootutil/include # for fault_injection_hardening.h only
${CMAKE_BINARY_DIR}/bl2/ext/mcuboot # for mcuboot_config.h only
$<BUILD_INTERFACE:${BL2_SOURCE}/ext/mcuboot/include>
- ${CMAKE_SOURCE_DIR}/interface/include # for psa/error.h
+ ${CMAKE_SOURCE_DIR}/interface/include # for psa/error.h
)
#========================= ns_agent_mailbox ===================================#
diff --git a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
index a458b5478..cff80b755 100644
--- a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
+++ b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
@@ -995,7 +995,7 @@ psa_status_t fwu_metadata_provision(void)
static uint8_t get_fwu_image_state(
struct fwu_metadata *metadata,
struct fwu_private_metadata *priv_metadata,
- uint32_t fwu_image_index)
+ uint32_t fwu_image_index)
{
FWU_LOG_MSG("%s: enter\n\r", __func__);
@@ -1305,12 +1305,12 @@ psa_status_t corstone1000_fwu_host_ack(void)
ret = PSA_SUCCESS; /* nothing to be done */
- for (int i = 0; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
- fmp_set_image_info(&fwu_image[i].image_guid,
- priv_metadata.fmp_version[i],
- priv_metadata.fmp_last_attempt_version[i],
- priv_metadata.fmp_last_attempt_status[i]);
- }
+ for (int i = 0; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
+ fmp_set_image_info(&fwu_image[i].image_guid,
+ priv_metadata.fmp_version[i],
+ priv_metadata.fmp_last_attempt_version[i],
+ priv_metadata.fmp_last_attempt_status[i]);
+ }
goto out;
@@ -1322,13 +1322,13 @@ psa_status_t corstone1000_fwu_host_ack(void)
/* firmware update failed, revert back to previous bank */
- for (int i = 0; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
+ for (int i = 0; i < NR_OF_IMAGES_IN_FW_BANK; i++) {
if(get_fwu_image_state(&_metadata, &priv_metadata, i) == PSA_FWU_TRIAL) {
priv_metadata.fmp_last_attempt_version[i] =
_metadata.fw_desc.img_entry[i].img_props[_metadata.active_index].version;
priv_metadata.fmp_last_attempt_status[i] = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
- }
+ }
}
ret = fwu_select_previous(&_metadata, &priv_metadata);
@@ -1455,14 +1455,14 @@ psa_status_t fwu_stage_nv_counter(enum fwu_nv_counter_index_t index,
psa_status_t corstone1000_fwu_flash_image(void)
{
- return PSA_SUCCESS;
+ return PSA_SUCCESS;
}
/* Verify if image index is valid or not */
bool is_image_index_valid(uint8_t fwu_image_index) {
return (fwu_image_index != FWU_FAKE_IMAGE_INDEX &&
fwu_image_index != FWU_IMAGE_INDEX_ESRT &&
- fwu_image_index < FWU_COMPONENT_NUMBER);
+ fwu_image_index < FWU_COMPONENT_NUMBER);
}
static psa_status_t get_esrt_data(struct fwu_esrt_data_wrapper *esrt)
@@ -1585,8 +1585,8 @@ static void fmp_header_image_info_init()
for (int i=0; i<FWU_COMPONENT_NUMBER; i++)
{
fmp_header_image_info[i].fmp_hdr_size_recvd = 0;
- fmp_header_image_info[i].image_size_recvd = 0;
- memset(&fmp_header_image_info[i].fmp_hdr, 0, sizeof(fmp_header_image_info[i].fmp_hdr));
+ fmp_header_image_info[i].image_size_recvd = 0;
+ memset(&fmp_header_image_info[i].fmp_hdr, 0, sizeof(fmp_header_image_info[i].fmp_hdr));
}
}
@@ -1598,7 +1598,7 @@ static psa_status_t erase_staging_area(struct fwu_metadata* metadata, psa_fwu_co
if (!is_image_index_valid(component)) {
FWU_LOG_MSG("%s: Invalid Component received \n\r", __func__);
- return PSA_ERROR_GENERIC_ERROR;
+ return PSA_ERROR_GENERIC_ERROR;
}
uint32_t active_index = metadata->active_index;
@@ -1691,7 +1691,7 @@ psa_status_t parse_fmp_header(psa_fwu_component_t component, const void *block,
(sizeof(fmp_header_image_info[component].fmp_hdr) - fmp_header_image_info[component].fmp_hdr_size_recvd));
fmp_header_image_info[component].fmp_hdr_size_recvd = sizeof(fmp_header_image_info[component].fmp_hdr);
- return PSA_SUCCESS;
+ return PSA_SUCCESS;
}
}
@@ -1738,7 +1738,7 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component,
}
if (ret == PSA_SUCCESS) {
block_size -= fmp_header_image_info[fwu_image_index].fmp_hdr_size_recvd;
- block += fmp_header_image_info[fwu_image_index].fmp_hdr_size_recvd;
+ block += fmp_header_image_info[fwu_image_index].fmp_hdr_size_recvd;
}
}
@@ -1774,7 +1774,7 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component,
if (fw_version <=
_metadata.fw_desc.img_entry[fwu_image_index].img_props[active_index].version)
{
- /* Version is extracted from the fmp_payload_header */
+ /* Version is extracted from the fmp_payload_header */
priv_metadata.fmp_last_attempt_version[fwu_image_index] = fmp_header_image_info[fwu_image_index].fmp_hdr.fw_version;
priv_metadata.fmp_last_attempt_status[fwu_image_index] = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
private_metadata_write(&priv_metadata);
@@ -1785,8 +1785,8 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component,
priv_metadata.fmp_last_attempt_status[fwu_image_index]);
FWU_LOG_MSG("ERROR: %s: version error\n\r",__func__);
- ret = PSA_OPERATION_INCOMPLETE;
- goto out;
+ ret = PSA_OPERATION_INCOMPLETE;
+ goto out;
}
if (active_index == BANK_0) {
@@ -1828,7 +1828,7 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component,
priv_metadata.fmp_last_attempt_version[fwu_image_index],
priv_metadata.fmp_last_attempt_status[fwu_image_index]);
ret = PSA_OPERATION_INCOMPLETE;
- goto out;
+ goto out;
}
else {
ret = PSA_SUCCESS;
@@ -1871,7 +1871,7 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u
} else {
FWU_LOG_MSG("ERROR: %s: active_index %d\n\r",__func__,active_index);
ret = PSA_ERROR_DATA_INVALID;
- goto out;
+ goto out;
}
_metadata.active_index = previous_active_index;
@@ -1881,7 +1881,7 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u
/* Change system state to trial bank state */
for (int i = 0; i < number; i++) {
/* Skip image with index 0 and ESRT image */
- if(!is_image_index_valid(candidates[i])) {
+ if(!is_image_index_valid(candidates[i])) {
FWU_LOG_MSG("%s: Invalid image index received \n\r", __func__);
continue;
}
@@ -1946,7 +1946,7 @@ static psa_status_t copy_image_from_other_bank(int image_index,
}
offset_read += data_size;
-
+
/* write image data to flash */
data_transferred_count = FWU_METADATA_FLASH_DEV.ProgramData(offset_write, data, data_size);
if (data_transferred_count < 0) {
@@ -1961,7 +1961,7 @@ static psa_status_t copy_image_from_other_bank(int image_index,
}
offset_write += data_size;
- remaining_size -= data_size;
+ remaining_size -= data_size;
}
FWU_LOG_MSG("%s: exit \n\r", __func__);
@@ -2004,8 +2004,8 @@ static psa_status_t maintain_bank_consistency(void)
ret = copy_image_from_other_bank(i, active_index, previous_active_index);
if(ret) {
FWU_LOG_MSG("ERROR: %s: copy_image_from_other_bank failed for Image : %d\n\r",__func__, i);
- return ret;
- }
+ return ret;
+ }
_metadata.fw_desc.img_entry[i].img_props[previous_active_index].version =
_metadata.fw_desc.img_entry[i].img_props[active_index].version;
@@ -2110,7 +2110,7 @@ psa_status_t fwu_bootloader_mark_image_accepted(const psa_fwu_component_t *trial
/* firmware update successful */
for (int i = 0; i < number; i++) {
- if(!is_image_index_valid(trials[i])) {
+ if(!is_image_index_valid(trials[i])) {
FWU_LOG_MSG("%s: Invalid image index received \n\r", __func__);
continue;
}
@@ -2201,7 +2201,7 @@ psa_status_t fwu_bootloader_reject_staged_image(psa_fwu_component_t component)
} else {
FWU_LOG_MSG("ERROR: %s: active_index %d\n\r",__func__,active_index);
ret = PSA_ERROR_GENERIC_ERROR;
- goto out;
+ goto out;
}
image_offset = bank_offset + fwu_image[image_index].image_offset;
@@ -2308,11 +2308,11 @@ psa_status_t fwu_bootloader_get_image_info(psa_fwu_component_t component,
ret = get_esrt_data(&esrt);
if (ret) {
FWU_LOG_MSG("%s: ERROR : Unable to populate ESRT \n\r", __func__);
- goto out;
+ goto out;
}
memcpy(&info->impl.candidate_digest, &esrt, esrt_size);
- if (query_state) {
+ if (query_state) {
info->state = PSA_FWU_READY;
}
}
@@ -1,4 +1,4 @@
From 3dcaa54afe671534b11a0586a49a9036b2bb2011 Mon Sep 17 00:00:00 2001
From c579565c25937ae9455efe9cc3fbcace84c3e580 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Mon, 29 Dec 2025 11:28:47 +0000
Subject: [PATCH] plat: cs1k: Removed unused variables
@@ -6,16 +6,15 @@ Subject: [PATCH] plat: cs1k: Removed unused variables
Change-Id: I0dd3ff834c47c58dc833586c74791deca679a3ab
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport
Signed-off-by: Ahmed Gomaa <Ahmed.Gomaa@arm.com>
---
.../arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
index 9fe9df0..89c2696 100644
index cff80b755..83b0bd27d 100644
--- a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
+++ b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
@@ -1594,7 +1594,6 @@ static psa_status_t fwu_accept_image(struct fwu_metadata *metadata,
@@ -1511,7 +1511,6 @@ static psa_status_t fwu_accept_image(struct fwu_metadata *metadata,
uint8_t number)
{
uint8_t current_state;
@@ -23,7 +22,7 @@ index 9fe9df0..89c2696 100644
uint32_t active_bank_index;
uint32_t fwu_image_index;
psa_status_t ret;
@@ -2070,7 +2069,6 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u
@@ -1848,7 +1847,6 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u
{
int ret;
uint32_t active_index;
@@ -31,8 +30,8 @@ index 9fe9df0..89c2696 100644
uint32_t previous_active_index;
uint8_t fwu_image_index;
@@ -2085,10 +2083,8 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u
active_index = _metadata.active_index;
@@ -1864,10 +1862,8 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u
if (active_index == BANK_0) {
previous_active_index = BANK_1;
- bank_offset = BANK_1_PARTITION_OFFSET;
@@ -0,0 +1,40 @@
From 50db5724ef37d5c7cec019254d135b3dcfd0d340 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Mon, 29 Dec 2025 11:30:32 +0000
Subject: [PATCH] plat: cs1k: Fixed bad function returns
The rest of the functions would go to a label to perform some cleanup
before exiting the function, however these particular errors did not. The
cleanup would reset the write mode on flash, which is required since the
errors occur after it being changed.
Change-Id: Ic8277a3295398922b2f05fcaddfb5a188b14e537
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49425]
---
.../arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
index 52db60bbc..2c17d4b79 100644
--- a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
+++ b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
@@ -1798,7 +1798,8 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component,
bank_offset = BANK_0_PARTITION_OFFSET;
} else {
FWU_LOG_MSG("ERROR: %s: active_index %d\n\r",__func__,active_index);
- return PSA_ERROR_DATA_INVALID;
+ ret = PSA_ERROR_DATA_INVALID;
+ goto out;
}
image_offset = bank_offset + fwu_image[fwu_image_index].image_offset;
@@ -2002,7 +2003,7 @@ static psa_status_t maintain_bank_consistency(void)
ret = copy_image_from_other_bank(i, active_index, previous_active_index);
if(ret) {
FWU_LOG_MSG("ERROR: %s: copy_image_from_other_bank failed for Image : %d\n\r",__func__, i);
- return ret;
+ goto out;
}
_metadata.fw_desc.img_entry[i].img_props[previous_active_index].version =
@@ -0,0 +1,48 @@
From f48a0a6b60309433269c7927dac992eff06f3745 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Mon, 29 Dec 2025 11:29:33 +0000
Subject: [PATCH] plat: cs1k: Improved logging in function
The enter log statement claims to log when the function is entered,
however it was possible for the function to return before reaching it.
The error cases have now been given log statements too in order to make
it easier to track when and why the function exited.
Change-Id: I7fe610ca6a596b6af1e48720a503b76064eed3ff
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49424]
---
.../arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
index 83b0bd27d..52db60bbc 100644
--- a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
+++ b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
@@ -1700,11 +1700,16 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component,
size_t block_size)
{
+ FWU_LOG_MSG("%s: enter: block_offset = %u, block = 0x%p, block_size = %u\n\r"
+ , __func__, block_offset, block, block_size);
+
if (block == NULL) {
+ FWU_LOG_MSG("%s: exit: block is NULL\n\r", __func__);
return PSA_ERROR_INVALID_ARGUMENT;
}
if (!is_initialized) {
+ FWU_LOG_MSG("%s: exit: not initialised\n\r", __func__);
return PSA_ERROR_BAD_STATE;
}
@@ -1726,9 +1731,6 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component,
uint8_t fwu_image_index = component - FWU_FAKE_IMAGES_INDEX_COUNT;
struct fwu_private_metadata priv_metadata;
- FWU_LOG_MSG("%s: enter: block_offset = %u, block = 0x%p, block_size = %u\n\r"
- , __func__, block_offset, block, block_size);
-
/* Parse the incoming block to make sure complete FMP header is received */
if (fmp_header_image_info[fwu_image_index].fmp_hdr_size_recvd != sizeof(fmp_header_image_info[fwu_image_index].fmp_hdr)) {
ret = parse_fmp_header(fwu_image_index, block, block_size);
@@ -0,0 +1,93 @@
From bd6d7dc80556e8c4261343141d675e865d4e960b Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 2 Jan 2026 13:33:25 +0000
Subject: [PATCH] plat: cs1k: Remove unused function
Change-Id: I6e054213dc1ec94a6dc8304705d4cb6e6da701cc
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49426]
---
.../bootloader/mcuboot/tfm_mcuboot_fwu.c | 70 -------------------
1 file changed, 70 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
index 2c17d4b79..76ee8a3dc 100644
--- a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
+++ b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
@@ -501,76 +501,6 @@ static psa_status_t metadata_validate(struct fwu_metadata *metadata)
return PSA_SUCCESS;
}
-#ifdef BL1_BUILD
-static psa_status_t metadata_read_without_validation(struct fwu_metadata *metadata)
-{
- FWU_LOG_MSG("%s: enter: flash addr = %u, size = %d\n\r", __func__,
- FWU_METADATA_REPLICA_1_OFFSET, sizeof(*metadata));
-
- if (!metadata) {
- FWU_LOG_MSG("%s: ERROR - Null pointer received\n\r", __func__);
- return PSA_ERROR_INVALID_ARGUMENT;
- }
-
- int ret = FWU_METADATA_FLASH_DEV.ReadData(FWU_METADATA_REPLICA_1_OFFSET,
- metadata, sizeof(*metadata));
- if (ret < 0) {
- FWU_LOG_MSG("%s: ERROR - Flash read failed (ret = %d)\n\r", __func__, ret);
- return PSA_ERROR_STORAGE_FAILURE;
- }
-
- if (ret != sizeof(*metadata)) {
- FWU_LOG_MSG("%s: ERROR - Incomplete metadata read (expected %zu, got %d)\n\r",
- __func__, sizeof(*metadata), ret);
- return PSA_ERROR_INSUFFICIENT_DATA;
- }
-
- FWU_LOG_MSG("%s: success: active = %u, previous = %d\n\r", __func__,
- metadata->active_index, metadata->previous_active_index);
-
- return PSA_SUCCESS;
-}
-#else
-static psa_status_t metadata_read_without_validation(struct fwu_metadata *metadata)
-{
- uuid_t metadata_uuid = FWU_METADATA_TYPE_UUID;
- partition_entry_t *part;
-
- if (!metadata) {
- FWU_LOG_MSG("%s: ERROR - Null pointer received\n\r", __func__);
- return PSA_ERROR_INVALID_ARGUMENT;
- }
-
- part = get_partition_entry_by_type(&metadata_uuid);
- if (!part) {
- FWU_LOG_MSG("%s: FWU metadata partition not found\n\r", __func__);
- return PSA_ERROR_GENERIC_ERROR;
- }
-
- FWU_LOG_MSG("%s: enter: flash addr = %u, size = %d\n\r", __func__,
- part->start, sizeof(*metadata));
-
-
- int ret = FWU_METADATA_FLASH_DEV.ReadData(part->start,
- metadata, sizeof(*metadata));
- if (ret < 0) {
- FWU_LOG_MSG("%s: ERROR - Flash read failed (ret = %d)\n\r", __func__, ret);
- return PSA_ERROR_STORAGE_FAILURE;
- }
-
- if (ret != sizeof(*metadata)) {
- FWU_LOG_MSG("%s: ERROR - Incomplete metadata read (expected %zu, got %d)\n\r",
- __func__, sizeof(*metadata), ret);
- return PSA_ERROR_INSUFFICIENT_DATA;
- }
-
- FWU_LOG_MSG("%s: success: active = %u, previous = %d\n\r", __func__,
- metadata->active_index, metadata->previous_active_index);
-
- return PSA_SUCCESS;
-}
-#endif
-
#ifdef BL1_BUILD
static psa_status_t metadata_read(struct fwu_metadata *metadata, uint8_t replica_num)
{
@@ -0,0 +1,464 @@
From 939d18a0d8dcedd2b5c4b6220e1a0f6c6855fcf6 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 2 Jan 2026 14:21:57 +0000
Subject: [PATCH] plat: cs1k: Reduce BL1 binary size
The size of the BL1 binary is nearly at its maximum allowable size of
64KiB. By making logging a bit more consistent, string literals can be
re-used and reduce the size of the binary. This allows more space for
BL1_2.
Some functions also had two or more "entry" logging statements, and so
the redundant statements were removed.
The size of BL1_1 has been updated to reflect these changes.
Change-Id: Id52dd0d319fb252d7d05e40b6f8f640d27d45ddb
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49427]
---
.../bootloader/mcuboot/tfm_mcuboot_fwu.c | 101 ++++++++++--------
.../arm/corstone1000/partition/region_defs.h | 2 +-
2 files changed, 56 insertions(+), 47 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
index 76ee8a3dc..dc7503d41 100644
--- a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
+++ b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
@@ -56,6 +56,13 @@
#define FWU_FAKE_IMAGES_INDEX_COUNT 1
#define FWU_FAKE_IMAGE_INDEX 0
+/* These macros provide consistent logging for simple function enter and
+ * successful exit. This helps reduce the number of string literals in the
+ * final binary, thus reducing its size
+ */
+#define FWU_LOG_FUNC_ENTER FWU_LOG_MSG("%s: enter\n\r", __func__)
+#define FWU_LOG_FUNC_EXIT_SUCCESS FWU_LOG_MSG("%s: success\n\r", __func__)
+
/*
* Metadata version 2 data structures defined by PSA_FW update specification
* at https://developer.arm.com/documentation/den0118/latest/
@@ -334,7 +341,7 @@ extern ARM_DRIVER_FLASH FWU_METADATA_FLASH_DEV;
static psa_status_t private_metadata_read(
struct fwu_private_metadata* priv_metadata)
{
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (!priv_metadata) {
FWU_LOG_MSG("%s: ERROR - Null pointer received\n\r", __func__);
@@ -366,7 +373,7 @@ static psa_status_t private_metadata_read(
partition_entry_t *part;
uuid_t private_uuid = PRIVATE_METADATA_TYPE_UUID;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (!priv_metadata) {
FWU_LOG_MSG("%s: ERROR - Null pointer received\n\r", __func__);
@@ -430,7 +437,7 @@ static psa_status_t private_metadata_write(
return PSA_ERROR_INSUFFICIENT_DATA;
}
- FWU_LOG_MSG("%s: success\n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return PSA_SUCCESS;
}
#else
@@ -473,14 +480,14 @@ static psa_status_t private_metadata_write(
return PSA_ERROR_INSUFFICIENT_DATA;
}
- FWU_LOG_MSG("%s: success\n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return PSA_SUCCESS;
}
#endif
static psa_status_t metadata_validate(struct fwu_metadata *metadata)
{
- FWU_LOG_MSG("%s: enter:\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (!metadata) {
FWU_LOG_MSG("%s: ERROR - Null pointer received\n\r", __func__);
@@ -496,7 +503,7 @@ static psa_status_t metadata_validate(struct fwu_metadata *metadata)
return PSA_ERROR_GENERIC_ERROR;
}
- FWU_LOG_MSG("%s: success\n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return PSA_SUCCESS;
}
@@ -506,7 +513,7 @@ static psa_status_t metadata_read(struct fwu_metadata *metadata, uint8_t replica
{
uint32_t replica_offset = 0;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (!metadata) {
FWU_LOG_MSG("%s: ERROR - Null pointer received\n\r", __func__);
@@ -525,7 +532,6 @@ static psa_status_t metadata_read(struct fwu_metadata *metadata, uint8_t replica
FWU_LOG_MSG("%s: flash addr = %u, size = %d\n\r", __func__,
replica_offset, sizeof(*metadata));
-
int ret = FWU_METADATA_FLASH_DEV.ReadData(replica_offset,
metadata, sizeof(*metadata));
if (ret < 0) {
@@ -555,7 +561,7 @@ static psa_status_t metadata_read(struct fwu_metadata *metadata, uint8_t replica
uuid_t metadata_uuid = FWU_METADATA_TYPE_UUID;
partition_entry_t *part;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (!metadata) {
FWU_LOG_MSG("%s: ERROR - Null pointer received\n\r", __func__);
@@ -611,7 +617,7 @@ static psa_status_t metadata_write(
{
uint32_t replica_offset = 0;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (!metadata) {
FWU_LOG_MSG("%s: ERROR - Null pointer received\n\r", __func__);
@@ -627,10 +633,9 @@ static psa_status_t metadata_write(
return PSA_ERROR_GENERIC_ERROR;
}
- FWU_LOG_MSG("%s: enter: flash addr = %u, size = %d\n\r", __func__,
+ FWU_LOG_MSG("%s: flash addr = %u, size = %d\n\r", __func__,
replica_offset, sizeof(*metadata));
-
int ret = FWU_METADATA_FLASH_DEV.EraseSector(replica_offset);
if (ret != ARM_DRIVER_OK) {
FWU_LOG_MSG("%s: ERROR - Flash erase failed (ret = %d)\n\r", __func__, ret);
@@ -661,6 +666,8 @@ static psa_status_t metadata_write(
uuid_t metadata_uuid = FWU_METADATA_TYPE_UUID;
partition_entry_t *part;
+ FWU_LOG_FUNC_ENTER;
+
if (!metadata) {
FWU_LOG_MSG("%s: ERROR - Null pointer received\n\r", __func__);
return PSA_ERROR_INVALID_ARGUMENT;
@@ -888,7 +895,7 @@ psa_status_t fwu_metadata_provision(void)
{
psa_status_t ret;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
ret = fwu_metadata_init();
if (ret) {
@@ -918,7 +925,7 @@ psa_status_t fwu_metadata_provision(void)
return ret;
}
- FWU_LOG_MSG("%s: FWU METADATA PROVISIONED.\n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return PSA_SUCCESS;
}
@@ -927,7 +934,7 @@ static uint8_t get_fwu_image_state(
struct fwu_private_metadata *priv_metadata,
uint32_t fwu_image_index)
{
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if ((metadata->fw_desc.img_entry[fwu_image_index].img_props[metadata->active_index].accepted)
== (IMAGE_NOT_ACCEPTED)) {
@@ -943,7 +950,7 @@ static uint8_t get_fwu_agent_state(
struct fwu_metadata *metadata,
struct fwu_private_metadata *priv_metadata)
{
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (priv_metadata->boot_index != metadata->active_index) {
FWU_LOG_MSG("%s: exit: FWU Agent PSA_FWU_TRIAL (index mismatch)\n\r", __func__);
@@ -966,7 +973,7 @@ static psa_status_t erase_image(uint32_t image_offset, uint32_t image_size)
int ret;
uint32_t sectors;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if ((image_offset % FWU_METADATA_FLASH_SECTOR_SIZE) != 0) {
return PSA_ERROR_INVALID_ARGUMENT;
@@ -989,7 +996,7 @@ static psa_status_t erase_image(uint32_t image_offset, uint32_t image_size)
}
}
- FWU_LOG_MSG("%s: exit\n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return PSA_SUCCESS;
}
@@ -1001,7 +1008,7 @@ static psa_status_t fwu_select_previous(
uint8_t current_state;
uint32_t index;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
/* it is expected to receive this call only when
in trial state */
@@ -1049,8 +1056,8 @@ static psa_status_t fwu_select_previous(
FWU_LOG_MSG("%s: in regular state by choosing previous active bank\n\r",
__func__);
- FWU_LOG_MSG("%s: exit: ret = %d\n\r", __func__, ret);
- return ret;
+ FWU_LOG_FUNC_EXIT_SUCCESS;
+ return PSA_SUCCESS;
}
@@ -1061,7 +1068,7 @@ void bl1_get_active_bl2_image(uint32_t *offset)
uint32_t boot_attempted;
uint32_t boot_index;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (fwu_metadata_init()) {
FWU_ASSERT(0);
@@ -1125,7 +1132,7 @@ uint8_t bl2_get_boot_bank(void)
{
uint8_t boot_index;
struct fwu_private_metadata priv_metadata;
- FWU_LOG_MSG("%s: enter", __func__);
+ FWU_LOG_FUNC_ENTER;
if (fwu_metadata_init()) {
FWU_ASSERT(0);
}
@@ -1150,7 +1157,7 @@ static psa_status_t update_nv_counters(
uint32_t security_cnt;
enum tfm_nv_counter_t tfm_nv_counter_i;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
/* The FWU_BL2_NV_COUNTER (0) is not mirrored in the private metadata. It is
* directly updated in the bl1_2_validate_image_at_addr() function, in
@@ -1194,7 +1201,7 @@ static psa_status_t update_nv_counters(
}
- FWU_LOG_MSG("%s: exit\n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return PSA_SUCCESS;
}
@@ -1204,7 +1211,7 @@ psa_status_t corstone1000_fwu_host_ack(void)
struct fwu_private_metadata priv_metadata;
uint8_t current_state;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (!is_initialized) {
return PSA_ERROR_BAD_STATE;
@@ -1309,7 +1316,7 @@ void host_acknowledgement_timer_to_reset(void)
struct fwu_private_metadata priv_metadata;
uint8_t current_state;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
Select_Write_Mode_For_Shared_Flash();
@@ -1342,7 +1349,7 @@ void host_acknowledgement_timer_to_reset(void)
}
}
- FWU_LOG_MSG("%s: exit\n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return;
}
@@ -1379,7 +1386,7 @@ psa_status_t fwu_stage_nv_counter(enum fwu_nv_counter_index_t index,
}
}
- FWU_LOG_MSG("%s: exit\n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return PSA_SUCCESS;
}
@@ -1397,7 +1404,7 @@ bool is_image_index_valid(uint8_t fwu_image_index) {
static psa_status_t get_esrt_data(struct fwu_esrt_data_wrapper *esrt)
{
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
if (!esrt)
{
@@ -1445,7 +1452,7 @@ static psa_status_t fwu_accept_image(struct fwu_metadata *metadata,
uint32_t fwu_image_index;
psa_status_t ret;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
/* booted from previous_active_bank, not expected
@@ -1492,8 +1499,8 @@ static psa_status_t fwu_accept_image(struct fwu_metadata *metadata,
return ret;
}
- FWU_LOG_MSG("%s: exit: fwu state is changed to regular, ret - %d\n\r", __func__, ret);
- return ret;
+ FWU_LOG_MSG("%s: success: fwu state is changed to regular\n\r", __func__);
+ return PSA_SUCCESS;
}
static psa_status_t uint_to_image_version(uint32_t ver_in, psa_fwu_image_version_t *ver_out)
@@ -1525,6 +1532,8 @@ static psa_status_t erase_staging_area(struct fwu_metadata* metadata, psa_fwu_co
return PSA_ERROR_INVALID_ARGUMENT;
}
+ FWU_LOG_FUNC_ENTER;
+
if (!is_image_index_valid(component)) {
FWU_LOG_MSG("%s: Invalid Component received \n\r", __func__);
return PSA_ERROR_GENERIC_ERROR;
@@ -1535,8 +1544,6 @@ static psa_status_t erase_staging_area(struct fwu_metadata* metadata, psa_fwu_co
uint32_t image_offset;
uint8_t fwu_image_index = component - FWU_FAKE_IMAGES_INDEX_COUNT; /* Decrement to get the correct fwu image index */
- FWU_LOG_MSG("%s: enter\n\r", __func__);
-
if (active_index == BANK_0) {
bank_offset = BANK_1_PARTITION_OFFSET;
} else if (active_index == BANK_1) {
@@ -1551,7 +1558,7 @@ static psa_status_t erase_staging_area(struct fwu_metadata* metadata, psa_fwu_co
return PSA_ERROR_GENERIC_ERROR;
}
- FWU_LOG_MSG("%s: exit: Staging area erased succesfully \n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return PSA_SUCCESS;
}
@@ -1559,7 +1566,7 @@ psa_status_t fwu_bootloader_init(void)
{
psa_status_t ret;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
ret = fwu_metadata_init();
if (ret) {
@@ -1569,7 +1576,7 @@ psa_status_t fwu_bootloader_init(void)
/* Initialize the fmp_header_image_info object */
fmp_header_image_info_init();
- FWU_LOG_MSG("%s: exit: Initialized\n\r", __func__);
+ FWU_LOG_FUNC_EXIT_SUCCESS;
return PSA_SUCCESS;
}
@@ -1588,7 +1595,7 @@ psa_status_t fwu_bootloader_staging_area_init(psa_fwu_component_t component,
psa_status_t ret;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
Select_Write_Mode_For_Shared_Flash();
@@ -1783,7 +1790,7 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u
uint32_t previous_active_index;
uint8_t fwu_image_index;
- FWU_LOG_MSG("%s: enter function\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
Select_Write_Mode_For_Shared_Flash();
@@ -1842,6 +1849,8 @@ static psa_status_t copy_image_from_other_bank(int image_index,
uint32_t active_index,
uint32_t previous_active_index)
{
+ FWU_LOG_FUNC_ENTER;
+
uint32_t bank_offset[NR_OF_FW_BANKS] = {BANK_0_PARTITION_OFFSET, BANK_1_PARTITION_OFFSET};
uint8_t data[FLASH_CHUNK_SIZE];
size_t remaining_size = fwu_image[image_index].image_size;
@@ -1904,7 +1913,7 @@ static psa_status_t maintain_bank_consistency(void)
uint32_t previous_active_index;
struct fwu_private_metadata priv_metadata;
- FWU_LOG_MSG("%s: Enter \n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
Select_Write_Mode_For_Shared_Flash();
if (metadata_read(&_metadata, 1) || private_metadata_read(&priv_metadata)) {
@@ -1979,7 +1988,7 @@ psa_status_t fwu_bootloader_install_image(const psa_fwu_component_t *candidates,
}
psa_status_t ret;
- FWU_LOG_MSG("%s: enter function\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
/* Copy images from other bank which are not received by FWU client */
ret = maintain_bank_consistency();
@@ -2015,7 +2024,7 @@ psa_status_t fwu_bootloader_mark_image_accepted(const psa_fwu_component_t *trial
uint8_t current_state;
uint8_t fwu_image_index;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
Select_Write_Mode_For_Shared_Flash();
@@ -2114,7 +2123,7 @@ psa_status_t fwu_bootloader_reject_staged_image(psa_fwu_component_t component)
uint32_t image_offset;
uint8_t image_index = component - FWU_FAKE_IMAGES_INDEX_COUNT; /* Decrement to get the correct fwu image index */
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
Select_Write_Mode_For_Shared_Flash();
if (metadata_read(&_metadata, 1)) {
@@ -2158,7 +2167,7 @@ psa_status_t fwu_bootloader_reject_trial_image(psa_fwu_component_t component)
int ret;
uint8_t fwu_image_index = component - FWU_FAKE_IMAGES_INDEX_COUNT; /* Decrement to get the correct fwu image index */
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
/* Disable host ackowledgement timer */
disable_host_ack_timer();
@@ -2213,7 +2222,7 @@ psa_status_t fwu_bootloader_get_image_info(psa_fwu_component_t component,
uint8_t current_state;
psa_status_t ret;
- FWU_LOG_MSG("%s: enter\n\r", __func__);
+ FWU_LOG_FUNC_ENTER;
Select_Write_Mode_For_Shared_Flash();
diff --git a/platform/ext/target/arm/corstone1000/partition/region_defs.h b/platform/ext/target/arm/corstone1000/partition/region_defs.h
index 92e01c0e3..1feee7841 100644
--- a/platform/ext/target/arm/corstone1000/partition/region_defs.h
+++ b/platform/ext/target/arm/corstone1000/partition/region_defs.h
@@ -94,7 +94,7 @@
/* SE BL1 regions */
#define BL1_1_CODE_START (0)
-#define BL1_1_CODE_SIZE (0x0000E800) /* 58 KiB */
+#define BL1_1_CODE_SIZE (0x0000E748) /* 58 KiB */
#define BL1_1_CODE_LIMIT (BL1_1_CODE_START + BL1_1_CODE_SIZE - 1)
#define PROVISIONING_DATA_START (BL1_1_CODE_START + BL1_1_CODE_SIZE)
@@ -0,0 +1,35 @@
From b4fd75b96b49756c4815685fc19089793fcc9356 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Wed, 14 Jan 2026 14:00:12 +0000
Subject: [PATCH] plat: cs1k: Update license identifier
Change-Id: I26af0dbf66359e76b7164b3abdbbf3ace3f358c6
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49428]
---
platform/ext/target/arm/corstone1000/platform.c | 2 +-
platform/ext/target/arm/corstone1000/platform.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/platform.c b/platform/ext/target/arm/corstone1000/platform.c
index d0f30b72a..32fdc55aa 100644
--- a/platform/ext/target/arm/corstone1000/platform.c
+++ b/platform/ext/target/arm/corstone1000/platform.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
*
* SPDX-License-Identifier: BSD-3-Clause
*
diff --git a/platform/ext/target/arm/corstone1000/platform.h b/platform/ext/target/arm/corstone1000/platform.h
index a88093ed4..906a8f9ae 100644
--- a/platform/ext/target/arm/corstone1000/platform.h
+++ b/platform/ext/target/arm/corstone1000/platform.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -0,0 +1,55 @@
From 201166be49ca4c0079cf804f208534f201cb4b65 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 13 Mar 2026 16:53:54 +0000
Subject: [PATCH] plat: cs1k: Move variable from stack to data
The firmware update secure partition stack is only 0x600 bytes in size.
The variable moved is a buffer of size 0x200, consituting one third of
the available stack. Moving this to the much larger .data section allows
much more stack space if required.
Change-Id: I59d68e80acefaeea36c7060442e005998217d923
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49430]
---
.../arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
index 5e1c4ecc5..a35125b00 100644
--- a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
+++ b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
@@ -39,6 +39,7 @@
* This is used when bank consistency is maintained during partial capsule update
*/
#define FLASH_CHUNK_SIZE 512
+static uint8_t flash_data_buf[FLASH_CHUNK_SIZE];
/* Possible states of the bank.
* Naming convention here matches the implementation in U-Boot
@@ -1978,7 +1979,6 @@ static psa_status_t copy_image_from_other_bank(int image_index,
FWU_LOG_FUNC_ENTER;
uint32_t bank_offset[NR_OF_FW_BANKS] = {BANK_0_PARTITION_OFFSET, BANK_1_PARTITION_OFFSET};
- uint8_t data[FLASH_CHUNK_SIZE];
size_t remaining_size = fwu_image[image_index].image_size;
size_t data_size;
size_t offset_read = bank_offset[active_index] + fwu_image[image_index].image_offset;
@@ -1997,7 +1997,7 @@ static psa_status_t copy_image_from_other_bank(int image_index,
data_size = (remaining_size > FLASH_CHUNK_SIZE) ? FLASH_CHUNK_SIZE : remaining_size;
/* read image data from flash */
- data_transferred_count = FWU_METADATA_FLASH_DEV.ReadData(offset_read, data, data_size);
+ data_transferred_count = FWU_METADATA_FLASH_DEV.ReadData(offset_read, flash_data_buf, data_size);
if (data_transferred_count < 0) {
FWU_LOG_MSG("%s: ERROR - Flash read failed (ret = %d)\n\r", __func__, data_transferred_count);
return PSA_ERROR_STORAGE_FAILURE;
@@ -2012,7 +2012,7 @@ static psa_status_t copy_image_from_other_bank(int image_index,
offset_read += data_size;
/* write image data to flash */
- data_transferred_count = FWU_METADATA_FLASH_DEV.ProgramData(offset_write, data, data_size);
+ data_transferred_count = FWU_METADATA_FLASH_DEV.ProgramData(offset_write, flash_data_buf, data_size);
if (data_transferred_count < 0) {
FWU_LOG_MSG("%s: ERROR - Flash read failed (ret = %d)\n\r", __func__, data_transferred_count);
return PSA_ERROR_STORAGE_FAILURE;
@@ -0,0 +1,521 @@
From 93101e6de045c0c4d633c502616ccf184c07e70a Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 13 Mar 2026 13:42:16 +0000
Subject: [PATCH] plat: cs1k: Create and remove FWU image partitions
Previous to this commit, the GPT library was used only to read each
firmware update image partition. However, the library now is used to
create new partitions, if they don't exist, at the start of an update
and remove the unused partitions at the end of an update, regardless of
whether the images were accepted or rejected.
The images are not moved and are still placed in fixed offsets, so the
idea of a ping-pong between banks still persists.
Change-Id: Ie2a2f0246a500c01019e3b498ac131466a2b3c84
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49431]
---
.../arm/corstone1000/bootloader/fwu_agent.h | 7 +-
.../bootloader/mcuboot/tfm_mcuboot_fwu.c | 313 +++++++++++++++++-
2 files changed, 302 insertions(+), 18 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/bootloader/fwu_agent.h b/platform/ext/target/arm/corstone1000/bootloader/fwu_agent.h
index 4393f5f7b..729e1594c 100644
--- a/platform/ext/target/arm/corstone1000/bootloader/fwu_agent.h
+++ b/platform/ext/target/arm/corstone1000/bootloader/fwu_agent.h
@@ -8,6 +8,7 @@
#ifndef FWU_AGENT_H
#define FWU_AGENT_H
+#include "flash_layout.h"
#include "psa/error.h"
#include "efi_guid_structs.h"
#include "gpt.h"
@@ -47,7 +48,7 @@ typedef struct {
size_t image_size_recvd;
} __packed fmp_header_image_info_t;
-/* Image information common for both the banks */
+/* Image information for each bank */
typedef struct {
/* Total size of the image */
uint32_t image_size;
@@ -55,8 +56,8 @@ typedef struct {
/* Offset of image within a bank. */
uint32_t image_offset;
- /* Name of the image in ascii */
- char image_name[FWU_IMAGE_NAME_LENGTH];
+ /* Names of the image in ascii, one for each bank */
+ const char image_names[NR_OF_FW_BANKS][FWU_IMAGE_NAME_LENGTH];
/* Image-type GUID */
struct efi_guid_t image_type;
diff --git a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
index a35125b00..71a91ade5 100644
--- a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
+++ b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/tfm_mcuboot_fwu.c
@@ -214,7 +214,7 @@ const fwu_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = {
#if PLATFORM_IS_FVP
// FVP payloads GUIDs
{
- .image_name = "bl2_secondary",
+ .image_names = {"bl2_primary", "bl2_secondary"},
.image_size = SE_BL2_PARTITION_SIZE,
.image_offset = SE_BL2_PARTITION_BANK_OFFSET,
.image_type = {
@@ -227,7 +227,7 @@ const fwu_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = {
},
},
{
- .image_name = "tfm_secondary",
+ .image_names = {"tfm_primary", "tfm_secondary"},
.image_size = TFM_PARTITION_SIZE,
.image_offset = TFM_PARTITION_BANK_OFFSET,
.image_type = {
@@ -240,7 +240,7 @@ const fwu_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = {
},
},
{
- .image_name = "FIP_B",
+ .image_names = {"FIP_A", "FIP_B"},
.image_size = FIP_PARTITION_SIZE,
.image_offset = FIP_PARTITION_BANK_OFFSET,
.image_type = {
@@ -253,7 +253,7 @@ const fwu_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = {
},
},
{
- .image_name = "kernel_secondary",
+ .image_names = {"kernel_primary", "kernel_secondary"},
.image_size = INITRAMFS_PARTITION_SIZE,
.image_offset = INITRAMFS_PARTITION_BANK_OFFSET,
.image_type = {
@@ -268,7 +268,7 @@ const fwu_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = {
#else
// MPS3 payloads GUIDs
{
- .image_name = "bl2_secondary",
+ .image_names = {"bl2_primary", "bl2_secondary"},
.image_size = SE_BL2_PARTITION_SIZE,
.image_offset = SE_BL2_PARTITION_BANK_OFFSET,
.image_type = {
@@ -281,7 +281,7 @@ const fwu_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = {
},
},
{
- .image_name = "tfm_secondary",
+ .image_names = {"tfm_primary", "tfm_secondary"},
.image_size = TFM_PARTITION_SIZE,
.image_offset = TFM_PARTITION_BANK_OFFSET,
.image_type = {
@@ -294,7 +294,7 @@ const fwu_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = {
}
},
{
- .image_name = "FIP_B",
+ .image_names = {"FIP_A", "FIP_B"},
.image_size = FIP_PARTITION_SIZE,
.image_offset = FIP_PARTITION_BANK_OFFSET,
.image_type = {
@@ -307,7 +307,7 @@ const fwu_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = {
}
},
{
- .image_name = "kernel_secondary",
+ .image_names = {"kernel_primary", "kernel_secondary"},
.image_size = INITRAMFS_PARTITION_SIZE,
.image_offset = INITRAMFS_PARTITION_BANK_OFFSET,
.image_type = {
@@ -354,6 +354,15 @@ extern ARM_DRIVER_FLASH FWU_METADATA_FLASH_DEV;
* This is the value decided after monitoring the total time
* taken by the host to boot both on FVP and FPGA.
*/
+#ifndef BL1_BUILD
+static void ascii_to_unicode(const char *ascii, char *unicode)
+{
+ for (int i = 0; i < strlen(ascii) + 1; ++i) {
+ unicode[i << 1] = ascii[i];
+ unicode[(i << 1) + 1] = '\0';
+ }
+}
+#endif
#ifdef BL1_BUILD
static psa_status_t private_metadata_read(
@@ -856,6 +865,11 @@ psa_status_t fwu_metadata_init(void)
if (ret != PSA_SUCCESS) {
return ret;
}
+
+ ret = psa_crypto_init();
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
#endif
/* Code assumes everything fits into a sector */
@@ -1146,6 +1160,45 @@ static psa_status_t fwu_select_previous(
return ret;
}
+#ifndef BL1_BUILD
+ /* Remove the GPT partitions for the rejected images. It is always the newer
+ * (second) partitions that are rejected, as they are created during the
+ * fwu process
+ */
+ for (int i = 0; i < NR_OF_IMAGES_IN_FW_BANK; ++i) {
+ struct partition_entry_t part;
+ ret = gpt_entry_read_by_type(&(fwu_image[i].image_type), 1, &part);
+
+ if (ret == PSA_ERROR_DOES_NOT_EXIST) {
+ FWU_LOG_MSG("%s: Unable to find partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[index]);
+ return ret;
+ } else if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst reading GPT partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to read partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[index]);
+ return ret;
+ }
+
+ ret = gpt_entry_remove(&(part.partition_guid));
+ if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst removing GPT partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to remove partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[index]);
+ return ret;
+ }
+
+ FWU_LOG_MSG("%s: Removed GPT partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[index]);
+ }
+#endif /* BL1_BUILD */
+
FWU_LOG_MSG("%s: in regular state by choosing previous active bank\n\r",
__func__);
@@ -1594,6 +1647,47 @@ static psa_status_t fwu_accept_image(struct fwu_metadata *metadata,
return ret;
}
+#ifndef BL1_BUILD
+ /* Remove the old (first) partitions from the GPT header. It is always the
+ * older images to be removed, as they were not created by the update
+ * process but existed before
+ */
+ uint32_t previous_bank_index = metadata->previous_active_index;
+
+ for (int i = 0; i < NR_OF_IMAGES_IN_FW_BANK; ++i) {
+ struct partition_entry_t part;
+
+ ret = gpt_entry_read_by_type(
+ &(fwu_image[i].image_type),
+ 0,
+ &part);
+ if (ret == PSA_ERROR_DOES_NOT_EXIST) {
+ FWU_LOG_MSG("%s: Unable to find partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[previous_bank_index]);
+ return ret;
+ } else if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst reading GPT partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[previous_bank_index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to read partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[previous_bank_index]);
+ return ret;
+ }
+
+ ret = gpt_entry_remove(&(part.partition_guid));
+ if (ret == PSA_ERROR_DOES_NOT_EXIST) {
+ FWU_LOG_MSG("%s: Flash error whilst removing GPT partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[previous_bank_index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to remove partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[previous_bank_index]);
+ return ret;
+ }
+ }
+#endif
+
FWU_LOG_MSG("%s: success: fwu state is changed to regular\n\r", __func__);
return PSA_SUCCESS;
}
@@ -1635,21 +1729,81 @@ static psa_status_t erase_staging_area(struct fwu_metadata* metadata, psa_fwu_co
}
uint32_t active_index = metadata->active_index;
+ uint32_t previous_active_index;
uint32_t bank_offset;
uint32_t image_offset;
+ uint32_t image_size;
uint8_t fwu_image_index = component - FWU_FAKE_IMAGES_INDEX_COUNT; /* Decrement to get the correct fwu image index */
if (active_index == BANK_0) {
bank_offset = BANK_1_PARTITION_OFFSET;
+ previous_active_index = BANK_1;
} else if (active_index == BANK_1) {
bank_offset = BANK_0_PARTITION_OFFSET;
+ previous_active_index = BANK_0;
} else {
FWU_LOG_MSG("ERROR: %s: active_index %d\n\r",__func__,active_index);
return PSA_ERROR_GENERIC_ERROR;
}
+#ifdef BL1_BUILD
image_offset = bank_offset + fwu_image[fwu_image_index].image_offset;
- if (erase_image(image_offset, fwu_image[fwu_image_index].image_size)) {
+ image_size = fwu_image[fwu_image_index].image_size;
+#else
+ /* Use GPT to find partition instead */
+ struct partition_entry_t part;
+
+ psa_status_t ret = gpt_entry_read_by_type(&(fwu_image[fwu_image_index].image_type), 1, &part);
+ if (ret == PSA_ERROR_DOES_NOT_EXIST) {
+ /* Create the partition in the expected space */
+ struct efi_guid_t new_guid = {0};
+ char unicode_name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ ascii_to_unicode(fwu_image[fwu_image_index].image_names[previous_active_index], unicode_name);
+
+ ret = gpt_entry_create(&(fwu_image[fwu_image_index].image_type),
+ (bank_offset + fwu_image[fwu_image_index].image_offset) / TFM_GPT_BLOCK_SIZE,
+ 1 + ((fwu_image[fwu_image_index].image_size - 1) / TFM_GPT_BLOCK_SIZE),
+ 0,
+ unicode_name,
+ &new_guid);
+ if (ret == PSA_ERROR_INSUFFICIENT_STORAGE) {
+ FWU_LOG_MSG("%s: No space left on device!\r\n", __func__);
+ return ret;
+ } else if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst creating GPT partition '%s'!\r\n",
+ __func__, fwu_image[fwu_image_index].image_names[previous_active_index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to create GPT partition '%s': %d\r\n", __func__,
+ fwu_image[fwu_image_index].image_names[previous_active_index], ret);
+ return ret;
+ }
+
+ ret = gpt_entry_read(&new_guid, &part);
+ if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst reading GPT partition '%s'\r\n",
+ __func__, fwu_image[fwu_image_index].image_names[previous_active_index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to read GPT partition '%s': %d\r\n", __func__,
+ fwu_image[fwu_image_index].image_names[previous_active_index], ret);
+ return ret;
+ }
+ } else if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst reading GPT partition '%s'\r\n",
+ __func__, fwu_image[fwu_image_index].image_names[previous_active_index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to read GPT partition '%s': %d\r\n", __func__,
+ fwu_image[fwu_image_index].image_names[previous_active_index], ret);
+ return ret;
+ }
+
+ image_offset = part.start * TFM_GPT_BLOCK_SIZE;
+ image_size = part.size * TFM_GPT_BLOCK_SIZE;
+#endif /* BL1_BUILD */
+
+ if (erase_image(image_offset, image_size)) {
return PSA_ERROR_GENERIC_ERROR;
}
@@ -1924,7 +2078,6 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u
goto out;
}
active_index = _metadata.active_index;
-
if (active_index == BANK_0) {
previous_active_index = BANK_1;
} else if (active_index == BANK_1) {
@@ -1979,15 +2132,89 @@ static psa_status_t copy_image_from_other_bank(int image_index,
FWU_LOG_FUNC_ENTER;
uint32_t bank_offset[NR_OF_FW_BANKS] = {BANK_0_PARTITION_OFFSET, BANK_1_PARTITION_OFFSET};
+ psa_status_t ret;
+
+#ifdef BL1_BUILD
+ /* Use offsets directly */
size_t remaining_size = fwu_image[image_index].image_size;
size_t data_size;
size_t offset_read = bank_offset[active_index] + fwu_image[image_index].image_offset;
size_t offset_write = bank_offset[previous_active_index] + fwu_image[image_index].image_offset;
int data_transferred_count;
+#else
+ /* Use GPT to find the correct image */
+ struct partition_entry_t active_part;
+ ret = gpt_entry_read_by_type(
+ &(fwu_image[image_index].image_type),
+ 0,
+ &active_part);
+ if (ret == PSA_ERROR_DOES_NOT_EXIST) {
+ FWU_LOG_MSG("%s: Unable to find partition '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[active_index]);
+ return ret;
+ } else if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst reading GPT partition '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[active_index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to read partition '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[active_index]);
+ return ret;
+ }
- FWU_LOG_MSG("%s: Enter \n\r", __func__);
+ struct partition_entry_t prev_active_part;
+ ret = gpt_entry_read_by_type(
+ &(fwu_image[image_index].image_type),
+ 1,
+ &prev_active_part);
- psa_status_t ret = erase_image(offset_write, fwu_image[image_index].image_size);
+ if (ret == PSA_ERROR_DOES_NOT_EXIST) {
+ /* Create the partition in the expected space */
+ struct efi_guid_t new_guid = {0};
+ char unicode_name[GPT_ENTRY_NAME_LENGTH] = {'\0'};
+ ascii_to_unicode(fwu_image[image_index].image_names[previous_active_index], unicode_name);
+
+ ret = gpt_entry_create(&(fwu_image[image_index].image_type),
+ (bank_offset[previous_active_index] + fwu_image[image_index].image_offset) / TFM_GPT_BLOCK_SIZE,
+ 1 + ((fwu_image[image_index].image_size - 1) / TFM_GPT_BLOCK_SIZE),
+ 0,
+ unicode_name,
+ &new_guid);
+ if (ret == PSA_ERROR_INSUFFICIENT_STORAGE) {
+ FWU_LOG_MSG("%s: No space left on device!\r\n", __func__);
+ return ret;
+ } else if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst creating GPT partition '%s'!\r\n",
+ __func__, fwu_image[image_index].image_names[previous_active_index]);
+ return ret;
+ } else if (ret < 0) {
+ return ret;
+ }
+
+ ret = gpt_entry_read(&new_guid, &prev_active_part);
+ if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst reading GPT partition '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[previous_active_index]);
+ return ret;
+ } else if (ret < 0) {
+ return ret;
+ }
+ } else if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst reading GPT partition '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[previous_active_index]);
+ return ret;
+ } else if (ret < 0) {
+ return ret;
+ }
+
+ size_t remaining_size = prev_active_part.size * TFM_GPT_BLOCK_SIZE;
+ size_t data_size;
+ size_t offset_read = active_part.start * TFM_GPT_BLOCK_SIZE;
+ size_t offset_write = prev_active_part.start * TFM_GPT_BLOCK_SIZE;
+ int data_transferred_count;
+#endif /* BL1_BUILD */
+
+ ret = erase_image(offset_write, remaining_size);
if (ret != PSA_SUCCESS) {
FWU_LOG_MSG("%s: ERROR - Flash erase failed for Image: %d\n\r", __func__, image_index);
return ret;
@@ -2244,10 +2471,10 @@ psa_status_t fwu_bootloader_reject_staged_image(psa_fwu_component_t component)
return PSA_ERROR_BAD_STATE;
}
- int ret;
+ psa_status_t ret;
uint32_t active_index;;
- uint32_t bank_offset;
uint32_t image_offset;
+ uint32_t image_size;
uint8_t image_index = component - FWU_FAKE_IMAGES_INDEX_COUNT; /* Decrement to get the correct fwu image index */
FWU_LOG_FUNC_ENTER;
@@ -2259,6 +2486,8 @@ psa_status_t fwu_bootloader_reject_staged_image(psa_fwu_component_t component)
}
active_index = _metadata.active_index;
+#ifdef BL1_BUILD
+ uint32_t bank_offset;
if (active_index == BANK_0) {
bank_offset = BANK_1_PARTITION_OFFSET;
} else if (active_index == BANK_1) {
@@ -2270,8 +2499,62 @@ psa_status_t fwu_bootloader_reject_staged_image(psa_fwu_component_t component)
}
image_offset = bank_offset + fwu_image[image_index].image_offset;
+ image_size = fwu_image[image_index].image_size;
+#else
+ uint32_t previous_active_index;
+ struct partition_entry_t part;
+
+ if (active_index == BANK_0) {
+ previous_active_index = BANK_1;
+ } else if (active_index == BANK_1) {
+ previous_active_index = BANK_0;
+ } else {
+ FWU_LOG_MSG("ERROR: %s: active_index %d\n\r",__func__,active_index);
+ ret = PSA_ERROR_GENERIC_ERROR;
+ goto out;
+ }
+
+ /* The newer entry of the same type is the staged image, as it was created
+ * during the fwu process
+ */
+ ret = gpt_entry_read_by_type(
+ &(fwu_image[image_index].image_type),
+ 1,
+ &part);
+
+ if (ret == PSA_ERROR_DOES_NOT_EXIST) {
+ FWU_LOG_MSG("%s: Partition '%s' not found\n\r",
+ __func__, fwu_image[image_index].image_names[previous_active_index]);
+ goto out;
+ } else if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s : ERROR - flash failure reading partition '%s'\n\r",
+ __func__, fwu_image[image_index].image_names[previous_active_index]);
+ goto out;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("Unable to find partition '%s', ret: %d\n\r",
+ fwu_image[image_index].image_names[previous_active_index], ret);
+ goto out;
+ }
+
+ /* Remove the partition. This only removes the entry from the header and
+ * does not erase the actual data the partition referred to
+ */
+ ret = gpt_entry_remove(&(part.partition_guid));
+ if (ret == PSA_ERROR_STORAGE_FAILURE) {
+ FWU_LOG_MSG("%s: Flash error whilst removing GPT partition '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[previous_active_index]);
+ goto out;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to remove partition '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[previous_active_index]);
+ goto out;
+ }
+
+ image_offset = part.start * TFM_GPT_BLOCK_SIZE;
+ image_size = part.size * TFM_GPT_BLOCK_SIZE;
+#endif /* BL1_BUILD */
- if (erase_image(image_offset, fwu_image[image_index].image_size)) {
+ if (erase_image(image_offset, image_size)) {
return PSA_ERROR_GENERIC_ERROR;
}
@@ -0,0 +1,111 @@
From 37cac6c86f10340382ff950e5e0323f2efbe5ed3 Mon Sep 17 00:00:00 2001
From: Michael Safwat <michael.safwat@arm.com>
Date: Wed, 8 Apr 2026 13:02:47 +0100
Subject: [PATCH 1/2] plat: cs1k: Derive host base addresses from offsets
Define explicit host register offsets and compute base addresses
from the common host address space base. This keeps the map
consistent, and also makes it easy to relocate all addresses if the
base addresses change.
Define External System Reset Control bitfields and use them to
de-assert CPUWAIT when booting the external system, so we can touch
only the bit of interest instead of zeroing the whole register.
Change-Id: Id228351926fc846d28d5bf4e4180a995057154b1
Signed-off-by: Michael Safwat <michael.safwat@arm.com>
Upstream-Status: Backport [d73cc1dbc2eb72af02de740926f7b3c889bbac4b]
---
.../Device/Include/platform_base_address.h | 52 ++++++++++++++-----
.../arm/corstone1000/tfm_hal_multi_core.c | 5 +-
2 files changed, 41 insertions(+), 16 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h b/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h
index 3908d69bc..62ee7d049 100644
--- a/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h
+++ b/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h
@@ -68,23 +68,49 @@
/* Host base addresses from the SE perspective - partial list, only the ones
* required by the SE are defined here */
#define CORSTONE1000_HOST_ADDRESS_SPACE_BASE (0x60000000U) /* Host Address Space */
-#define CORSTONE1000_HOST_BIR_BASE (0x60000000U) /* Boot Instruction Register */
-#define CORSTONE1000_HOST_TRUSTED_RAM_BASE (0x62000000U) /* Secure RAM */
-#define CORSTONE1000_HOST_XNVM_BASE (0x68000000U) /* XNVM */
-#define CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE (0x7A010000U) /* Host SCB */
-#define CORSTONE1000_EXT_SYS_RESET_REG (0x7A010310U) /* external system (cortex-M3) */
-#define CORSTONE1000_HOST_FIREWALL_BASE (0x7A800000U) /* Host Firewall */
-#define CORSTONE1000_HOST_INT_APBCOM_BASE (0x7B900000U) /* Internal APBCOM */
-#define CORSTONE1000_HOST_FPGA_SCC_REGISTERS (0x80000000U) /* FPGA SCC Registers */
-#define CORSTONE1000_HOST_SE_SECURE_FLASH_BASE_FVP (0x80010000U) /* SE Flash */
-#define CORSTONE1000_HOST_AXI_QSPI_CTRL_REG_BASE (0x80050000U) /* AXI QSPI Controller */
-#define CORSTONE1000_HOST_AXI_QSPI_CTRL_REG_BASE_SE_SECURE_FLASH (0x90010000U) /* AXI QSPI Controller for SE FLash */
-#define CORSTONE1000_HOST_DRAM_UEFI_CAPSULE (0xA0000000U) /* 1.5 GB DDR */
+/* Registers offsets - partial list, only the ones
+ * required by the SE are defined here */
+#define CORSTONE1000_HOST_BIR_OFFSET (0x00000000U)
+#define CORSTONE1000_HOST_CVM_OFFSET (0x02000000U)
+#define CORSTONE1000_HOST_XNVM_OFFSET (0x08000000U)
+#define CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE_OFFSET (0x1A010000U)
+#define CORSTONE1000_HOST_EXT_SYS0_RST_CTRL_OFFSET (0x310U)
+#define CORSTONE1000_HOST_FIREWALL_BASE_OFFSET (0x1A800000U)
+#define CORSTONE1000_HOST_INT_APBCOM_BASE_OFFSET (0x1B900000U)
+/* The below offsets have been derived from the reserved section.*/
+#define CORSTONE1000_HOST_FPGA_SCC_REGISTERS_OFFSET (0x20000000U)
+#define CORSTONE1000_HOST_SE_SECURE_FLASH_BASE_FVP_OFFSET (0x20010000U)
+#define CORSTONE1000_HOST_AXI_QSPI_CTRL_REG_BASE_OFFSET (0x20050000U)
+#define CORSTONE1000_HOST_AXI_QSPI_CTRL_REG_BASE_SE_SECURE_FLASH_OFFSET (0x30010000U)
+#define CORSTONE1000_HOST_DRAM_UEFI_CAPSULE_OFFSET (0x40000000U)
+#define CORSTONE1000_HOST_DSU_120T_BASE_OFFSET (0x60910000U)
+
+/* Register Addresses */
+#define CORSTONE1000_HOST_BIR_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_BIR_OFFSET) /* Boot Instruction Register */
+#define CORSTONE1000_HOST_TRUSTED_RAM_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_CVM_OFFSET) /* On-chip Volatile Memory */
+#define CORSTONE1000_HOST_XNVM_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_XNVM_OFFSET) /* eXecute-in-place Non-volatile Memory */
+#define CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE_OFFSET) /* Security Control Bits */
+#define CORSTONE1000_EXT_SYS_RESET_REG (CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE + CORSTONE1000_HOST_EXT_SYS0_RST_CTRL_OFFSET) /* External System (Cortex-M3) */
+#define CORSTONE1000_HOST_FIREWALL_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_FIREWALL_BASE_OFFSET) /* System Firewall */
+#define CORSTONE1000_HOST_INT_APBCOM_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_INT_APBCOM_BASE_OFFSET) /* Internal Advanced Peripheral Bus Communication */
+#define CORSTONE1000_HOST_FPGA_SCC_REGISTERS (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_FPGA_SCC_REGISTERS_OFFSET) /* FPGA Serial Communication Controller Registers */
+#define CORSTONE1000_HOST_SE_SECURE_FLASH_BASE_FVP (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_SE_SECURE_FLASH_BASE_FVP_OFFSET) /* Secure Enclave Flash */
+#define CORSTONE1000_HOST_AXI_QSPI_CTRL_REG_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_AXI_QSPI_CTRL_REG_BASE_OFFSET) /* AXI QSPI Controller */
+#define CORSTONE1000_HOST_AXI_QSPI_CTRL_REG_BASE_SE_SECURE_FLASH (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_AXI_QSPI_CTRL_REG_BASE_SE_SECURE_FLASH_OFFSET) /* AXI QSPI Controller for SE FLash */
+#define CORSTONE1000_HOST_DRAM_UEFI_CAPSULE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_DRAM_UEFI_CAPSULE_OFFSET) /* DDR RAM (1.5 GB) */
#ifdef CORSTONE1000_DSU_120T
-#define CORSTONE1000_HOST_DSU_120T_BASE (0xC0910000U) /* DSU-120T PPU */
+#define CORSTONE1000_HOST_DSU_120T_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_DSU_120T_BASE_OFFSET) /* DynamIQ Shared Unit-120 Power Policy Units */
#endif
+/* Bit definition for External System Reset Control register */
+#define CORSTONE1000_EXT_SYS_RESET_REG_CPUWAIT_Pos (0U) // CPU Wait Control. 0b0 - External System's CPUWAIT signal is de-asserted. 0b1 - External System's CPUWAIT signal is asserted.
+#define CORSTONE1000_EXT_SYS_RESET_REG_CPUWAIT_Msk (0x1UL << CORSTONE1000_EXT_SYS_RESET_REG_CPUWAIT_Pos) // 1 bit
+#define CORSTONE1000_EXT_SYS_RESET_REG_RST_REQ_Pos (1U) // Reset Request for External System. 0b0 - No Reset Requested. 0b1 - Reset Requested.
+#define CORSTONE1000_EXT_SYS_RESET_REG_RST_REQ_Msk (0x1UL << CORSTONE1000_EXT_SYS_RESET_REG_RST_REQ_Pos) // 1 bit
+#define CORSTONE1000_EXT_SYS_RESET_REG_Reserved_Pos (2U) // Reserved.
+#define CORSTONE1000_EXT_SYS_RESET_REG_Reserved_Msk (0x3FFFFFFFUL << CORSTONE1000_EXT_SYS_RESET_REG_Reserved_Pos) // 30 bits
+
/* Map Component definitions to Corstone definitions */
#define CC3XX_BASE_S CORSTONE1000_CRYPTO_ACCELERATOR_BASE
diff --git a/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c b/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
index 9a785bfa0..76360b507 100644
--- a/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
+++ b/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
@@ -26,12 +26,11 @@
#define AA64nAA32_MASK (1 << 3)
#ifdef EXTERNAL_SYSTEM_SUPPORT
-void tfm_external_system_boot()
+void tfm_external_system_boot(void)
{
volatile uint32_t *ext_sys_reset_ctl_reg = (uint32_t *)(CORSTONE1000_EXT_SYS_RESET_REG);
- /* de-assert CPU_WAIT signal*/
- *ext_sys_reset_ctl_reg = 0x0;
+ *ext_sys_reset_ctl_reg &= ~(CORSTONE1000_EXT_SYS_RESET_REG_CPUWAIT_Msk);
}
#endif
--
2.43.0
@@ -0,0 +1,75 @@
From 334e5513db08f6ebdd7e59429849d442b7b43446 Mon Sep 17 00:00:00 2001
From: Michael Safwat <michael.safwat@arm.com>
Date: Thu, 19 Mar 2026 11:12:19 +0000
Subject: [PATCH 2/2] plat: cs1k: Drive NPU via external system reset control
On Corstone-1000 with Cortex-A320, the NPU reset was previously tied
to the host boot flow, so the NPU was powered on when the Secure
Enclave powered on the host. Now the NPU is tied to the External
System Reset Control register to control the power state.
Reuse the existing external-system boot control mechanism for NPU.
Change-Id: I74f9d57e8cbe5cb38db352d706885f9a37db0183
Signed-off-by: Michael Safwat <michael.safwat@arm.com>
Upstream-Status: Backport [6010d3b509e51cf10a711596e7d6058bde1568dc]
---
platform/ext/target/arm/corstone1000/CMakeLists.txt | 5 +++++
.../arm/corstone1000/Device/Include/platform_base_address.h | 2 +-
platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c | 4 ++--
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/CMakeLists.txt b/platform/ext/target/arm/corstone1000/CMakeLists.txt
index e543c4b6b..739a6a086 100644
--- a/platform/ext/target/arm/corstone1000/CMakeLists.txt
+++ b/platform/ext/target/arm/corstone1000/CMakeLists.txt
@@ -484,6 +484,11 @@ if (CORSTONE1000_CORTEX_A320)
PUBLIC
CORSTONE1000_CORTEX_A320
)
+
+ target_compile_definitions(platform_s
+ PUBLIC
+ CORSTONE1000_CORTEX_A320
+ )
endif()
#========================= tfm_adac ============================================#
diff --git a/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h b/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h
index 62ee7d049..631592b34 100644
--- a/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h
+++ b/platform/ext/target/arm/corstone1000/Device/Include/platform_base_address.h
@@ -91,7 +91,7 @@
#define CORSTONE1000_HOST_TRUSTED_RAM_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_CVM_OFFSET) /* On-chip Volatile Memory */
#define CORSTONE1000_HOST_XNVM_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_XNVM_OFFSET) /* eXecute-in-place Non-volatile Memory */
#define CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE_OFFSET) /* Security Control Bits */
-#define CORSTONE1000_EXT_SYS_RESET_REG (CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE + CORSTONE1000_HOST_EXT_SYS0_RST_CTRL_OFFSET) /* External System (Cortex-M3) */
+#define CORSTONE1000_EXT_SYS_RESET_REG (CORSTONE1000_HOST_BASE_SYSTEM_CONTROL_BASE + CORSTONE1000_HOST_EXT_SYS0_RST_CTRL_OFFSET) /* External System (Cortex-M3/NPU) */
#define CORSTONE1000_HOST_FIREWALL_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_FIREWALL_BASE_OFFSET) /* System Firewall */
#define CORSTONE1000_HOST_INT_APBCOM_BASE (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_INT_APBCOM_BASE_OFFSET) /* Internal Advanced Peripheral Bus Communication */
#define CORSTONE1000_HOST_FPGA_SCC_REGISTERS (CORSTONE1000_HOST_ADDRESS_SPACE_BASE + CORSTONE1000_HOST_FPGA_SCC_REGISTERS_OFFSET) /* FPGA Serial Communication Controller Registers */
diff --git a/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c b/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
index 76360b507..ff65228bf 100644
--- a/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
+++ b/platform/ext/target/arm/corstone1000/tfm_hal_multi_core.c
@@ -25,7 +25,7 @@
#define AA64nAA32_MASK (1 << 3)
-#ifdef EXTERNAL_SYSTEM_SUPPORT
+#if defined(EXTERNAL_SYSTEM_SUPPORT) || defined(CORSTONE1000_CORTEX_A320)
void tfm_external_system_boot(void)
{
volatile uint32_t *ext_sys_reset_ctl_reg = (uint32_t *)(CORSTONE1000_EXT_SYS_RESET_REG);
@@ -123,7 +123,7 @@ void tfm_hal_boot_ns_cpu(uintptr_t start_addr)
#endif
#endif
-#ifdef EXTERNAL_SYSTEM_SUPPORT
+#if defined(EXTERNAL_SYSTEM_SUPPORT) || defined(CORSTONE1000_CORTEX_A320)
/*release EXT SYS out of reset*/
tfm_external_system_boot();
#endif
--
2.43.0
@@ -0,0 +1,114 @@
From 4f11567a0152f1ecd98159ca555d8663ee8e5ce0 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 10 Apr 2026 17:20:39 +0100
Subject: [PATCH] lib: gpt: Fix final entry not being removed
The final entry would not be removed due to the removals being hidden
behind a check on whether the removed entry was not the final entry,
causing it to be a no-op. Removal operation is no longer hidden behind
that condition.
Change-Id: Ib264d988d57cb39098f2783c4a001fcf3b004270
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [f3cf6bda1534b8893620c7b7c0d9ff647b44603e]
---
lib/gpt/src/gpt.c | 64 +++++++++++++++++++++++------------------------
1 file changed, 32 insertions(+), 32 deletions(-)
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index a9dbb918e..e4e7fde32 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -648,6 +648,7 @@ psa_status_t gpt_entry_remove(const struct efi_guid_t *guid)
* to be modified if the last entry in the array was moved or if it is
* the only LBA used by the partition array
*/
+ const uint64_t array_end_lba = partition_array_last_lba(&primary_gpt);;
if (cached_index != primary_gpt.num_used_partitions - 1 ||
cached_index < gpt_entry_per_lba_count())
{
@@ -669,7 +670,6 @@ psa_status_t gpt_entry_remove(const struct efi_guid_t *guid)
* Use a second buffer to read each consecutive LBA and copy that to
* the global LBA buffer to then write afterwards.
*/
- const uint64_t array_end_lba = partition_array_last_lba(&primary_gpt);
for (uint64_t i = partition_entry_lba(&primary_gpt, cached_index) + 1;
i <= array_end_lba;
++i)
@@ -705,45 +705,45 @@ psa_status_t gpt_entry_remove(const struct efi_guid_t *guid)
sizeof(array_buf) - primary_gpt.header.entry_size);
memcpy(lba_buf, array_buf, TFM_GPT_BLOCK_SIZE);
}
+ }
- /* What was the final LBA is now cached and may be empty or partially-filled */
- cached_lba = array_end_lba;
- write_buffered = false;
- uint32_t entries_in_last_lba = (--primary_gpt.num_used_partitions) % gpt_entry_per_lba_count();
- if (entries_in_last_lba == 0) {
- /* There's nothing left in this LBA, so zero it all and write it out.
- * There is also no need to do an erase just to zero afterwards.
- */
- memset(lba_buf, 0, TFM_GPT_BLOCK_SIZE);
- if (backup_gpt_array_lba != 0) {
- int write_ret = plat_flash_driver->write(
- backup_gpt_array_lba + array_end_lba - PRIMARY_GPT_ARRAY_LBA,
- lba_buf);
- if (write_ret != TFM_GPT_BLOCK_SIZE) {
- return PSA_ERROR_STORAGE_FAILURE;
- }
- }
- int write_ret = plat_flash_driver->write(array_end_lba, lba_buf);
+ /* What was the final LBA is now cached and may be empty or partially-filled */
+ cached_lba = array_end_lba;
+ write_buffered = false;
+ uint32_t entries_in_last_lba = (--primary_gpt.num_used_partitions) % gpt_entry_per_lba_count();
+ if (entries_in_last_lba == 0) {
+ /* There's nothing left in this LBA, so zero it all and write it out.
+ * There is also no need to do an erase just to zero afterwards.
+ */
+ memset(lba_buf, 0, TFM_GPT_BLOCK_SIZE);
+ if (backup_gpt_array_lba != 0) {
+ int write_ret = plat_flash_driver->write(
+ backup_gpt_array_lba + array_end_lba - PRIMARY_GPT_ARRAY_LBA,
+ lba_buf);
if (write_ret != TFM_GPT_BLOCK_SIZE) {
return PSA_ERROR_STORAGE_FAILURE;
}
- } else {
- /* Zero what is not needed anymore */
- memset(
- lba_buf + primary_gpt.header.entry_size * entries_in_last_lba,
- 0,
- (gpt_entry_per_lba_count() - entries_in_last_lba) * primary_gpt.header.entry_size);
- if (backup_gpt_array_lba != 0) {
- ret = write_to_flash(backup_gpt_array_lba + array_end_lba - PRIMARY_GPT_ARRAY_LBA);
- if (ret != PSA_SUCCESS) {
- return ret;
- }
- }
- ret = write_to_flash(array_end_lba);
+ }
+ int write_ret = plat_flash_driver->write(array_end_lba, lba_buf);
+ if (write_ret != TFM_GPT_BLOCK_SIZE) {
+ return PSA_ERROR_STORAGE_FAILURE;
+ }
+ } else {
+ /* Zero what is not needed anymore */
+ memset(
+ lba_buf + primary_gpt.header.entry_size * entries_in_last_lba,
+ 0,
+ (gpt_entry_per_lba_count() - entries_in_last_lba) * primary_gpt.header.entry_size);
+ if (backup_gpt_array_lba != 0) {
+ ret = write_to_flash(backup_gpt_array_lba + array_end_lba - PRIMARY_GPT_ARRAY_LBA);
if (ret != PSA_SUCCESS) {
return ret;
}
}
+ ret = write_to_flash(array_end_lba);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
}
/* Update the header after flash changes */
@@ -0,0 +1,37 @@
From 68874e58811c5d4004492f15b3ac46d2cca186c0 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Thu, 16 Apr 2026 09:54:55 +0100
Subject: [PATCH] lib: gpt: Replace warnings with errors
These warnings return errors, so it makes more sense to output an error
message.
Change-Id: I589e24ba8aba2502a3fc86d2aeb648d125c022bd
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [68874e58811c5d4004492f15b3ac46d2cca186c0]
---
lib/gpt/src/gpt.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index 16bda8aba..32c7277bd 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -830,7 +830,7 @@ psa_status_t gpt_defragment(void)
*/
psa_status_t ret = sort_partition_array(&primary_gpt);
if (ret != PSA_SUCCESS) {
- WARN("Unable to defragment flash!\n");
+ ERROR("Unable to defragment flash!\n");
return ret;
}
@@ -926,7 +926,7 @@ psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_part
if (mbr.partitions[0].os_type == MBR_TYPE_GPT) {
ret = read_table_from_flash(&primary_gpt, true);
} else {
- WARN("Unsupported legacy MBR in use\n");
+ ERROR("Unsupported legacy MBR in use\n");
ret = PSA_ERROR_NOT_SUPPORTED;
}
@@ -0,0 +1,268 @@
From ff08a9d998c545a6152789f8ce55bd4200a937cf Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Wed, 15 Apr 2026 10:59:28 +0100
Subject: [PATCH] lib: gpt: Enforce entry size of 128 bytes
Previous to this, the entry size could have been set to any number, even
those deemed illegal by the UEFI spec 2.10 [1], as the library did not
validate it. 128 bytes is the minimum size for a partition entry and
most standard tools that create GPTs will use this.
[1] https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html
Change-Id: Ib6c436353a4b8e00e6c6e63b933a49f11c0a7340
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [ff08a9d998c545a6152789f8ce55bd4200a937cf]
---
lib/gpt/inc/gpt.h | 2 +
lib/gpt/src/gpt.c | 65 +++++++++++++++++++++-----------
lib/gpt/unittests/gpt/test_gpt.c | 40 ++++++++++++++++++++
3 files changed, 85 insertions(+), 22 deletions(-)
diff --git a/lib/gpt/inc/gpt.h b/lib/gpt/inc/gpt.h
index baf4767f9..34ce67580 100644
--- a/lib/gpt/inc/gpt.h
+++ b/lib/gpt/inc/gpt.h
@@ -214,6 +214,7 @@ psa_status_t gpt_entry_remove(const struct efi_guid_t *guid);
*
* \retval PSA_SUCCESS GPT is valid.
* \retval PSA_ERROR_STORAGE_FAILURE I/O error.
+ * \retval PSA_ERROR_NOT_SUPPORTED Entry size is not 128 bytes
* \retval PSA_ERROR_INVALID_SIGNATURE GPT is invalid.
*/
psa_status_t gpt_validate(bool is_primary);
@@ -249,6 +250,7 @@ psa_status_t gpt_defragment(void);
* functions defined by \p flash_driver is NULL. The init
* and uninit functions may be NULL if not required.
* \retval PSA_ERROR_NOT_SUPPORTED Legacy MBR is used and not GPT.
+ * \retval PSA_ERROR_NOT_SUPPORTED Entry size is not 128 bytes
*/
__attribute__((nonnull(1)))
psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver,
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index 32c7277bd..200e21599 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -459,7 +459,7 @@ psa_status_t gpt_entry_move(const struct efi_guid_t *guid,
/* Cached LBA */
for (uint32_t i = 0; i < num_entries_in_cached_lba; ++i) {
- memcpy(&entry, lba_buf + (i * primary_gpt.header.entry_size), GPT_ENTRY_SIZE);
+ memcpy(&entry, lba_buf + (i * GPT_ENTRY_SIZE), GPT_ENTRY_SIZE);
const struct efi_guid_t ent_guid = entry.unique_guid;
if (efi_guid_cmp(&ent_guid, guid) == 0) {
@@ -658,9 +658,9 @@ psa_status_t gpt_entry_remove(const struct efi_guid_t *guid)
const uint32_t lba_index = cached_index % gpt_entry_per_lba_count();
if (lba_index + 1 != gpt_entry_per_lba_count()) {
memmove(
- lba_buf + lba_index * primary_gpt.header.entry_size,
- lba_buf + (lba_index + 1) * primary_gpt.header.entry_size,
- (gpt_entry_per_lba_count() - lba_index - 1) * primary_gpt.header.entry_size);
+ lba_buf + lba_index * GPT_ENTRY_SIZE,
+ lba_buf + (lba_index + 1) * GPT_ENTRY_SIZE,
+ (gpt_entry_per_lba_count() - lba_index - 1) * GPT_ENTRY_SIZE);
}
/* If this is not the last LBA, then read the next LBA into memory and
@@ -683,7 +683,7 @@ psa_status_t gpt_entry_remove(const struct efi_guid_t *guid)
}
memcpy(
- lba_buf + primary_gpt.header.entry_size * (gpt_entry_per_lba_count() - 1),
+ lba_buf + GPT_ENTRY_SIZE * (gpt_entry_per_lba_count() - 1),
array_buf,
GPT_ENTRY_SIZE);
@@ -701,8 +701,8 @@ psa_status_t gpt_entry_remove(const struct efi_guid_t *guid)
memmove(
array_buf,
- array_buf + primary_gpt.header.entry_size,
- sizeof(array_buf) - primary_gpt.header.entry_size);
+ array_buf + GPT_ENTRY_SIZE,
+ sizeof(array_buf) - GPT_ENTRY_SIZE);
memcpy(lba_buf, array_buf, TFM_GPT_BLOCK_SIZE);
}
}
@@ -731,9 +731,9 @@ psa_status_t gpt_entry_remove(const struct efi_guid_t *guid)
} else {
/* Zero what is not needed anymore */
memset(
- lba_buf + primary_gpt.header.entry_size * entries_in_last_lba,
+ lba_buf + GPT_ENTRY_SIZE * entries_in_last_lba,
0,
- (gpt_entry_per_lba_count() - entries_in_last_lba) * primary_gpt.header.entry_size);
+ (gpt_entry_per_lba_count() - entries_in_last_lba) * GPT_ENTRY_SIZE);
if (backup_gpt_array_lba != 0) {
ret = write_to_flash(backup_gpt_array_lba + array_end_lba - PRIMARY_GPT_ARRAY_LBA);
if (ret != PSA_SUCCESS) {
@@ -934,6 +934,14 @@ psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_part
goto fail_load;
}
+ /* Ensure entry size is supported. */
+ if (primary_gpt.header.entry_size != GPT_ENTRY_SIZE) {
+ ERROR("Unsupported entry size 0x%08x, must be 0x%08x\n",
+ primary_gpt.header.entry_size, GPT_ENTRY_SIZE);
+ ret = PSA_ERROR_NOT_SUPPORTED;
+ goto fail_load;
+ }
+
/* Count the number of used entries, assuming the array is not sparese */
ret = count_used_partitions(&primary_gpt, &primary_gpt.num_used_partitions);
if (ret != PSA_SUCCESS) {
@@ -948,6 +956,12 @@ psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_part
if (ret != PSA_SUCCESS) {
goto fail_load;
}
+ if (backup_gpt.header.entry_size != GPT_ENTRY_SIZE) {
+ ERROR("Unsupported entry size 0x%08x, must be 0x%08x\n",
+ backup_gpt.header.entry_size, GPT_ENTRY_SIZE);
+ ret = PSA_ERROR_NOT_SUPPORTED;
+ goto fail_load;
+ }
backup_gpt_array_lba = backup_gpt.header.array_lba;
} else {
WARN("Backup GPT location is unknown!\n");
@@ -999,11 +1013,7 @@ psa_status_t gpt_uninit(void)
/* Returns the number of partition entries in each LBA */
static inline uint64_t gpt_entry_per_lba_count(void)
{
- static uint64_t num_entries = 0;
- if (num_entries == 0) {
- num_entries = TFM_GPT_BLOCK_SIZE / primary_gpt.header.entry_size;
- }
- return num_entries;
+ return TFM_GPT_BLOCK_SIZE / GPT_ENTRY_SIZE;
}
/* Copies information from the entry to the user visible structure */
@@ -1129,15 +1139,15 @@ static psa_status_t update_header(uint32_t num_partitions)
/* Take the CRC of the partition array */
uint32_t crc = 0;
for (uint32_t i = 0; i < header->num_partitions; ++i) {
- uint8_t entry_buf[header->entry_size];
- memset(entry_buf, 0, header->entry_size);
+ uint8_t entry_buf[GPT_ENTRY_SIZE];
+ memset(entry_buf, 0, GPT_ENTRY_SIZE);
struct gpt_entry_t *entry = (struct gpt_entry_t *)entry_buf;
psa_status_t ret = read_entry_from_flash(&primary_gpt, i, entry);
if (ret != PSA_SUCCESS) {
return ret;
}
- crc = efi_soft_crc32_update(crc, entry_buf, header->entry_size);
+ crc = efi_soft_crc32_update(crc, entry_buf, GPT_ENTRY_SIZE);
}
header->array_crc = crc;
@@ -1268,7 +1278,7 @@ static psa_status_t read_entry_from_flash(const struct gpt_t *table,
memcpy(
entry,
- lba_buf + ((array_index % gpt_entry_per_lba_count()) * table->header.entry_size),
+ lba_buf + ((array_index % gpt_entry_per_lba_count()) * GPT_ENTRY_SIZE),
GPT_ENTRY_SIZE);
return PSA_SUCCESS;
@@ -1415,7 +1425,7 @@ static psa_status_t write_entry(uint32_t array_index,
/* Copy into buffer */
uint32_t index_in_lba = array_index % gpt_entry_per_lba_count();
- memcpy(lba_buf + index_in_lba * primary_gpt.header.entry_size, entry, GPT_ENTRY_SIZE);
+ memcpy(lba_buf + index_in_lba * GPT_ENTRY_SIZE, entry, GPT_ENTRY_SIZE);
/* Write on every nth operation. */
if (++num_writes == gpt_entry_per_lba_count()) {
@@ -1519,18 +1529,29 @@ static psa_status_t validate_table(struct gpt_t *table, bool is_primary)
return PSA_ERROR_INVALID_SIGNATURE;
}
+ /* Check the entry size. This is not a part of the spec but ensures the
+ * library only supports entry sizes equal to 128. Otherwise, the backup
+ * could be used to restore the primary with an entry size that is different
+ * and break that assumption, or vise-versa
+ */
+ if (header->entry_size != GPT_ENTRY_SIZE) {
+ ERROR("Unsupported entry size 0x%08x, must be 0x%08x\n",
+ header->entry_size, GPT_ENTRY_SIZE);
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
/* Check the CRC of the partition array */
calc_crc = 0;
for (uint32_t i = 0; i < header->num_partitions; ++i) {
- uint8_t entry_buf[header->entry_size];
- memset(entry_buf, 0, header->entry_size);
+ uint8_t entry_buf[GPT_ENTRY_SIZE];
+ memset(entry_buf, 0, GPT_ENTRY_SIZE);
struct gpt_entry_t *entry = (struct gpt_entry_t *)entry_buf;
psa_status_t ret = read_entry_from_flash(table, i, entry);
if (ret != PSA_SUCCESS) {
return ret;
}
- calc_crc = efi_soft_crc32_update(calc_crc, (uint8_t *)entry, header->entry_size);
+ calc_crc = efi_soft_crc32_update(calc_crc, (uint8_t *)entry, GPT_ENTRY_SIZE);
}
if (calc_crc != header->array_crc) {
diff --git a/lib/gpt/unittests/gpt/test_gpt.c b/lib/gpt/unittests/gpt/test_gpt.c
index 2f05a6b4a..db897b967 100644
--- a/lib/gpt/unittests/gpt/test_gpt.c
+++ b/lib/gpt/unittests/gpt/test_gpt.c
@@ -351,6 +351,30 @@ void test_gpt_init_should_failWhenMbrTypeInvalid(void)
TEST_ASSERT_EQUAL(PSA_ERROR_NOT_SUPPORTED, setup_test_gpt());
}
+void test_gpt_init_should_failWhenEntrySizeBad(void)
+{
+ test_header.entry_size--;
+ /* Expect first a valid MBR read */
+ register_mocked_read(&test_mbr, sizeof(test_mbr));
+
+ /* Expect a GPT header read second */
+ register_mocked_read(&test_header, sizeof(test_header));
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_NOT_SUPPORTED, gpt_init(&mock_driver, TEST_MAX_PARTITIONS));
+ test_header.entry_size = default_header.entry_size;
+
+ /* Now do the backup. */
+ register_mocked_read(&test_mbr, sizeof(test_mbr));
+ register_mocked_read(&test_header, sizeof(test_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ /* Expect fourth the backup to be read. Make the entry size bad */
+ test_header.entry_size = 0;
+ setup_backup_gpt();
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_NOT_SUPPORTED, gpt_init(&mock_driver, TEST_MAX_PARTITIONS));
+}
+
void test_gpt_init_should_failWhenFlashDriverNotFullyDefined(void)
{
gpt_flash_read_t read_fn = mock_driver.read;
@@ -433,6 +457,22 @@ void test_gpt_validate_should_failWhenLbaPointerBad(void)
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
}
+void test_gpt_validate_should_failWhenBackupEntrySizeInvalid(void)
+{
+ /* The entry size for the primary GPT is validated on gpt_init and kept
+ * in memory. Therefore, the entry size can only be validated on gpt_validate
+ * for the backup table, which is read
+ */
+ setup_test_gpt();
+ struct gpt_header_t backup_header;
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+ backup_header.entry_size--;
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+
+ TEST_ASSERT_EQUAL(PSA_ERROR_NOT_SUPPORTED, gpt_validate(false));
+}
+
void test_gpt_validate_should_failWhenArrayCrcBad(void)
{
test_header.array_crc--;
@@ -0,0 +1,38 @@
From c07da31be4551ee9b3ce546a1f6adccb19bc3b59 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Wed, 15 Apr 2026 11:17:25 +0100
Subject: [PATCH] lib: gpt: Ensure block size complies with spec
The UEFI spec 2.10 [1] implicitly requires a block size of at least 512
in order to fit a legacy Master Boot Record.
[1] https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html#legacy-master-boot-record-mbr
Change-Id: I8218ef3d883b51d8fa14835e0ed884139fdebc7d
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [c07da31be4551ee9b3ce546a1f6adccb19bc3b59]
---
lib/gpt/src/gpt.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index 200e21599..cda9fe358 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -20,11 +20,15 @@
#include "efi_soft_crc.h"
/* This needs to be defined by the platform and is used by the GPT library as
- * the number of bytes in a Logical Block Address (LBA)
+ * the number of bytes in a Logical Block Address (LBA). It also must be at least
+ * 512.
*/
#ifndef TFM_GPT_BLOCK_SIZE
#error "TFM_GPT_BLOCK_SIZE must be defined if using GPT library!"
#endif
+#if TFM_GPT_BLOCK_SIZE < 512
+#error "TFM_GPT_BLOCK_SIZE must be at least 512!"
+#endif
/* Where Master Boot Record (MBR) is on flash */
#define MBR_LBA 0ULL
@@ -0,0 +1,352 @@
From bcce0ce881817b36ad52df550bcbf41b4f0d4938 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Wed, 15 Apr 2026 15:09:03 +0100
Subject: [PATCH] lib: gpt: Expand table validation
It is implied by the UEFI spec 2.10 [1] that the backup GPT must be
located at the end of storage. To this effect, ensure that it is the
largest known LBA value.
Additionally, it is also implied that the partition entry arrays, both
primary and backup, must be before or after usable space respectively.
[1] https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html
Change-Id: I5042836822f990a21fbf48b19422879384a844aa
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Backport [bcce0ce881817b36ad52df550bcbf41b4f0d4938]
---
lib/gpt/src/gpt.c | 115 ++++++++++++++++++++
lib/gpt/unittests/gpt/test_gpt.c | 179 +++++++++++++++++++++++++++++++
2 files changed, 294 insertions(+)
diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c
index cda9fe358..0335befa7 100644
--- a/lib/gpt/src/gpt.c
+++ b/lib/gpt/src/gpt.c
@@ -229,6 +229,12 @@ static psa_status_t mbr_load(struct mbr_t *mbr);
static bool gpt_entry_cmp_guid(const struct gpt_entry_t *entry, const void *guid);
static bool gpt_entry_cmp_name(const struct gpt_entry_t *entry, const void *name);
static bool gpt_entry_cmp_type(const struct gpt_entry_t *entry, const void *type);
+static psa_status_t validate_backup_gpt_lba(const uint64_t backup_lba,
+ const uint64_t primary_lba,
+ const uint64_t partition_array_end,
+ const struct gpt_header_t *header);
+static psa_status_t validate_array_lba(const uint64_t partition_array_end,
+ const uint64_t usable_lba_start);
static psa_status_t validate_table(struct gpt_t *table, bool is_primary);
static psa_status_t restore_table(struct gpt_t *restore_from, bool is_primary);
static psa_status_t sort_partition_array(const struct gpt_t *table);
@@ -1498,6 +1504,73 @@ static inline void swap_headers(const struct gpt_header_t *src, struct gpt_heade
primary_gpt.header.array_lba);
}
+/* Validate that the backup GPT LBA is greater than all other LBAs in the header
+ */
+static psa_status_t validate_backup_gpt_lba(const uint64_t backup_lba,
+ const uint64_t primary_lba,
+ const uint64_t partition_array_end,
+ const struct gpt_header_t *header)
+{
+ if (backup_lba <= primary_lba) {
+ ERROR("Backup LBA (0x%08x%08x) must be final LBA on flash, "
+ "primary LBA at 0x%08x%08x\n",
+ (uint32_t)(backup_lba >> 32),
+ (uint32_t)(backup_lba),
+ (uint32_t)(primary_lba >> 32),
+ (uint32_t)(primary_lba));
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ if (backup_lba <= header->first_lba) {
+ ERROR("Backup LBA (0x%08x%08x) must be final LBA on flash, "
+ "first usable LBA at 0x%08x%08x\n",
+ (uint32_t)(backup_lba >> 32),
+ (uint32_t)(backup_lba),
+ (uint32_t)(header->first_lba >> 32),
+ (uint32_t)(header->first_lba));
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ if (backup_lba <= header->last_lba) {
+ ERROR("Backup LBA (0x%08x%08x) must be final LBA on flash, "
+ "last usable LBA at 0x%08x%08x\n",
+ (uint32_t)(backup_lba >> 32),
+ (uint32_t)(backup_lba),
+ (uint32_t)(header->last_lba >> 32),
+ (uint32_t)(header->last_lba));
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ if (backup_lba <= partition_array_end) {
+ ERROR("Backup LBA (0x%08x%08x) must be final LBA on flash, "
+ "partition array ends at LBA at 0x%08x%08x\n",
+ (uint32_t)(backup_lba >> 32),
+ (uint32_t)(backup_lba),
+ (uint32_t)(partition_array_end >> 32),
+ (uint32_t)(partition_array_end));
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ return PSA_SUCCESS;
+}
+
+/* Validate partition array is outside the area of usable flash */
+static psa_status_t validate_array_lba(const uint64_t partition_array_end,
+ const uint64_t usable_lba_start)
+{
+ if (partition_array_end >= usable_lba_start) {
+ ERROR("GPT partition array must not be in usable space: "
+ "0x%08x%08x >= 0x%08x%08x\n",
+ (uint32_t)(partition_array_end >> 32),
+ (uint32_t)partition_array_end,
+ (uint32_t)(usable_lba_start >> 32),
+ (uint32_t)usable_lba_start);
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ return PSA_SUCCESS;
+}
+
/* Validates a specific GPT. */
static psa_status_t validate_table(struct gpt_t *table, bool is_primary)
{
@@ -1564,6 +1637,48 @@ static psa_status_t validate_table(struct gpt_t *table, bool is_primary)
return PSA_ERROR_INVALID_SIGNATURE;
}
+ /* Check the backup LBA is greater than all other LBAs. Check also
+ * the partition array cannot be overritten by data by ensuring
+ * that it is not between the first and last usable LBAs
+ */
+ if (is_primary) {
+ psa_status_t ret = validate_backup_gpt_lba(
+ header->backup_lba,
+ header->current_lba,
+ partition_entry_lba(table, header->num_partitions - 1),
+ header);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* Go to the final LBA of the partition array, including unused entries */
+ ret = validate_array_lba(
+ partition_entry_lba(table, header->num_partitions - 1),
+ header->first_lba);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ } else {
+ psa_status_t ret = validate_backup_gpt_lba(
+ header->current_lba,
+ header->backup_lba,
+ partition_entry_lba(table, header->num_partitions - 1),
+ header);
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+
+ /* To flip the condition, negate the parameters passed: it becomes
+ * -array_lba >= -last_lba (equivalent to) array_lba < last_lba
+ * (equivalent to) last_lba >= array_lba. This is because the backup array is
+ * after the last_lba
+ */
+ ret = validate_array_lba(~(header->array_lba), ~(header->last_lba));
+ if (ret != PSA_SUCCESS) {
+ return ret;
+ }
+ }
+
if (is_primary) {
/* Any time the primary table is considered valid, cache the backup
* LBA field
diff --git a/lib/gpt/unittests/gpt/test_gpt.c b/lib/gpt/unittests/gpt/test_gpt.c
index db897b967..bd161ec74 100644
--- a/lib/gpt/unittests/gpt/test_gpt.c
+++ b/lib/gpt/unittests/gpt/test_gpt.c
@@ -493,6 +493,185 @@ void test_gpt_validate_should_failWhenArrayCrcBad(void)
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
}
+void test_gpt_validate_should_failWhenBackupLbaNotAtEndOfDisk(void)
+{
+ /* First test when the backup lba is before usable disk */
+ test_header.backup_lba = test_header.first_lba - 1;
+ setup_test_gpt();
+
+ /* Each entry will be read in order to check the partition array CRC */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* Then test when the backup is before in usable disk space */
+ test_header.backup_lba = test_header.first_lba;
+ setup_test_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ test_header.backup_lba = test_header.first_lba + 1;
+ setup_test_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ test_header.backup_lba = test_header.last_lba - 1;
+ setup_test_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ test_header.backup_lba = test_header.last_lba;
+ setup_test_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* Finally, test when the backup is before the end of the partition entry array */
+ test_header.backup_lba = test_header.array_lba - 1;
+ setup_test_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* For this scenario, manually setup the backup header so that the array LBA
+ * (also the backup header LBA) is valid on init and can then be validated
+ * with gpt_validate
+ */
+ test_header.backup_lba = test_header.array_lba;
+
+ /* Expect first a valid MBR read */
+ register_mocked_read(&test_mbr, sizeof(test_mbr));
+
+ /* Expect a GPT header read second */
+ register_mocked_read(&test_header, sizeof(test_header));
+
+ /* Expect third each partition is read to find the number in use. This is
+ * also the backup header, which will be cached
+ */
+ setup_backup_gpt();
+
+ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_init(&mock_driver, TEST_MAX_PARTITIONS));
+
+ /* Backup partition array read for crc */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* Now do the backup gpt header */
+ struct gpt_header_t backup_header;
+ test_header.backup_lba = test_header.first_lba - 1;
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ test_header.backup_lba = backup_header.first_lba;
+ backup_header.current_lba = backup_header.first_lba;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ test_header.backup_lba = backup_header.first_lba + 1;
+ backup_header.current_lba = backup_header.first_lba + 1;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ test_header.backup_lba = backup_header.last_lba - 1;
+ backup_header.current_lba = backup_header.last_lba - 1;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ test_header.backup_lba = backup_header.last_lba;
+ backup_header.current_lba = backup_header.last_lba;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ test_header.backup_lba = backup_header.array_lba - 1;
+ backup_header.current_lba = backup_header.array_lba - 1;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ test_header.backup_lba = backup_header.array_lba;
+ backup_header.current_lba = backup_header.array_lba;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+}
+
+void test_gpt_validate_should_failWhenPartitionArrayInUsableDiskSpace(void)
+{
+ /* First test when the primary partition array is in usable disk space */
+ test_header.array_lba = test_header.first_lba;
+ setup_test_gpt();
+
+ /* Each entry will be read in order to check the partition array CRC */
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ test_header.array_lba = test_header.first_lba + 1;
+ setup_test_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ test_header.array_lba = test_header.last_lba - 1;
+ setup_test_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ test_header.array_lba = test_header.last_lba;
+ setup_test_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* Then test when the primary partition array is after usable disk space */
+ test_header.array_lba = test_header.last_lba + 1;
+ setup_test_gpt();
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(true));
+
+ /* Now do the backup gpt header, ensuring it is always after usable space */
+ struct gpt_header_t backup_header;
+ MAKE_BACKUP_HEADER(backup_header, test_header);
+
+ backup_header.array_lba = test_header.first_lba - 1;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ /* Then test that the backup partition array is after usable disk space */
+ backup_header.array_lba = test_header.first_lba;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ backup_header.array_lba = test_header.first_lba + 1;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ backup_header.array_lba = test_header.last_lba - 1;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+
+ backup_header.array_lba = test_header.last_lba;
+ setup_test_gpt();
+ register_mocked_read(&backup_header, sizeof(backup_header));
+ register_mocked_read(&test_partition_array, sizeof(test_partition_array));
+ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_SIGNATURE, gpt_validate(false));
+}
+
void test_gpt_restore_should_restorePrimaryFromBackup(void)
{
/* Start with a valid GPT */
@@ -0,0 +1,151 @@
From 6391a6189ee2024f0ef956f56373f79128576230 Mon Sep 17 00:00:00 2001
From: Maulik Patel <maulik.patel@arm.com>
Date: Tue, 23 Sep 2025 21:26:44 +0100
Subject: [PATCH] Build: Fix compiler warnings
- Add header crypto_hw for crypto_hw_apply_debug_permissions()
- Add header int_com_port_driver.h for IComPortRxIntInit()
- Move psa_adac_platform_init() declaration to psa_adac_platform.h
- Add include path for psa-adac/transport_layer/transports/sdc-600
Signed-off-by: Maulik Patel <maulik.patel@arm.com>
Change-Id: I34f774a9843f7a3a62ad447fa0ae607184bd800a
Upstream-Status: Backport [6391a6189ee2024f0ef956f56373f79128576230]
Signed-off-by: Jon Mason <jon.mason@arm.com>
---
.../platform/arm/corstone1000/CMakeLists.txt | 2 ++
.../platform/arm/corstone1000/corstone1000.c | 7 ++++++-
.../platform/arm/corstone1000/include/platform/platform.h | 1 -
.../platform/arm/corstone1000/include/psa_adac_platform.h | 6 ++++++
.../platform/arm/rse/common/CMakeLists.txt | 1 +
.../platform/arm/rse/common/include/platform/platform.h | 1 -
.../platform/arm/rse/common/include/psa_adac_platform.h | 7 +++++++
.../platform/arm/rse/common/psa_adac_platform.c | 5 +++++
8 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/target/trusted-firmware-m/platform/arm/corstone1000/CMakeLists.txt b/target/trusted-firmware-m/platform/arm/corstone1000/CMakeLists.txt
index c36259e0b31f..604c9b72745d 100644
--- a/target/trusted-firmware-m/platform/arm/corstone1000/CMakeLists.txt
+++ b/target/trusted-firmware-m/platform/arm/corstone1000/CMakeLists.txt
@@ -20,6 +20,8 @@ target_include_directories(${PROJECT_NAME}
${CMAKE_CURRENT_SOURCE_DIR}
${PSA_ADAC_MBEDTLS_INCLUDE}
${PSA_ADAC_ROOT}/transport_layer/transports
+ ${PSA_ADAC_ROOT}/transport_layer/transports/sdc-600
+
)
target_compile_definitions(${PROJECT_NAME}
diff --git a/target/trusted-firmware-m/platform/arm/corstone1000/corstone1000.c b/target/trusted-firmware-m/platform/arm/corstone1000/corstone1000.c
index e629eed97236..e979b3246e12 100644
--- a/target/trusted-firmware-m/platform/arm/corstone1000/corstone1000.c
+++ b/target/trusted-firmware-m/platform/arm/corstone1000/corstone1000.c
@@ -12,6 +12,11 @@
#include "platform/msg_interface.h"
#include "demo-anchors.h"
#include <string.h>
+#include "crypto_hw.h"
+
+#ifdef PSA_ADAC_AS_TFM_RUNTIME_SERVICE
+#include "int_com_port_driver.h"
+#endif /* PSA_ADAC_AS_TFM_RUNTIME_SERVICE */
extern uint8_t discovery_template[];
extern size_t discovery_template_len;
@@ -70,7 +75,7 @@ int psa_adac_platform_check_certificate(uint8_t *crt, size_t crt_size)
int psa_adac_to_tfm_apply_permissions(uint8_t permissions_mask[16])
{
- /* This implementation only support coarse-grained secure debug
+ /* This implementation only support coarse-grained secure debug
* unlock (closed/open). Fine-grained access-control can be
* supported by defining a mapping from permissions_mask to
* dcu_reg_values.
diff --git a/target/trusted-firmware-m/platform/arm/corstone1000/include/platform/platform.h b/target/trusted-firmware-m/platform/arm/corstone1000/include/platform/platform.h
index e99d0d55f624..82b416f5f67f 100644
--- a/target/trusted-firmware-m/platform/arm/corstone1000/include/platform/platform.h
+++ b/target/trusted-firmware-m/platform/arm/corstone1000/include/platform/platform.h
@@ -31,7 +31,6 @@ adac_status_t psa_adac_change_life_cycle_state(uint8_t *input, size_t input_size
void psa_adac_close_session(void);
void psa_adac_resume(void);
void psa_adac_platform_lock(void);
-void psa_adac_platform_init(void);
int psa_adac_detect_debug_request(void);
void psa_adac_acknowledge_debug_request(void);
diff --git a/target/trusted-firmware-m/platform/arm/corstone1000/include/psa_adac_platform.h b/target/trusted-firmware-m/platform/arm/corstone1000/include/psa_adac_platform.h
index 26f10f8999ca..2ae4569f5ff1 100644
--- a/target/trusted-firmware-m/platform/arm/corstone1000/include/psa_adac_platform.h
+++ b/target/trusted-firmware-m/platform/arm/corstone1000/include/psa_adac_platform.h
@@ -30,5 +30,11 @@ int tfm_to_psa_adac_corstone1000_secure_debug(uint8_t *secure_debug_rotpk, uint3
*/
int psa_adac_to_tfm_apply_permissions(uint8_t permissions_mask[16]);
+/*
+ * Platform initialization function for PSA ADAC.
+ * This function should be called during runtime service init to initialize
+ * the PSA ADAC platform-specific components.
+ */
+void psa_adac_platform_init(void);
#endif /* __PSA_ADAC_PLATFORM_H__ */
diff --git a/target/trusted-firmware-m/platform/arm/rse/common/CMakeLists.txt b/target/trusted-firmware-m/platform/arm/rse/common/CMakeLists.txt
index 67214bb3f354..d1b9718a8183 100644
--- a/target/trusted-firmware-m/platform/arm/rse/common/CMakeLists.txt
+++ b/target/trusted-firmware-m/platform/arm/rse/common/CMakeLists.txt
@@ -23,6 +23,7 @@ target_include_directories(${PROJECT_NAME}
${PSA_ADAC_MBEDTLS_INCLUDE}
${PSA_ADAC_ROOT}/transport_layer/transports
${TFM_SRC_DIR}/platform/ext/target/arm/rse/common/partition
+ ${PSA_ADAC_ROOT}/transport_layer/transports/sdc-600
)
target_compile_definitions(${PROJECT_NAME}
diff --git a/target/trusted-firmware-m/platform/arm/rse/common/include/platform/platform.h b/target/trusted-firmware-m/platform/arm/rse/common/include/platform/platform.h
index 57044f05a67a..afd4b3033a4b 100644
--- a/target/trusted-firmware-m/platform/arm/rse/common/include/platform/platform.h
+++ b/target/trusted-firmware-m/platform/arm/rse/common/include/platform/platform.h
@@ -32,7 +32,6 @@ void psa_adac_resume(void);
void psa_adac_platform_lock(void);
int psa_adac_platform_check_token(uint8_t *token, size_t token_size);
int psa_adac_platform_check_certificate(uint8_t *crt, size_t crt_size);
-void psa_adac_platform_init(void);
int psa_adac_detect_debug_request(void);
void psa_adac_acknowledge_debug_request(void);
int psa_adac_apply_permissions(uint8_t permissions_mask[16]);
diff --git a/target/trusted-firmware-m/platform/arm/rse/common/include/psa_adac_platform.h b/target/trusted-firmware-m/platform/arm/rse/common/include/psa_adac_platform.h
index a47788566aec..3e1dc73c4e0e 100644
--- a/target/trusted-firmware-m/platform/arm/rse/common/include/psa_adac_platform.h
+++ b/target/trusted-firmware-m/platform/arm/rse/common/include/psa_adac_platform.h
@@ -34,6 +34,13 @@ int tfm_to_psa_adac_rse_secure_debug(uint8_t *secure_debug_rotpk, uint32_t len);
*/
int psa_adac_to_tfm_apply_permissions(uint8_t permissions_mask[16]);
+/*
+ * Platform initialization function for PSA ADAC.
+ * This function should be called during runtime service init to initialize
+ * the PSA ADAC platform-specific components.
+ */
+void psa_adac_platform_init(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/target/trusted-firmware-m/platform/arm/rse/common/psa_adac_platform.c b/target/trusted-firmware-m/platform/arm/rse/common/psa_adac_platform.c
index fa2e7c023ef4..5c5cfd1529a3 100644
--- a/target/trusted-firmware-m/platform/arm/rse/common/psa_adac_platform.c
+++ b/target/trusted-firmware-m/platform/arm/rse/common/psa_adac_platform.c
@@ -21,6 +21,11 @@
#include "rse_debug_after_reset.h"
#include "lcm_drv.h"
#include "device_definition.h"
+
+#ifdef PSA_ADAC_AS_TFM_RUNTIME_SERVICE
+#include "int_com_port_driver.h"
+#endif /* PSA_ADAC_AS_TFM_RUNTIME_SERVICE */
+
#define ROTPK_ANCHOR_ALG PSA_ALG_SHA_512
#define UINT8_SIZE_IN_BITS 8
@@ -0,0 +1,32 @@
From 972bf711ad884607409c225f9338bf25206e29e8 Mon Sep 17 00:00:00 2001
From: Bence Balogh <bence.balogh@arm.com>
Date: Wed, 31 Jul 2024 15:56:51 +0200
Subject: [PATCH] Fix psa_key_handle_t initialization
If the MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER macro is defined in the
mbedcrypto configuration header file then the psa_key_handle_t is a
struct. In this case, it is defined in the used configuration header
so the struct cannot be initialized with -1.
Signed-off-by: Bence Balogh <bence.balogh@arm.com>
Upstream-Status: Inappropriate [mbedcrypto configs have to be fixed to build secure-debug mps3 without this patch]
---
psa_crypto/adac_crypto_psa_mac.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/psa_crypto/adac_crypto_psa_mac.c b/psa_crypto/adac_crypto_psa_mac.c
index 046fef7..93ab8f9 100644
--- a/psa_crypto/adac_crypto_psa_mac.c
+++ b/psa_crypto/adac_crypto_psa_mac.c
@@ -198,7 +198,7 @@ psa_status_t psa_adac_verify_mac(uint8_t key_type,
size_t mac_size)
{
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
- psa_key_handle_t handle = -1;
+ psa_key_handle_t handle = {0};
psa_status_t ret = PSA_ERROR_NOT_SUPPORTED;
psa_key_type_t type = 0;
size_t bits = 0;
--
2.25.1
@@ -28,35 +28,78 @@ EXTRA_OECMAKE += "-DPLATFORM_IS_FVP=${TFM_PLATFORM_IS_FVP}"
EXTRA_OECMAKE += "-DCC312_LEGACY_DRIVER_API_ENABLED=OFF"
EXTRA_OECMAKE:append = " -DENABLE_MULTICORE=${@bb.utils.contains('MACHINE_FEATURES', 'corstone1000_smp', 'TRUE', 'FALSE', d)}"
EXTRA_OECMAKE:append:corstone1000-mps3 = " -DPLATFORM_PSA_ADAC_SECURE_DEBUG=${@bb.utils.contains('MACHINE_FEATURES', 'secure-debug', 'ON', 'OFF', d)}"
# Keep the device in CM until authenticated DCU_EN can be preserved across
# reset and applied from BL2.
EXTRA_OECMAKE:append:corstone1000-mps3 = " -DCORSTONE1000_SKIP_PROVISIONING_FOR_DEBUG=${@bb.utils.contains('MACHINE_FEATURES', 'secure-debug', 'ON', 'OFF', d)}"
EXTRA_OECMAKE:append:corstone1000-mps3 = " -DPLATFORM_PSA_ADAC_SOURCE_PATH=${S}/external/tfm-psa-adac -DPLATFORM_PSA_ADAC_BUILD_PATH=${B}/tfm-psa-adac-build"
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI:append:corstone1000 = " \
file://0001-CC312-alignment-of-cc312-differences-between-fvp-and.patch \
file://0002-Corstone-1000-Enable-different-DRBG-configurations.patch \
file://0003-bl2-corstone-1000-secure-debug-waiting-in-CM-LCS.patch \
file://0004-Workaround-compile-errors-in-AES.patch \
file://0005-plat-cs1k-Removed-unused-variables.patch \
file://0006-lib-gpt-Show-intent-of-GUIDs-in-unittests-more-clear.patch \
file://0007-lib-gpt-Provide-macro-identifying-free-space.patch \
file://0008-lib-gpt-Add-operation-to-duplicate-entries.patch \
file://0009-lib-gpt-Consecutively-erase-blocks-when-moving-parti.patch \
file://0010-lib-gpt-Clarify-API-operation.patch \
file://0011-lib-gpt-Add-metadata-only-API-operations.patch \
file://0012-plat-cs1k-Add-flash-erase-protection.patch \
file://0013-plat-cs1k-Remove-unused-FWU-partitions-upon-version-.patch \
file://0014-plat-cs1k-Duplicate-old-images-in-FWU.patch \
file://0015-platform-corstone1000-Increase-FIP-partition-size.patch \
file://0016-platform-corstone1000-Optionally-skip-provisioning.patch \
file://0001-arm-trusted-firmware-m-disable-address-warnings-into.patch \
file://0002-Platform-CS1000-Remove-unused-BL1-files.patch \
file://0003-Platform-Corstone1000-Fix-BL1-compiler-switch-and-re.patch \
file://0004-CC312-alignment-of-cc312-differences-between-fvp-and.patch \
file://0005-Platform-Corstone1000-Enable-FWU-partition.patch \
file://0006-Platform-Corstone1000-Implement-Bootloader-Abstracti.patch \
file://0007-Platform-Corstone1000-Increase-buffer-sizes.patch \
file://0008-Platform-Corstone1000-Remove-duplicate-configuration.patch \
file://0009-plat-corstone1000-Add-support-for-Cortex-A320-varian.patch \
file://0010-Corstone-1000-Enable-different-DRBG-configurations.patch \
file://0011-bl2-corstone-1000-Remove-psa_adac_to_tfm_apply_permi.patch \
file://0012-bl2-corstone-1000-secure-debug-waiting-in-CM-LCS.patch \
file://0013-Build-adjust-CS1000-platform-for-GCC-v14.2.patch \
file://0014-Workaround-compile-errors-in-AES.patch \
file://0015-CC312-Add-barrier-before-first-AO-lock-write.patch \
file://0016-Platform-CS1K-make-mutlicore-support-platform-generi.patch \
file://0017-lib-efi_guid-Added-EFI-GUID-library.patch \
file://0018-lib-efi_soft_crc-Added-EFI-CRC-library.patch \
file://0019-lib-gpt-Implemented-generic-GPT-parser-for-flash.patch \
file://0020-lib-gpt-Expanded-how-GPT-partition-can-be-identified.patch \
file://0021-lib-gpt-Added-operations-to-modify-partitions.patch \
file://0022-lib-gpt-Added-operation-to-move-entry.patch \
file://0023-lib-gpt-Added-ability-to-create-and-remove-partition.patch \
file://0024-lib-gpt-Added-table-validation-operations.patch \
file://0025-lib-gpt-Added-defragmentation-operation.patch \
file://0026-lib-GPT-Fix-cppcheck-warnings.patch \
file://0027-lib-efi_guid-Remove-unecessary-include-folder.patch \
file://0028-lib-efi_guid-Correct-included-folder.patch \
file://0029-lib-efi_soft_crc-Correct-include-directory.patch \
file://0030-lib-gpt-Add-missing-link-library.patch \
file://0031-lib-gpt-Correct-variable-name-used.patch \
file://0032-lib-gpt-Correct-include-directory.patch \
file://0033-lib-gpt-Move-contents-of-CMake-config-file.patch \
file://0034-plat-cs1k-Fixed-formatting-errors.patch \
file://0035-plat-cs1k-Removed-unused-variables.patch \
file://0036-plat-cs1k-Fixed-bad-function-returns.patch \
file://0037-plat-cs1k-Improved-logging-in-function.patch \
file://0038-plat-cs1k-Remove-unused-function.patch \
file://0039-plat-cs1k-Reduce-BL1-binary-size.patch \
file://0040-plat-cs1k-Update-license-identifier.patch \
file://0041-plat-cs1k-Changed-to-use-new-GPT-library.patch \
file://0042-plat-cs1k-Move-variable-from-stack-to-data.patch \
file://0043-plat-cs1k-Create-and-remove-FWU-image-partitions.patch \
file://0044-plat-cs1k-Derive-host-base-addresses-from-offsets.patch \
file://0045-plat-cs1k-Drive-NPU-via-external-system-reset-contro.patch \
file://0046-lib-gpt-Fix-final-entry-not-being-removed.patch \
file://0047-lib-gpt-Replace-warnings-with-errors.patch \
file://0048-lib-gpt-Enforce-entry-size-of-128-bytes.patch \
file://0049-lib-gpt-Ensure-block-size-complies-with-spec.patch \
file://0050-lib-gpt-Expand-table-validation.patch \
file://0051-lib-gpt-Show-intent-of-GUIDs-in-unittests-more-clear.patch \
file://0052-lib-gpt-Provide-macro-identifying-free-space.patch \
file://0053-lib-gpt-Add-operation-to-duplicate-entries.patch \
file://0054-lib-gpt-Consecutively-erase-blocks-when-moving-parti.patch \
file://0055-lib-gpt-Clarify-API-operation.patch \
file://0056-lib-gpt-Add-metadata-only-API-operations.patch \
file://0057-plat-cs1k-Add-flash-erase-protection.patch \
file://0058-plat-cs1k-Remove-unused-FWU-partitions-upon-version-.patch \
file://0059-plat-cs1k-Duplicate-old-images-in-FWU.patch \
"
SRCREV_tfm-psa-adac:corstone1000 = "f2809ae231be33a1afcd7714f40756c67d846c88"
FILESEXTRAPATHS:prepend:corstone1000-mps3 := "${THISDIR}/files/corstone1000/psa-adac:"
SRC_URI:append:corstone1000-mps3 = " \
file://0001-PSA-revert-header-versions.patch;patchdir=external/tfm-psa-adac \
file://0002-cmake-Update-psa_adac_psa_crypto-dependencies.patch;patchdir=external/tfm-psa-adac \
file://0002-Fix-psa_key_handle_t-initialization.patch;patchdir=external/tfm-psa-adac \
file://0003-cmake-Update-psa_adac_psa_crypto-dependencies.patch;patchdir=external/tfm-psa-adac \
file://0001-Build-Fix-compiler-warnings.patch;patchdir=external/tfm-psa-adac \
"
create_bl1_image(){
@@ -86,23 +86,6 @@ SRC_URI:append = " \
file://0040-configs-corstone1000-disable-EFI-debug-support.patch \
"
# Add FF-A bus runtime support
SRC_URI:append = " \
file://0041-efi_loader-add-runtime-memset-helper.patch \
file://0042-arm-ffa-add-FF-A-bus-runtime-support.patch \
file://0043-efi_loader-add-FF-A-runtime-support-in-EFI-variable-.patch \
file://0044-efi_loader-enable-EFI-runtime-SetVariable-GetVariabl.patch \
file://0045-efi_loader-move-runtime-GetVariable-helpers-to-efi_v.patch \
file://0046-corstone1000-enable-bootefi-selftest.patch \
file://0047-efi-selftest-add-runtime-variable-tests-with-non-vol.patch \
file://0048-test-dm-add-sandbox-FF-A-runtime-transport-tests.patch \
file://0049-sandbox-ffa-share-synthetic-partition-metadata-via-m.patch \
file://0050-doc-arm64-document-FF-A-runtime-path-for-EFI-variabl.patch \
file://0051-doc-bootefi-note-two-phase-runtime-variables-selftes.patch \
file://0052-efi_loader-align-FF-A-cache-maintenance-with-runtime.patch \
file://0053-corstone1000-a320-enable-bootefi-selftest.patch \
"
uboot_configure_config:append() {
openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=CRT/ -keyout ${B}/CRT.key -out ${S}/CRT.crt -nodes -days 365
}
@@ -1,4 +1,4 @@
From 8113805be420994a67bde766f0100fc3c39e985e Mon Sep 17 00:00:00 2001
From 891cef3c87081d0b719213c98cb2a50ecb601332 Mon Sep 17 00:00:00 2001
From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Date: Wed, 30 Oct 2024 14:10:43 +0000
Subject: [PATCH] arm_ffa: Add NULL pointer check to the uclass driver
@@ -18,7 +18,7 @@ Upstream-Status: Submitted [cover letter: https://lore.kernel.org/all/2025070215
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 76a8775e911..2f5fc879ff4 100644
index 96c64964bb7..f8d231204db 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -1,6 +1,6 @@
@@ -29,7 +29,7 @@ index 76a8775e911..2f5fc879ff4 100644
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -951,6 +951,9 @@ int ffa_partition_info_get(struct udevice *dev, const char *uuid_str,
@@ -954,6 +954,9 @@ int ffa_partition_info_get(struct udevice *dev, const char *uuid_str,
{
struct ffa_bus_ops *ops = ffa_get_ops(dev);
@@ -39,7 +39,7 @@ index 76a8775e911..2f5fc879ff4 100644
if (!ops->partition_info_get)
return -ENOSYS;
@@ -976,6 +979,9 @@ int ffa_sync_send_receive(struct udevice *dev, u16 dst_part_id,
@@ -979,6 +982,9 @@ int ffa_sync_send_receive(struct udevice *dev, u16 dst_part_id,
{
struct ffa_bus_ops *ops = ffa_get_ops(dev);
@@ -49,7 +49,7 @@ index 76a8775e911..2f5fc879ff4 100644
if (!ops->sync_send_receive)
return -ENOSYS;
@@ -997,6 +1003,9 @@ int ffa_rxtx_unmap(struct udevice *dev)
@@ -1000,6 +1006,9 @@ int ffa_rxtx_unmap(struct udevice *dev)
{
struct ffa_bus_ops *ops = ffa_get_ops(dev);
@@ -1,4 +1,4 @@
From 05e6d6b8949eb00a1a22f75a53e005a8d9e3c87e Mon Sep 17 00:00:00 2001
From d4dc79029ab883a5baa33fbecd5db20a93716172 Mon Sep 17 00:00:00 2001
From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Date: Tue, 29 Oct 2024 17:22:35 +0000
Subject: [PATCH] arm_ffa: Add FFA_MEM_SHARE support
@@ -48,10 +48,10 @@ index f966f8ba6af..3eec735d741 100644
- FF-A bus discovery makes sure FF-A framework is responsive and compatible
with the driver
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 2f5fc879ff4..d09e31177d7 100644
index f8d231204db..2ba0b925fa6 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -92,6 +92,20 @@ static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = {
@@ -95,6 +95,20 @@ static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = {
"DENIED: Buffer pair already registered",
},
},
@@ -72,7 +72,7 @@ index 2f5fc879ff4..d09e31177d7 100644
};
/**
@@ -926,6 +940,177 @@ int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id,
@@ -929,6 +943,177 @@ int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id,
return ffa_to_std_errno(ffa_errno);
}
@@ -250,7 +250,7 @@ index 2f5fc879ff4..d09e31177d7 100644
/* FF-A driver operations (used by clients for communicating with FF-A)*/
/**
@@ -1012,6 +1197,31 @@ int ffa_rxtx_unmap(struct udevice *dev)
@@ -1015,6 +1200,31 @@ int ffa_rxtx_unmap(struct udevice *dev)
return ops->rxtx_unmap(dev);
}
@@ -283,7 +283,7 @@ index 2f5fc879ff4..d09e31177d7 100644
* ffa_do_probe() - probing FF-A framework
* @dev: the FF-A bus device (arm_ffa)
diff --git a/drivers/firmware/arm-ffa/arm-ffa.c b/drivers/firmware/arm-ffa/arm-ffa.c
index 9e6b5dcc542..8f7c5794f95 100644
index 94e6105cb38..df904cae412 100644
--- a/drivers/firmware/arm-ffa/arm-ffa.c
+++ b/drivers/firmware/arm-ffa/arm-ffa.c
@@ -1,6 +1,6 @@
@@ -294,7 +294,7 @@ index 9e6b5dcc542..8f7c5794f95 100644
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -81,6 +81,7 @@ static const struct ffa_bus_ops ffa_ops = {
@@ -84,6 +84,7 @@ static const struct ffa_bus_ops ffa_ops = {
.partition_info_get = ffa_get_partitions_info_hdlr,
.sync_send_receive = ffa_msg_send_direct_req_hdlr,
.rxtx_unmap = ffa_unmap_rxtx_buffers_hdlr,
@@ -1,4 +1,4 @@
From c26404d7403748b60e61205b68b08912c34f436d Mon Sep 17 00:00:00 2001
From 4a608633474b545eac07c3e4dd27bdad7bdfb005 Mon Sep 17 00:00:00 2001
From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Date: Tue, 29 Oct 2024 17:24:43 +0000
Subject: [PATCH] arm_ffa: Add FFA_MEM_RECLAIM support
@@ -47,10 +47,10 @@ index 3eec735d741..d2c4fb49f79 100644
- FF-A bus discovery makes sure FF-A framework is responsive and compatible
with the driver
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index d09e31177d7..84023f6a94c 100644
index 2ba0b925fa6..597b4e994b4 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -106,6 +106,18 @@ static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = {
@@ -109,6 +109,18 @@ static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = {
"DENIED: Memory region ownership, permission, access or attributes error",
},
},
@@ -69,7 +69,7 @@ index d09e31177d7..84023f6a94c 100644
};
/**
@@ -1111,6 +1123,44 @@ int ffa_memory_share_hdlr(struct udevice *dev, struct ffa_mem_ops_args *args)
@@ -1114,6 +1126,44 @@ int ffa_memory_share_hdlr(struct udevice *dev, struct ffa_mem_ops_args *args)
return ffa_memory_ops(dev, FFA_MEM_SHARE, args);
}
@@ -114,7 +114,7 @@ index d09e31177d7..84023f6a94c 100644
/* FF-A driver operations (used by clients for communicating with FF-A)*/
/**
@@ -1222,6 +1272,32 @@ int ffa_memory_share(struct udevice *dev, struct ffa_mem_ops_args *args)
@@ -1225,6 +1275,32 @@ int ffa_memory_share(struct udevice *dev, struct ffa_mem_ops_args *args)
return ops->memory_share(dev, args);
}
@@ -148,10 +148,10 @@ index d09e31177d7..84023f6a94c 100644
* ffa_do_probe() - probing FF-A framework
* @dev: the FF-A bus device (arm_ffa)
diff --git a/drivers/firmware/arm-ffa/arm-ffa.c b/drivers/firmware/arm-ffa/arm-ffa.c
index 8f7c5794f95..863dc7e5cac 100644
index df904cae412..de36f5647d2 100644
--- a/drivers/firmware/arm-ffa/arm-ffa.c
+++ b/drivers/firmware/arm-ffa/arm-ffa.c
@@ -82,6 +82,7 @@ static const struct ffa_bus_ops ffa_ops = {
@@ -85,6 +85,7 @@ static const struct ffa_bus_ops ffa_ops = {
.sync_send_receive = ffa_msg_send_direct_req_hdlr,
.rxtx_unmap = ffa_unmap_rxtx_buffers_hdlr,
.memory_share = ffa_memory_share_hdlr,
@@ -1,4 +1,4 @@
From 1c41fc705dc986935000ecb49a167ab823b11116 Mon Sep 17 00:00:00 2001
From 28ecd80dd073448b1ec200f1bf4b6c2c4659af16 Mon Sep 17 00:00:00 2001
From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Date: Thu, 17 Oct 2024 22:11:22 +0100
Subject: [PATCH] arm_ffa: sandbox: Replace the emulator error log with debug
@@ -17,7 +17,7 @@ Upstream-Status: Submitted [cover letter: https://lore.kernel.org/all/2025070215
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
index 6198d687354..954cada27ce 100644
index 1521d9b66ac..d2f051f7e2a 100644
--- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c
+++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
@@ -1,6 +1,6 @@
@@ -28,7 +28,7 @@ index 6198d687354..954cada27ce 100644
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -655,8 +655,7 @@ void sandbox_arm_ffa_smccc_smc(ffa_value_t *args, ffa_value_t *res)
@@ -658,8 +658,7 @@ void sandbox_arm_ffa_smccc_smc(ffa_value_t *args, ffa_value_t *res)
args->a0);
}
@@ -1,4 +1,4 @@
From eaa2884eef6015b530ea66317b908f035ce73124 Mon Sep 17 00:00:00 2001
From 962b8b4f2baf4a84de1fc76382ef7aa240ec1534 Mon Sep 17 00:00:00 2001
From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Date: Tue, 11 Feb 2025 17:54:45 +0000
Subject: [PATCH] arm_ffa: sandbox: Improve the readability of clearing the X
@@ -40,10 +40,10 @@ index b0881822d78..5c46547beab 100644
/* number of emulated FF-A secure partitions (SPs) */
#define SANDBOX_PARTITIONS_CNT (4)
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
index 954cada27ce..48b6d1fec2e 100644
index d2f051f7e2a..dcf5bce9435 100644
--- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c
+++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
@@ -80,7 +80,7 @@ static int sandbox_ffa_version(struct udevice *emul, ffa_value_t *pargs, ffa_val
@@ -83,7 +83,7 @@ static int sandbox_ffa_version(struct udevice *emul, ffa_value_t *pargs, ffa_val
res->a0 = priv->fwk_version;
/* x1-x7 MBZ */
@@ -52,7 +52,7 @@ index 954cada27ce..48b6d1fec2e 100644
return 0;
}
@@ -108,7 +108,7 @@ static int sandbox_ffa_id_get(struct udevice *emul, ffa_value_t *pargs, ffa_valu
@@ -111,7 +111,7 @@ static int sandbox_ffa_id_get(struct udevice *emul, ffa_value_t *pargs, ffa_valu
res->a2 = priv->id;
/* x3-x7 MBZ */
@@ -61,7 +61,7 @@ index 954cada27ce..48b6d1fec2e 100644
return 0;
}
@@ -133,14 +133,14 @@ static int sandbox_ffa_features(ffa_value_t *pargs, ffa_value_t *res)
@@ -136,14 +136,14 @@ static int sandbox_ffa_features(ffa_value_t *pargs, ffa_value_t *res)
res->a2 = RXTX_BUFFERS_MIN_SIZE;
res->a3 = 0;
/* x4-x7 MBZ */
@@ -78,7 +78,7 @@ index 954cada27ce..48b6d1fec2e 100644
log_err("FF-A interface %lx not implemented\n", pargs->a1);
return ffa_to_std_errmap[NOT_SUPPORTED];
@@ -245,7 +245,7 @@ cleanup:
@@ -248,7 +248,7 @@ cleanup:
res->a1 = 0;
/* x3-x7 MBZ */
@@ -87,7 +87,7 @@ index 954cada27ce..48b6d1fec2e 100644
return ret;
}
@@ -302,7 +302,7 @@ feedback:
@@ -305,7 +305,7 @@ feedback:
res->a1 = 0;
/* x3-x7 MBZ */
@@ -96,7 +96,7 @@ index 954cada27ce..48b6d1fec2e 100644
return ret;
}
@@ -349,7 +349,7 @@ feedback:
@@ -352,7 +352,7 @@ feedback:
res->a1 = 0;
/* x3-x7 MBZ */
@@ -105,7 +105,7 @@ index 954cada27ce..48b6d1fec2e 100644
return ret;
}
@@ -385,7 +385,7 @@ static int sandbox_ffa_rx_release(struct udevice *emul, ffa_value_t *pargs, ffa_
@@ -388,7 +388,7 @@ static int sandbox_ffa_rx_release(struct udevice *emul, ffa_value_t *pargs, ffa_
res->a1 = 0;
/* x3-x7 MBZ */
@@ -114,7 +114,7 @@ index 954cada27ce..48b6d1fec2e 100644
return ret;
}
@@ -445,7 +445,7 @@ static int sandbox_ffa_msg_send_direct_req(struct udevice *emul,
@@ -448,7 +448,7 @@ static int sandbox_ffa_msg_send_direct_req(struct udevice *emul,
res->a2 = -INVALID_PARAMETERS;
/* x3-x7 MBZ */

Some files were not shown because too many files have changed in this diff Show More