1
0
mirror of https://git.yoctoproject.org/meta-arm synced 2026-05-07 04:58:57 +00:00

arm-bsp/trusted-firmware-m:cs1k: Use new GPT duplicate functionality

Uses the new GPT duplicate operation during a firmware update. This also
adds flash erase protections so that the operation is not too slow and
erasing flash multiple times redundantly.

Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Signed-off-by: Jon Mason <jon.mason@arm.com>
This commit is contained in:
Frazer Carsley
2026-04-24 16:36:56 +01:00
committed by Jon Mason
parent 1eaa431ff3
commit 78354ba272
4 changed files with 471 additions and 0 deletions
@@ -0,0 +1,98 @@
From 60277832aa6d4a205a5b1180f0513de0eb7c84c6 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Tue, 17 Mar 2026 11:05:45 +0000
Subject: [PATCH] plat: cs1k: Add flash erase protection
The GPT library deals in blocks, whereas flash deals in sectors. On
cs1k, eight blocks make up a sector. So, when the GPT library requests a
block erase from the platform driver, it actually erases the entire
sector, and then rewrites the data that was there for the blocks that
weren't being erased.
This means that if all eight blocks in a sector were erased in a row,
then the same sector would be erased eight times, which is both slow and
also redundant, wearing out the flash device without need. These
protections prevent flash erasure if the data is already equal to the
erased value.
Change-Id: Id8efe515647f45ac8e65cc95ef1bf58f9160aca2
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/50259/1]
---
.../ext/target/arm/corstone1000/io/io_gpt.c | 42 +++++++++++++++++--
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/platform/ext/target/arm/corstone1000/io/io_gpt.c b/platform/ext/target/arm/corstone1000/io/io_gpt.c
index 513c77016..f7c3d79d2 100644
--- a/platform/ext/target/arm/corstone1000/io/io_gpt.c
+++ b/platform/ext/target/arm/corstone1000/io/io_gpt.c
@@ -53,6 +53,32 @@ static uint8_t sector_buf[FLASH_SECTOR_SIZE];
/* From io_gpt.h - the driver given to the GPT library */
struct gpt_flash_driver_t io_gpt_flash_driver = {0};
+/* Read the bytes that need to be erased. If they are already erased_value,
+ * report that an erase is not required. This is to reduce the number of flash
+ * erase cyles. If the read fails in any way, report erase required.
+ */
+static bool erase_required(uint32_t erase_addr,
+ size_t num_bytes)
+{
+ if (num_bytes > FLASH_SECTOR_SIZE) {
+ return true;
+ }
+
+ int32_t ret = flash_driver->ReadData(erase_addr, sector_buf, num_bytes);
+ if (ret < 0 || (uint32_t)ret != num_bytes) {
+ return true;
+ }
+
+ uint8_t erased_value = flash_driver->GetInfo()->erased_value;
+ for (size_t offset = 0; offset < num_bytes; ++offset) {
+ if (sector_buf[offset] != erased_value) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* Erases TFM_GPT_BLOCK_SIZE bytes from offset within the sector beginning at
* sector_addr. This is done via a read-erase-write pattern whereby data is read,
* the sector is erased, and data written back to the parts of the sector that
@@ -61,6 +87,10 @@ struct gpt_flash_driver_t io_gpt_flash_driver = {0};
static gpt_flash_err_t partially_erase_sector(uint32_t sector_addr,
uint32_t offset)
{
+ if (!erase_required(sector_addr + offset, TFM_GPT_BLOCK_SIZE)) {
+ return GPT_FLASH_SUCCESS;
+ }
+
if (flash_driver->ReadData(
sector_addr,
sector_buf,
@@ -139,6 +169,10 @@ static ssize_t flash_erase(uint64_t lba, size_t num_blocks)
/* Whole sector erases until last sector */
for (size_t i = 0; i < num_sectors - 1; ++i) {
+ if (!erase_required(erase_addr + i * FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE)) {
+ continue;
+ }
+
int32_t ret = flash_driver->EraseSector(erase_addr + i * FLASH_SECTOR_SIZE);
if (ret != ARM_DRIVER_OK) {
return i;
@@ -146,9 +180,11 @@ static ssize_t flash_erase(uint64_t lba, size_t num_blocks)
}
if (num_blocks % LBAS_PER_SECTOR == 0 && lba % LBAS_PER_SECTOR == 0) {
- /* Fully erase final sector */
- if (flash_driver->EraseSector(last_erase_addr) != ARM_DRIVER_OK) {
- return (num_sectors - 1) * LBAS_PER_SECTOR;
+ /* Fully erase final sector if required */
+ if (erase_required(last_erase_addr, FLASH_SECTOR_SIZE)) {
+ if (flash_driver->EraseSector(last_erase_addr) != ARM_DRIVER_OK) {
+ return (num_sectors - 1) * LBAS_PER_SECTOR;
+ }
}
} else {
/* Partial erase of final sector */
@@ -0,0 +1,153 @@
From 281f6799d6de19e63cbcf175ad848b8c8f2cc220 Mon Sep 17 00:00:00 2001
From: Frazer Carsley <frazer.carsley@arm.com>
Date: Fri, 10 Apr 2026 17:15:36 +0100
Subject: [PATCH] plat: cs1k: Remove unused FWU partitions upon version
rejection
If a firmware update (FWU) is attempted and the version of any image is
lower or equal to the current version, the entire capsule is rejected
and the previous bank used to continue booting. The partitions created
during staging for the to-be images therefore can be removed and the
space free'd up.
Change-Id: I9b74c2ed5efee938c14dbdd0380d8d094e71c10e
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/50260/1]
---
.../bootloader/mcuboot/tfm_mcuboot_fwu.c | 108 ++++++++++++------
1 file changed, 75 insertions(+), 33 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 d85590c71..557e48d07 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
@@ -1105,6 +1105,54 @@ static psa_status_t erase_image(uint32_t image_offset, uint32_t image_size)
return PSA_SUCCESS;
}
+#ifndef BL1_BUILD
+/* stale index is the index of the partition to remove within the partition entry
+ * array, which could be representing either bank 0 or bank 1. name_index is the
+ * index of partition to remove within the fwu_images image_names index, which is
+ * fixed at compile time in the structure
+ */
+static psa_status_t remove_all_stale_partitions(const uint32_t stale_index,
+ const uint32_t name_index)
+{
+ psa_status_t ret;
+
+ 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), stale_index, &part);
+
+ if (ret == PSA_ERROR_DOES_NOT_EXIST) {
+ FWU_LOG_MSG("%s: Unable to find partition '%s', skipping removal\r\n",
+ __func__, fwu_image[i].image_names[name_index]);
+ continue;
+ } 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[name_index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to read partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[name_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[name_index]);
+ return ret;
+ } else if (ret < 0) {
+ FWU_LOG_MSG("%s: Unable to remove partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[name_index]);
+ return ret;
+ }
+
+ FWU_LOG_MSG("%s: Removed GPT partition '%s'\r\n",
+ __func__, fwu_image[i].image_names[name_index]);
+ }
+
+ return ret;
+}
+#endif
+
static psa_status_t fwu_select_previous(
struct fwu_metadata *metadata,
struct fwu_private_metadata *priv_metadata)
@@ -1162,40 +1210,12 @@ static psa_status_t fwu_select_previous(
#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
+ * (previous active) 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]);
+ ret = remove_all_stale_partitions(1, metadata->previous_active_index);
+ if (ret != PSA_SUCCESS) {
+ return ret;
}
#endif /* BL1_BUILD */
@@ -1971,6 +1991,28 @@ 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__);
+
+#ifndef BL1_BUILD
+ /* The FWU process short circuits at this point, so remove all images,
+ * effecitvely treating them all as rejected. Ignore return code and
+ * in order to return PSA_OPERATION_INCOMPLETE as per PSA FWU API.
+ */
+ uint32_t previous_active_index;
+ 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_DATA_INVALID;
+ goto out;
+ }
+
+ /* The newer index should be removed as that was just created in the
+ * staging phase.
+ */
+ (void)remove_all_stale_partitions(1, previous_active_index);
+#endif
ret = PSA_OPERATION_INCOMPLETE;
goto out;
}
@@ -0,0 +1,217 @@
From 3c7cb3432084df3b75b6382e543f3fc2352e32cf 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: Duplicate old images in FWU
When copying existing partitions during a partial firmware update, the
GPT library is now used to duplicate the old partitions and then rename
them accordingly. This streamlines the steps of
1. creating a new partition for the image to be copied into and
2. the copying itself
into a single library call.
Change-Id: Ibd169dcc14ed1c946bbd6c30b6962c89055d0e8e
Signed-off-by: Frazer Carsley <frazer.carsley@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/50261/1]
---
.../bootloader/mcuboot/tfm_mcuboot_fwu.c | 144 +++++++++---------
1 file changed, 68 insertions(+), 76 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 557e48d07..c48d51b32 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,7 +39,6 @@
* 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
@@ -2171,94 +2170,24 @@ out:
return ret;
}
+#ifdef BL1_BUILD
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;
+ /* Use offsets directly */
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 */
+ 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;
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;
- }
-
- struct partition_entry_t prev_active_part;
- ret = gpt_entry_read_by_type(
- &(fwu_image[image_index].image_type),
- 1,
- &prev_active_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[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) {
@@ -2270,7 +2199,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, flash_data_buf, data_size);
+ data_transferred_count = FWU_METADATA_FLASH_DEV.ReadData(offset_read, data, 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;
@@ -2285,7 +2214,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, flash_data_buf, data_size);
+ data_transferred_count = FWU_METADATA_FLASH_DEV.ProgramData(offset_write, data, 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;
@@ -2304,6 +2233,69 @@ static psa_status_t copy_image_from_other_bank(int image_index,
FWU_LOG_MSG("%s: exit \n\r", __func__);
return PSA_SUCCESS;
}
+#else
+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;
+
+ /* Use GPT to find and copy the correct image */
+ uint32_t bank_offset[NR_OF_FW_BANKS] = {BANK_0_PARTITION_OFFSET, BANK_1_PARTITION_OFFSET};
+ uint64_t new_lba =
+ (bank_offset[previous_active_index] + fwu_image[image_index].image_offset) / TFM_GPT_BLOCK_SIZE;
+
+ struct partition_entry_t active_part;
+ psa_status_t 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;
+ }
+
+ struct efi_guid_t new_guid;
+ ret = gpt_entry_duplicate(&(active_part.partition_guid), new_lba, &new_guid);
+ 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) {
+ FWU_LOG_MSG("%s: Unable to create partition '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[previous_active_index]);
+ return ret;
+ }
+
+ 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_rename(&new_guid, unicode_name);
+ if (ret != PSA_SUCCESS) {
+ FWU_LOG_MSG("%s: Unable to rename partition to '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[previous_active_index]);
+
+ /* Delete the newly created partition as there is code that relies on the naming */
+ ret = gpt_entry_remove(&new_guid);
+ if (ret != PSA_SUCCESS) {
+ FWU_LOG_MSG("%s: Catastrophic failure: unable to remove duplicate partition '%s'\r\n",
+ __func__, fwu_image[image_index].image_names[active_index]);
+ }
+ return ret;
+ }
+
+ FWU_LOG_MSG("%s: exit \n\r", __func__);
+ return PSA_SUCCESS;
+}
+#endif /* BL1_BUILD */
static psa_status_t maintain_bank_consistency(void)
{
@@ -88,6 +88,9 @@ SRC_URI:append:corstone1000 = " \
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"