From patchwork Thu Mar 26 13:28:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frazer Carsley X-Patchwork-Id: 84517 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id DE83D10A62D0 for ; Thu, 26 Mar 2026 13:29:20 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.47420.1774531755792115195 for ; Thu, 26 Mar 2026 06:29:16 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: body hash did not verify" header.i=@arm.com header.s=foss header.b=f0CSK+5k; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: frazer.carsley@arm.com) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 51E21175A; Thu, 26 Mar 2026 06:29:09 -0700 (PDT) Received: from e138143.arm.com (unknown [10.57.12.40]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DFE8D3F836; Thu, 26 Mar 2026 06:29:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1774531755; bh=uA3VqkzSq4rKaR0dn+fgN4MRQFeD/BkUasyYKkbBQFw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=f0CSK+5kT4Q/RY9kpcgXCwwv/mnwPoUQi7DHgYRbi2Mb9KZoFCdPAB92cV18GVVrf iM0ASmLE133oDea0kUqBTCSqQJuFblMP5p4Pq1NkNuL6KN6L2Zy2iSLFtggdKpIPHi a5XQcoum6Lm9HOdj8fbLcVu6yZvHwH4GghoorOcE= From: Frazer Carsley To: meta-arm@lists.yoctoproject.org Cc: Frazer Carsley Subject: [PATCH 1/2] arm-bsp/tf-m:cs1k: Add GPT library Date: Thu, 26 Mar 2026 13:28:39 +0000 Message-ID: <20260326132857.1590256-2-frazer.carsley@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260326132857.1590256-1-frazer.carsley@arm.com> References: <20260326132857.1590256-1-frazer.carsley@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 26 Mar 2026 13:29:20 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/6974 The patches added in this commit add a generic GPT library for use in flash devices. Corstone1000 could use these to manage partitions during a firmware update. The patches are all backports from trusted-firmware-m (TF-M) main branch and can be removed if Corstone1000 upgrades when the next version of TF-M is released. Signed-off-by: Frazer Carsley --- ...-lib-efi_guid-Added-EFI-GUID-library.patch | 217 +++ ...b-efi_soft_crc-Added-EFI-CRC-library.patch | 136 ++ ...emented-generic-GPT-parser-for-flash.patch | 1495 +++++++++++++++++ ...-how-GPT-partition-can-be-identified.patch | 308 ++++ ...dded-operations-to-modify-partitions.patch | 961 +++++++++++ ...ib-gpt-Added-operation-to-move-entry.patch | 374 +++++ ...ility-to-create-and-remove-partition.patch | 713 ++++++++ ...pt-Added-table-validation-operations.patch | 412 +++++ ...-gpt-Added-defragmentation-operation.patch | 280 +++ .../0026-lib-GPT-Fix-cppcheck-warnings.patch | 74 + ...uid-Remove-unecessary-include-folder.patch | 28 + ...lib-efi_guid-Correct-included-folder.patch | 28 + ...i_soft_crc-Correct-include-directory.patch | 25 + ...030-lib-gpt-Add-missing-link-library.patch | 27 + ...1-lib-gpt-Correct-variable-name-used.patch | 24 + ...32-lib-gpt-Correct-include-directory.patch | 27 + ...t-Move-contents-of-CMake-config-file.patch | 51 + .../trusted-firmware-m-corstone1000.inc | 17 + 18 files changed, 5197 insertions(+) create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0017-lib-efi_guid-Added-EFI-GUID-library.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0018-lib-efi_soft_crc-Added-EFI-CRC-library.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0019-lib-gpt-Implemented-generic-GPT-parser-for-flash.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0020-lib-gpt-Expanded-how-GPT-partition-can-be-identified.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0021-lib-gpt-Added-operations-to-modify-partitions.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0022-lib-gpt-Added-operation-to-move-entry.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0023-lib-gpt-Added-ability-to-create-and-remove-partition.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0024-lib-gpt-Added-table-validation-operations.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0025-lib-gpt-Added-defragmentation-operation.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0026-lib-GPT-Fix-cppcheck-warnings.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0027-lib-efi_guid-Remove-unecessary-include-folder.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0028-lib-efi_guid-Correct-included-folder.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0029-lib-efi_soft_crc-Correct-include-directory.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0030-lib-gpt-Add-missing-link-library.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0031-lib-gpt-Correct-variable-name-used.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0032-lib-gpt-Correct-include-directory.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0033-lib-gpt-Move-contents-of-CMake-config-file.patch diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0017-lib-efi_guid-Added-EFI-GUID-library.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0017-lib-efi_guid-Added-EFI-GUID-library.patch new file mode 100644 index 00000000..244bc20a --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0017-lib-efi_guid-Added-EFI-GUID-library.patch @@ -0,0 +1,217 @@ +From 5fc4f3857739a9fe93819cedc4a8108d33bf8241 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 ++ $ ++ 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 ++#include ++ ++#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 ++ ++#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; ++} diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0018-lib-efi_soft_crc-Added-EFI-CRC-library.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0018-lib-efi_soft_crc-Added-EFI-CRC-library.patch new file mode 100644 index 00000000..b8715e3b --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0018-lib-efi_soft_crc-Added-EFI-CRC-library.patch @@ -0,0 +1,136 @@ +From 4a47d926420bfec4a0e687b6ecc4cf52419e4f58 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 ++ $ ++) +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 ++#include ++ ++#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; ++} diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0019-lib-gpt-Implemented-generic-GPT-parser-for-flash.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0019-lib-gpt-Implemented-generic-GPT-parser-for-flash.patch new file mode 100644 index 00000000..c75f1568 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0019-lib-gpt-Implemented-generic-GPT-parser-for-flash.patch @@ -0,0 +1,1495 @@ +From ea6748c8778d21e331b22ddea808f9343a654b4d Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +Date: Mon, 29 Dec 2025 17:36:22 +0000 +Subject: [PATCH] lib: gpt: Implemented generic GPT parser for flash + +The library can be used to parse GPT partitions on a flash device by +giving the library endpoint the GUID that identifies the partition. A +platform must register with the library a pseudo-device driver that +defines a read operation, allowing the library to perform I/O. + +Change-Id: Id504ceb93856561063751570a773c4aae592b535 +Signed-off-by: Frazer Carsley +Upstream-Status: Backport [2b155c6163f866757971ddf438014b518c4edd05] +--- + CMakeLists.txt | 5 + + config/config_base.cmake | 2 + + lib/gpt/CMakeLists.txt | 40 ++ + lib/gpt/config.cmake | 8 + + lib/gpt/inc/gpt.h | 80 ++++ + lib/gpt/inc/gpt_flash.h | 73 ++++ + lib/gpt/src/gpt.c | 592 ++++++++++++++++++++++++++++++ + lib/gpt/unittests/CMakeLists.txt | 179 +++++++++ + lib/gpt/unittests/gpt/test_gpt.c | 383 +++++++++++++++++++ + lib/gpt/unittests/gpt/utcfg.cmake | 28 ++ + 10 files changed, 1390 insertions(+) + create mode 100644 lib/gpt/CMakeLists.txt + create mode 100644 lib/gpt/config.cmake + create mode 100644 lib/gpt/inc/gpt.h + create mode 100644 lib/gpt/inc/gpt_flash.h + create mode 100644 lib/gpt/src/gpt.c + create mode 100644 lib/gpt/unittests/CMakeLists.txt + create mode 100644 lib/gpt/unittests/gpt/test_gpt.c + create mode 100644 lib/gpt/unittests/gpt/utcfg.cmake + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b120de697..9e6e2ceda 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -42,6 +42,11 @@ set(CMAKE_CXX_COMPILER_FORCED true) + + project("Trusted Firmware M" VERSION ${TFM_VERSION} LANGUAGES C CXX ASM) + ++ ++if(PLATFORM_GPT_LIBRARY) ++ add_subdirectory(lib/gpt) ++endif() ++ + add_subdirectory(lib/backtrace) + add_subdirectory(lib/ext) + add_subdirectory(lib/efi_guid) +diff --git a/config/config_base.cmake b/config/config_base.cmake +index f4b2f3cd9..4cd14ab2b 100644 +--- a/config/config_base.cmake ++++ b/config/config_base.cmake +@@ -129,6 +129,8 @@ set(PLATFORM_DEFAULT_SYSTEM_RESET_HALT ON CACHE BOOL "Use default + set(PLATFORM_DEFAULT_IMAGE_SIGNING ON CACHE BOOL "Use default image signing implementation") + set(PLATFORM_DEFAULT_PROV_LINKER_SCRIPT ON CACHE BOOL "Use default provisioning linker script") + ++set(PLATFORM_GPT_LIBRARY OFF CACHE BOOL "Whether to build the GPT library or not") ++ + set(TFM_DUMMY_PROVISIONING ON CACHE BOOL "Provision with dummy values. NOT to be used in production") + + set(BL2_HEADER_SIZE 0x000 CACHE STRING "BL2 Header size") +diff --git a/lib/gpt/CMakeLists.txt b/lib/gpt/CMakeLists.txt +new file mode 100644 +index 000000000..2b5d6af8f +--- /dev/null ++++ b/lib/gpt/CMakeLists.txt +@@ -0,0 +1,40 @@ ++#------------------------------------------------------------------------------- ++# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors ++# ++# SPDX-License-Identifier: BSD-3-Clause ++# ++#------------------------------------------------------------------------------- ++ ++cmake_minimum_required(VERSION 3.21) ++ ++add_library(tfm_gpt STATIC) ++ ++include(./config.cmake) ++ ++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") ++endif() ++ ++target_sources(tfm_gpt ++ PRIVATE ++ src/gpt.c ++) ++ ++target_include_directories(tfm_gpt ++ PUBLIC ++ $ ++) ++ ++target_compile_definitions(tfm_gpt ++ PUBLIC ++ TFM_GPT_BLOCK_SIZE=${TFM_GPT_BLOCK_SIZE} ++ PRIVATE ++ LOG_LEVEL=${GPT_LOG_LEVEL} ++) ++ ++target_link_libraries(tfm_gpt ++ PUBLIC ++ tfm_log_headers ++ PRIVATE ++ tfm_efi_guid ++) +diff --git a/lib/gpt/config.cmake b/lib/gpt/config.cmake +new file mode 100644 +index 000000000..9575aa8a8 +--- /dev/null ++++ b/lib/gpt/config.cmake +@@ -0,0 +1,8 @@ ++#------------------------------------------------------------------------------- ++# 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") +diff --git a/lib/gpt/inc/gpt.h b/lib/gpt/inc/gpt.h +new file mode 100644 +index 000000000..d98abe980 +--- /dev/null ++++ b/lib/gpt/inc/gpt.h +@@ -0,0 +1,80 @@ ++/* ++ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ */ ++ ++#ifndef __TFM_GPT_H__ ++#define __TFM_GPT_H__ ++ ++#include ++#include ++ ++#include "psa/error.h" ++#include "gpt_flash.h" ++#include "efi_guid_structs.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** \brief Name length of a GPT partition entry. */ ++#define GPT_ENTRY_NAME_LENGTH 72 ++ ++/** ++ * \brief Information about a GPT partition presented to callers. ++ */ ++struct partition_entry_t { ++ uint64_t start; /**< Start Logical Block Address (LBA) of the partition. */ ++ uint64_t size; /**< Size of the partition in number of LBAs. */ ++ char name[GPT_ENTRY_NAME_LENGTH]; /**< Human readable name for the partition in unicode. */ ++ uint64_t attr; /**< Attributes associated with the partition. */ ++ struct efi_guid_t partition_guid; /**< Unique partition GUID. */ ++ struct efi_guid_t type_guid; /**< Partition type GUID. */ ++}; ++ ++/** ++ * \brief Reads the contents of a partition entry identified by a GUID. ++ * ++ * \param[in] guid GUID of the partition entry to read. ++ * \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 GUID. ++ */ ++__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 GPT header from the second block (LBA 1). ++ * ++ * \param[in] flash_driver Driver used to perform I/O. ++ * \param[in] max_partitions Maximum number of allowable partitions. ++ * ++ * \retval PSA_SUCCESS Success. ++ * \retval PSA_ERROR_STORAGE_FAILURE I/O error. ++ * \retval PSA_ERROR_INVALID_ARGUMENT \p max_partitions is less than four, or one of the I/O ++ * 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. ++ */ ++__attribute__((nonnull(1))) ++psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, ++ uint64_t max_partitions); ++ ++/** ++ * \brief Uninitialises the library. ++ * ++ * \retval PSA_SUCCESS Success. ++ * \retval PSA_ERROR_STORAGE_FAILURE I/O error. ++ */ ++psa_status_t gpt_uninit(void); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __TFM_GPT_H__ */ +diff --git a/lib/gpt/inc/gpt_flash.h b/lib/gpt/inc/gpt_flash.h +new file mode 100644 +index 000000000..2b43390c1 +--- /dev/null ++++ b/lib/gpt/inc/gpt_flash.h +@@ -0,0 +1,73 @@ ++/* ++ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ */ ++ ++#ifndef __TFM_GPT_FLASH_H__ ++#define __TFM_GPT_FLASH_H__ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** ++ * \brief Error codes returned by GPT flash driver operations. ++ */ ++typedef enum { ++ GPT_FLASH_SUCCESS = 0, /**< Operation completed successfully. */ ++ GPT_FLASH_GENERIC_ERROR = -1, /**< Unspecified error. */ ++ GPT_FLASH_NOT_INIT = -2, /**< Flash driver has not been initialised. */ ++ GPT_FLASH_UNAVAILABLE = -3, /**< Flash driver is unavailable. */ ++ GPT_FLASH_BAD_PARAM = -4, /**< Parameter supplied to the driver is invalid. */ ++} gpt_flash_err_t; ++ ++/** ++ * \brief Function used to initialise the driver. ++ * ++ * \retval GPT_FLASH_SUCCESS Success. ++ * \retval GPT_FLASH_GENERIC_ERROR Driver-specific failure. ++ */ ++typedef gpt_flash_err_t (*gpt_flash_init_t)(void); ++ ++/** ++ * \brief Function used to uninitialise the driver. ++ * ++ * \retval GPT_FLASH_SUCCESS Success. ++ * \retval GPT_FLASH_GENERIC_ERROR Driver-specific failure. ++ */ ++typedef gpt_flash_err_t (*gpt_flash_uninit_t)(void); ++ ++/** ++ * \brief Function that reads a logical block address. ++ * ++ * \param[in] lba Logical block address to read. ++ * \param[out] buf Buffer to populate. Must be at least the size of an LBA. ++ * ++ * \return Number of bytes read 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_read_t)(uint64_t lba, ++ void *buf); ++ ++/** ++ * \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. */ ++}; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __TFM_GPT_FLASH_H__ */ +diff --git a/lib/gpt/src/gpt.c b/lib/gpt/src/gpt.c +new file mode 100644 +index 000000000..99d735797 +--- /dev/null ++++ b/lib/gpt/src/gpt.c +@@ -0,0 +1,592 @@ ++/* ++ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "psa/error.h" ++#include "gpt.h" ++#include "gpt_flash.h" ++#include "tfm_log.h" ++#include "efi_guid_structs.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) ++ */ ++#ifndef TFM_GPT_BLOCK_SIZE ++#error "TFM_GPT_BLOCK_SIZE must be defined if using GPT library!" ++#endif ++ ++/* Where Master Boot Record (MBR) is on flash */ ++#define MBR_LBA 0ULL ++ ++/* Number of unused bytes at the start of the MBR */ ++#define MBR_UNUSED_BYTES 446 ++ ++/* Cylinder Head Sector (CHS) length for MBR entry */ ++#define MBR_CHS_ADDRESS_LEN 3 ++ ++/* Number of entries in an MBR */ ++#define MBR_NUM_ENTRIES 4 ++ ++/* MBR signature as defined by UEFI spec */ ++#define MBR_SIG 0xAA55 ++ ++/* Type of MBR partition that indicates GPT in use */ ++#define MBR_TYPE_GPT 0xEE ++ ++/* Default GUID Partition Table (GPT) header size */ ++#define GPT_HEADER_SIZE 92 ++ ++/* "EFI PART" (without null byte) */ ++#define GPT_SIG "EFI PART" ++#define GPT_SIG_LEN 8 ++ ++/* Default partition entry size */ ++#define GPT_ENTRY_SIZE 128 ++ ++/* Minimum number of partition entries according to spec */ ++#define GPT_MIN_PARTITIONS 4 ++ ++/* Logical Block Address (LBA) for primary GPT */ ++#define PRIMARY_GPT_LBA 1 ++ ++/* LBA for primary GPT partition array */ ++#define PRIMARY_GPT_ARRAY_LBA 2 ++ ++/* MBR partition entry - both for protective MBR entry and ++ * legacy MBR entry ++ */ ++struct mbr_entry_t { ++ /* Indicates if bootable */ ++ uint8_t status; ++ /* For legacy MBR, not used by UEFI firmware. For protective MBR, set to ++ * 0x000200 ++ */ ++ uint8_t first_sector[MBR_CHS_ADDRESS_LEN]; ++ /* Type of partition */ ++ uint8_t os_type; ++ /* For legacy MBR, not used by UEFI firmware. For protective MBR, last ++ * block on flash. ++ */ ++ uint8_t last_sector[MBR_CHS_ADDRESS_LEN]; ++ /* For legacy MBR, starting LBA of partition. For protective MBR, set to ++ * 0x00000001 ++ */ ++ uint32_t first_lba; ++ /* For legacy MBR, size of partition. For protective MBR, size of flash ++ * minus one ++ */ ++ uint32_t size; ++} __attribute__((packed)); ++ ++/* MBR. This structure is used both for protective MBR and legacy MBR. The boot ++ * code, flash signature and unknown sections are not read because they are ++ * unused and do not change. ++ */ ++struct mbr_t { ++ /* Boot code at offset 0 is unused in EFI */ ++ /* Unique MBR Disk signature at offset 440 is unused */ ++ /* The next 2 bytes are also unused */ ++ /* Array of four MBR partition records. For protective MBR, only the first ++ * is valid ++ */ ++ struct mbr_entry_t partitions[MBR_NUM_ENTRIES]; ++ /* 0xAA55 */ ++ uint16_t sig; ++} __attribute__((packed)); ++ ++/* A GPT partition entry. */ ++ struct gpt_entry_t { ++ struct efi_guid_t partition_type; /* Partition type, defining purpose */ ++ struct efi_guid_t unique_guid; /* Unique GUID that defines each partition */ ++ uint64_t start; /* Starting LBA for partition */ ++ uint64_t end; /* Ending LBA for partition */ ++ uint64_t attr; /* Attribute bits */ ++ char name[GPT_ENTRY_NAME_LENGTH]; /* Human readable name for partition */ ++} __attribute__((packed)); ++ ++/* The GPT header. */ ++struct gpt_header_t { ++ char signature[GPT_SIG_LEN]; /* "EFI PART" */ ++ uint32_t revision; /* Revision number */ ++ uint32_t size; /* Size of this header */ ++ uint32_t header_crc; /* CRC of this header */ ++ uint32_t reserved; /* Reserved */ ++ uint64_t current_lba; /* LBA of this header */ ++ uint64_t backup_lba; /* LBA of backup GPT header */ ++ uint64_t first_lba; /* First usable LBA */ ++ uint64_t last_lba; /* Last usable LBA */ ++ struct efi_guid_t flash_guid; /* Disk GUID */ ++ uint64_t array_lba; /* First LBA of array of partition entries */ ++ uint32_t num_partitions; /* Number of partition entries in array */ ++ uint32_t entry_size; /* Size of a single partition entry */ ++ uint32_t array_crc; /* CRC of partitions array */ ++} __attribute__((packed)); ++ ++/* A GUID partition table in memory. The array is not stored in memory ++ * due to its size ++ */ ++struct gpt_t { ++ struct gpt_header_t header; /* GPT header */ ++ uint32_t num_used_partitions; /* Number of in-use partitions */ ++}; ++ ++/* A function for comparing some gpt entry's attribute with something known. ++ * Used to find entries of a certain kind, such as with a particular GUID, ++ * name or type. ++ */ ++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 flash driver, used to perform I/O */ ++static struct gpt_flash_driver_t *plat_flash_driver = NULL; ++ ++/* Maximum partitions on platform */ ++static uint32_t plat_max_partitions = 0; ++ ++/* The primary GPT (also used if legacy MBR, but GPT header and partition ++ * entries are zero'd) ++ */ ++static struct gpt_t primary_gpt = {0}; ++ ++/* Buffer to use for LBA I/O */ ++static uint8_t lba_buf[TFM_GPT_BLOCK_SIZE] = {0}; ++ ++/* LBA that is cached in the buffer. Zero is valid only for protective MBR, all ++ * other GPT operations must have LBA of one or greater ++ */ ++static uint64_t cached_lba = 0; ++ ++/* Helper function prototypes */ ++__attribute__((unused)) ++static void print_guid(struct efi_guid_t guid); ++__attribute__((unused)) ++static void dump_table(const struct gpt_t *table, bool header_only); ++__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 gpt_entry_per_lba_count(void); ++static psa_status_t count_used_partitions(const struct gpt_t *table, ++ uint32_t *num_used); ++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, ++ struct gpt_entry_t *entry); ++static psa_status_t read_table_from_flash(struct gpt_t *table, bool is_primary); ++static psa_status_t find_gpt_entry(const struct gpt_t *table, ++ gpt_entry_cmp_t compare, ++ const void *attr, ++ const uint32_t repeat_index, ++ struct gpt_entry_t *entry, ++ 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); ++ ++/* PUBLIC API FUNCTIONS */ ++ ++psa_status_t gpt_entry_read(const struct efi_guid_t *guid, ++ 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_guid, guid, 0, &cached_entry, NULL); ++ if (ret != PSA_SUCCESS) { ++ 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; ++ ++ return PSA_SUCCESS; ++} ++ ++/* Initialises GPT from first block. */ ++psa_status_t gpt_init(struct gpt_flash_driver_t *flash_driver, uint64_t max_partitions) ++{ ++ cached_lba = 0; ++ 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) { ++ ERROR("I/O functions must be defined\n"); ++ return PSA_ERROR_INVALID_ARGUMENT; ++ } ++ ++ /* Retain information needed to perform I/O. */ ++ if (plat_flash_driver == NULL) { ++ plat_flash_driver = flash_driver; ++ } ++ if (plat_max_partitions == 0) { ++ plat_max_partitions = max_partitions; ++ } ++ if (plat_flash_driver->init != NULL) { ++ if (plat_flash_driver->init() != 0) { ++ ERROR("Unable to initialise flash driver\n"); ++ return PSA_ERROR_STORAGE_FAILURE; ++ } ++ } ++ ++ struct mbr_t mbr; ++ psa_status_t ret = mbr_load(&mbr); ++ if (ret != PSA_SUCCESS) { ++ goto fail_load; ++ } ++ ++ /* If the first record has type 0xEE (GPT protective), then the flash uses ++ * GPT. Else, treat it as legacy MBR ++ */ ++ 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"); ++ ret = PSA_ERROR_NOT_SUPPORTED; ++ } ++ ++ if (ret != PSA_SUCCESS) { ++ 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) { ++ goto fail_load; ++ } ++ ++ /* Read the backup GPT and cache necessary values */ ++ backup_gpt_lba = primary_gpt.header.backup_lba; ++ if (backup_gpt_lba != 0) { ++ struct gpt_t backup_gpt; ++ ret = read_table_from_flash(&backup_gpt, false); ++ if (ret != PSA_SUCCESS) { ++ goto fail_load; ++ } ++ } else { ++ WARN("Backup GPT location is unknown!\n"); ++ } ++ ++ return PSA_SUCCESS; ++ ++fail_load: ++ /* Reset so that the user can try with something else if desired */ ++ plat_flash_driver = NULL; ++ plat_max_partitions = 0; ++ backup_gpt_lba = 0; ++ cached_lba = 0; ++ ++ return ret; ++} ++ ++psa_status_t gpt_uninit(void) ++{ ++ psa_status_t ret = PSA_SUCCESS; ++ ++ if (plat_flash_driver) { ++ /* Uninitialise driver if function provided */ ++ if (plat_flash_driver->uninit != NULL) { ++ if (plat_flash_driver->uninit() != 0) { ++ ERROR("Unable to uninitialise flash driver\n"); ++ ret = PSA_ERROR_STORAGE_FAILURE; ++ } ++ } ++ } ++ ++ plat_flash_driver = NULL; ++ plat_max_partitions = 0; ++ backup_gpt_lba = 0; ++ cached_lba = 0; ++ ++ return ret; ++} ++ ++/* 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; ++} ++ ++/* Compare the entry with the given guid */ ++static bool gpt_entry_cmp_guid(const struct gpt_entry_t *entry, const void *guid) ++{ ++ const struct efi_guid_t *cmp_guid = (const struct efi_guid_t *)guid; ++ const struct efi_guid_t entry_guid = entry->unique_guid; ++ ++ return efi_guid_cmp(&entry_guid, cmp_guid) == 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, ++ const void *cmp_attr, ++ const uint32_t repeat_index, ++ struct gpt_entry_t *entry, ++ uint32_t *array_index) ++{ ++ if (table->num_used_partitions == 0) { ++ return PSA_ERROR_DOES_NOT_EXIST; ++ } ++ ++ uint32_t num_found = 0; ++ bool io_failure = false; ++ for (uint32_t i = 0; i < table->num_used_partitions; ++i) { ++ const psa_status_t ret = read_entry_from_flash(table, i, entry); ++ if (ret != PSA_SUCCESS) { ++ /* This might not have been the partition being sought after anyway, ++ * so may as well try the rest ++ */ ++ io_failure = true; ++ continue; ++ } ++ ++ if (compare(entry, cmp_attr) && num_found++ == repeat_index) { ++ if (array_index != NULL) { ++ *array_index = i; ++ } ++ return PSA_SUCCESS; ++ } ++ } ++ ++ return io_failure ? PSA_ERROR_STORAGE_FAILURE : PSA_ERROR_DOES_NOT_EXIST; ++} ++ ++/* Load MBR from flash */ ++static psa_status_t mbr_load(struct mbr_t *mbr) ++{ ++ /* Read the beginning of the first block of flash, which will contain either ++ * a legacy MBR or a protective MBR (in the case of GPT). The first ++ * MBR_UNUSED_BYTES are unused and so do not need to be considered. ++ */ ++ ssize_t ret = plat_flash_driver->read(MBR_LBA, lba_buf); ++ if (ret != TFM_GPT_BLOCK_SIZE) { ++ ERROR("Unable to read from flash at block 0x%08x%08x\n", ++ (uint32_t)(MBR_LBA >> 32), ++ (uint32_t)MBR_LBA); ++ return PSA_ERROR_STORAGE_FAILURE; ++ } ++ memcpy(mbr, lba_buf + MBR_UNUSED_BYTES, sizeof(*mbr)); ++ ++ /* Check MBR boot signature */ ++ if (mbr->sig != MBR_SIG) { ++ ERROR("MBR signature incorrect\n"); ++ return PSA_ERROR_INVALID_ARGUMENT; ++ } ++ ++ return PSA_SUCCESS; ++} ++ ++/* Reads an LBA from the flash device and caches it. If the requested LBA is ++ * already cached, this is a no-op ++ */ ++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 (ret != TFM_GPT_BLOCK_SIZE) { ++ ERROR("Unable to read from flash at block 0x%08x%08x\n", ++ (uint32_t)(required_lba >> 32), ++ (uint32_t)required_lba); ++ return PSA_ERROR_STORAGE_FAILURE; ++ } ++ cached_lba = required_lba; ++ } ++ ++ return PSA_SUCCESS; ++} ++ ++/* Returns the LBA that a particular partition entry is in based on its position ++ * in the array ++ */ ++static uint64_t inline partition_entry_lba(const struct gpt_t *table, ++ uint32_t array_index) ++{ ++ return table->header.array_lba + (array_index / gpt_entry_per_lba_count()); ++} ++ ++/* Returns the number of partition entries used in the array, assuming the ++ * array is not sparse ++ */ ++static psa_status_t count_used_partitions(const struct gpt_t *table, ++ uint32_t *num_used) ++{ ++ for (uint32_t i = 0; i < table->header.num_partitions; ++i) { ++ struct gpt_entry_t entry = {0}; ++ const psa_status_t ret = read_entry_from_flash(table, i, &entry); ++ if (ret != PSA_SUCCESS) { ++ return ret; ++ } ++ ++ const struct efi_guid_t null_guid = NULL_GUID; ++ const struct efi_guid_t entry_guid = entry.partition_type; ++ if (efi_guid_cmp(&null_guid, &entry_guid) == 0) { ++ *num_used = i; ++ return PSA_SUCCESS; ++ } ++ } ++ ++ *num_used = table->header.num_partitions; ++ return PSA_SUCCESS; ++} ++ ++/* Reads a GPT entry from the given table on flash */ ++static psa_status_t read_entry_from_flash(const struct gpt_t *table, ++ uint32_t array_index, ++ struct gpt_entry_t *entry) ++{ ++ uint64_t required_lba = partition_entry_lba(table, array_index); ++ const psa_status_t ret = read_from_flash(required_lba); ++ if (ret != PSA_SUCCESS) { ++ return ret; ++ } ++ ++ memcpy( ++ entry, ++ lba_buf + ((array_index % gpt_entry_per_lba_count()) * table->header.entry_size), ++ GPT_ENTRY_SIZE); ++ ++ return PSA_SUCCESS; ++} ++ ++/* Reads a GPT table from flash */ ++static psa_status_t read_table_from_flash(struct gpt_t *table, bool is_primary) ++{ ++ if (!is_primary && backup_gpt_lba == 0) { ++ ERROR("Backup GPT location unknown!\n"); ++ return PSA_ERROR_STORAGE_FAILURE; ++ } ++ ++ const psa_status_t ret = read_from_flash(is_primary ? PRIMARY_GPT_LBA : backup_gpt_lba); ++ if (ret != PSA_SUCCESS) { ++ return ret; ++ } ++ ++ memcpy(&(table->header), lba_buf, GPT_HEADER_SIZE); ++ ++ return PSA_SUCCESS; ++} ++ ++/* Converts unicode string to valid ascii */ ++static psa_status_t unicode_to_ascii(const char *unicode, char *ascii) ++{ ++ /* Check whether the unicode string is valid */ ++ if (unicode[0] == '\0') { ++ return PSA_ERROR_INVALID_ARGUMENT; ++ } ++ for (int i = 1; i < GPT_ENTRY_NAME_LENGTH; i += 2) { ++ if (unicode[i] != '\0') { ++ return PSA_ERROR_INVALID_ARGUMENT; ++ } ++ } ++ ++ /* Convert the unicode string to ascii string */ ++ for (int i = 0; i < GPT_ENTRY_NAME_LENGTH; i += 2) { ++ ascii[i >> 1] = unicode[i]; ++ if (unicode[i] == '\0') { ++ break; ++ } ++ } ++ ++ return PSA_SUCCESS; ++} ++ ++/* Prints guid in human readable format. Useful for debugging but should never ++ * be used in production, hence marked as unused ++ */ ++static void print_guid(struct efi_guid_t guid) ++{ ++ INFO("%04x%04x-%04x-%04x-%04x-%04x%04x%04x\n", ++ ((uint16_t *)&guid)[0], ++ ((uint16_t *)&guid)[1], ++ ((uint16_t *)&guid)[2], ++ ((uint16_t *)&guid)[3], ++ ((uint16_t *)&guid)[4], ++ ((uint16_t *)&guid)[5], ++ ((uint16_t *)&guid)[6], ++ ((uint16_t *)&guid)[7]); ++} ++ ++/* Dumps header and optionally meta-data about array. Useful for debugging, ++ * but should never be used in production, hence marked as unused. ++ */ ++static void dump_table(const struct gpt_t *table, bool header_only) ++{ ++ /* Print the header first */ ++ const struct gpt_header_t *header = &(table->header); ++ INFO("----------\n"); ++ INFO("Signature: %8s\n", header->signature); ++ INFO("Revision: 0x%08x\n", header->revision); ++ INFO("HeaderSize: 0x%08x\n", header->size); ++ INFO("HeaderCRC32: 0x%08x\n", header->header_crc); ++ INFO("Reserved: 0x%08x\n", header->reserved); ++ INFO("MyLBA: 0x%08x%08x\n", ++ (uint32_t)(header->current_lba >> 32), ++ (uint32_t)(header->current_lba)); ++ INFO("AlternateLBA: 0x%08x%08x\n", ++ (uint32_t)(header->backup_lba >> 32), ++ (uint32_t)(header->backup_lba)); ++ INFO("FirstUsableLBA: 0x%08x%08x\n", ++ (uint32_t)(header->first_lba >> 32), ++ (uint32_t)(header->first_lba)); ++ INFO("LastUsableLBA: 0x%08x%08x\n", ++ (uint32_t)(header->last_lba >> 32), ++ (uint32_t)(header->last_lba)); ++ INFO("DiskGUID: "); ++ print_guid(header->flash_guid); ++ INFO("ParitionEntryLBA: 0x%08x%08x\n", ++ (uint32_t)(header->array_lba >> 32), ++ (uint32_t)(header->array_lba)); ++ INFO("NumberOfPartitionEntries: 0x%08x\n", header->num_partitions); ++ INFO("SizeOfPartitionEntry: 0x%08x\n", header->entry_size); ++ INFO("PartitionEntryArrayCRC32: 0x%08x\n", header->array_crc); ++ INFO("----------\n"); ++ ++ if (!header_only) { ++ /* Now print meta-data for each entry, including those not in use */ ++ for (uint32_t i = 0; i < table->num_used_partitions; ++i) { ++ struct gpt_entry_t entry; ++ psa_status_t ret = read_entry_from_flash(&primary_gpt, i, &entry); ++ if (ret != PSA_SUCCESS) { ++ continue; ++ } ++ ++ INFO("Entry number: %u\n", i); ++ INFO("\tPartitionTypeGUID: "); ++ print_guid(entry.partition_type); ++ INFO("\tUniquePartitionGUID: "); ++ print_guid(entry.unique_guid); ++ INFO("\tStartingLBA: 0x%08x%08x\n", ++ (uint32_t)(entry.start >> 32), ++ (uint32_t)(entry.start)); ++ INFO("\tEndingLBA: 0x%08x%08x\n", ++ (uint32_t)(entry.end >> 32), ++ (uint32_t)(entry.end)); ++ INFO("\tAttributes: 0x%08x%08x\n", ++ (uint32_t)(entry.attr >> 32), ++ (uint32_t)(entry.attr)); ++ char name[GPT_ENTRY_NAME_LENGTH >> 1]; ++ if (unicode_to_ascii(entry.name, name) != PSA_SUCCESS) { ++ INFO("\tPartitionName: [Not valid ascii]\n"); ++ } else { ++ INFO("\tPartitionName: %s\n", name); ++ } ++ } ++ } ++} +diff --git a/lib/gpt/unittests/CMakeLists.txt b/lib/gpt/unittests/CMakeLists.txt +new file mode 100644 +index 000000000..61c7078e5 +--- /dev/null ++++ b/lib/gpt/unittests/CMakeLists.txt +@@ -0,0 +1,179 @@ ++#------------------------------------------------------------------------------- ++# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors ++# ++# SPDX-License-Identifier: BSD-3-Clause ++# ++#------------------------------------------------------------------------------- ++cmake_minimum_required(VERSION 3.21) ++ ++if (NOT DEFINED TFM_UNITTESTS_PATHS) ++ message(FATAL_ERROR "Please provide absolute paths to the unittests using -DTFM_UNITTESTS_PATHS=") ++endif() ++ ++if (NOT DEFINED TFM_ROOT_DIR) ++ message(FATAL_ERROR "Please provide absolute paths to the TF-M root directory using -DTFM_ROOT_DIR=") ++endif() ++ ++list(APPEND CMAKE_MODULE_PATH ${TFM_ROOT_DIR}/cmake) ++ ++project( ++ "tfm_gpt_unit_tests" ++ VERSION 1.0.0 ++ LANGUAGES C ++) ++ ++enable_testing() ++include(CTest) ++ ++find_package(Ruby) ++find_program(LCOV lcov REQUIRED) ++find_program(GENHTML genhtml REQUIRED) ++ ++set(UNITY_SRC_DIR ${TFM_ROOT_DIR}/platform/ext/target/arm/rse/common/unittests/framework/unity) ++set(CMOCK_SRC_DIR ${TFM_ROOT_DIR}/platform/ext/target/arm/rse/common/unittests/framework/cmock) ++ ++add_subdirectory(${UNITY_SRC_DIR} ${UNITY_SRC_DIR}) ++add_subdirectory(${CMOCK_SRC_DIR} ${CMOCK_SRC_DIR}) ++ ++function(generate_test UNIT_NAME UNIT_PATH) ++ include(${UNIT_PATH}/utcfg.cmake) ++ ++ # Generate runner for the test ++ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/unittests/${UNIT_NAME}) ++ add_custom_command( ++ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/unittests/${UNIT_NAME}/test_runner.c ++ COMMAND ${Ruby_EXECUTABLE} ++ ${UNITY_PATH}/auto/generate_test_runner.rb ++ ${UNITY_SRC_DIR}/cfg.yml ++ ${UNIT_TEST_SUITE} ++ ${CMAKE_CURRENT_BINARY_DIR}/unittests/${UNIT_NAME}/test_runner.c ++ COMMENT "Generating test runner for ${UNIT_NAME}" ++ ) ++ ++ # test_ is the runner for ++ add_executable(test_${UNIT_NAME} ${UNIT_UNDER_TEST} ++ ${UNIT_TEST_SUITE} ++ ${CMAKE_CURRENT_BINARY_DIR}/unittests/${UNIT_NAME}/test_runner.c ++ ${UNIT_TEST_DEPS} ++ ) ++ ++ # Enable debug syms & coverage support while compiling ++ target_compile_options(test_${UNIT_NAME} ++ PUBLIC ++ -g3 ++ -fprofile-arcs ++ -ftest-coverage ++ ) ++ ++ target_link_libraries(test_${UNIT_NAME} ++ PRIVATE cmock ++ PRIVATE unity ++ PRIVATE gcov ++ ${UNIT_TEST_LINK_LIBS} ++ ) ++ ++ target_include_directories(test_${UNIT_NAME} ++ PUBLIC ++ ${UNIT_TEST_INCLUDE_DIRS} ++ ) ++ ++ # UNIT_TEST must always be defined, each unit test may define more ++ target_compile_definitions(test_${UNIT_NAME} ++ PUBLIC ++ UNIT_TEST ++ ${UNIT_TEST_COMPILE_DEFS} ++ ) ++ ++ # For every in, we build test_ ++ add_test( ++ NAME ${UNIT_NAME} ++ COMMAND test_${UNIT_NAME} ++ ) ++ ++ # Generate mocks ++ foreach(FILEPATH_TO_MOCK ${MOCK_HEADERS}) ++ get_filename_component(FILENAME_TO_MOCK ${FILEPATH_TO_MOCK} NAME_WE) ++ set(MOCK_TARGET ${UNIT_NAME}_mock_${FILENAME_TO_MOCK}) ++ ++ # Invoke CMock to generate mock_ ++ add_custom_command( ++ OUTPUT ++ ${CMAKE_BINARY_DIR}/unittests/${UNIT_NAME}/mock_${FILENAME_TO_MOCK}.c ++ COMMAND ${CMAKE_COMMAND} -E env ++ UNITY_DIR=${UNITY_PATH} ++ ${Ruby_EXECUTABLE} ++ ${CMOCK_PATH}/lib/cmock.rb ++ -o${CMOCK_SRC_DIR}/cfg.yml ++ ${FILEPATH_TO_MOCK} ++ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests/${UNIT_NAME} ++ DEPENDS ${FILEPATH_TO_MOCK} ++ COMMENT "Mocking ${FILEPATH_TO_MOCK} for ${UNIT_NAME}" ++ ) ++ ++ target_sources( ++ test_${UNIT_NAME} PRIVATE ++ ${CMAKE_BINARY_DIR}/unittests/${UNIT_NAME}/mock_${FILENAME_TO_MOCK}.c ++ ) ++ ++ target_include_directories( ++ test_${UNIT_NAME} PRIVATE ++ ${CMAKE_BINARY_DIR}/unittests/${UNIT_NAME} ++ ) ++ endforeach() ++endfunction() ++ ++# unittests target ++# Depends on ++# - All tests detected ++# Performs ++# - Execute all tests ++# - Generate and filter coverage info ++# - Convert report into browsable html ++add_custom_target(unittests) ++ ++add_custom_command( ++ TARGET unittests ++ POST_BUILD ++ COMMAND ${CMAKE_CTEST_COMMAND} ++ ARGS ++ --output-on-failure ++ COMMAND ${LCOV} ++ ARGS ++ --capture ++ --directory ${CMAKE_CURRENT_BINARY_DIR} ++ --output-file raw_test_coverage.info ++ > lcov.log 2>&1 ++ COMMAND ${LCOV} ++ ARGS ++ --remove raw_test_coverage.info ++ -o test_coverage.info ++ '/usr/*' ++ '${CMAKE_BINARY_DIR}/*' ++ '*tests*' ++ >> lcov.log 2>&1 ++ COMMAND ${GENHTML} ++ ARGS ++ test_coverage.info ++ --output-directory ${CMAKE_BINARY_DIR}/coverage_report ++ >> lcov.log 2>&1 ++ COMMAND ${CMAKE_COMMAND} ++ ARGS ++ -E echo "Coverage Report: file://${CMAKE_BINARY_DIR}/coverage_report/index.html" ++) ++ ++foreach(TFM_UNITTESTS_PATH ${TFM_UNITTESTS_PATHS}) ++ if (NOT EXISTS ${TFM_UNITTESTS_PATH}) ++ message(FATAL_ERROR "Path ${TFM_UNITTESTS_PATH} does not exist.") ++ endif() ++ ++ file(GLOB_RECURSE UNIT_PATHS LIST_DIRECTORIES TRUE "${TFM_UNITTESTS_PATH}/*") ++ foreach(UNIT_PATH ${UNIT_PATHS}) ++ # Only for directories that contain a utcfg.cmake ++ if(IS_DIRECTORY ${UNIT_PATH} AND EXISTS ${UNIT_PATH}/utcfg.cmake) ++ get_filename_component(UNIT_NAME ${UNIT_PATH} NAME) ++ message(STATUS "Found ${UNIT_NAME}") ++ generate_test(${UNIT_NAME} ${UNIT_PATH}) ++ add_dependencies(unittests test_${UNIT_NAME}) ++ endif() ++ endforeach() ++endforeach() +\ No newline at end of file +diff --git a/lib/gpt/unittests/gpt/test_gpt.c b/lib/gpt/unittests/gpt/test_gpt.c +new file mode 100644 +index 000000000..325887fae +--- /dev/null ++++ b/lib/gpt/unittests/gpt/test_gpt.c +@@ -0,0 +1,383 @@ ++/* ++ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ */ ++ ++#include ++#include ++ ++#include "unity.h" ++ ++#include "mock_tfm_log.h" ++#include "mock_tfm_vprintf.h" ++ ++#include "efi_guid_structs.h" ++#include "gpt_flash.h" ++#include "gpt.h" ++#include "psa/error.h" ++ ++/* Basic mocked disk layout and number of partitions */ ++#define TEST_BLOCK_SIZE 512 ++#define TEST_DISK_NUM_BLOCKS 128 ++#define TEST_MAX_PARTITIONS 4 ++#define TEST_DEFAULT_NUM_PARTITIONS TEST_MAX_PARTITIONS - 1 ++ ++/* Maximum number of mocked reads per test */ ++#define TEST_MOCK_BUFFER_SIZE 512 ++ ++/* Master Boot Record (MBR) definitions for test */ ++#define TEST_MBR_SIG 0xAA55 ++#define TEST_MBR_TYPE_GPT 0xEE ++#define TEST_MBR_CHS_ADDRESS_LEN 3 ++#define TEST_MBR_NUM_PARTITIONS 4 ++#define TEST_MBR_UNUSED_BYTES 446 ++ ++/* GUID Partition Table (GPT) header values */ ++#define TEST_GPT_SIG_LEN 8 ++#define TEST_GPT_SIG_INITIALISER {'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T'} ++#define TEST_GPT_REVISION 0x00010000 ++#define TEST_GPT_HEADER_SIZE 92 ++#define TEST_GPT_CRC32 42 ++#define TEST_GPT_PRIMARY_LBA 1 ++#define TEST_GPT_BACKUP_LBA (TEST_DISK_NUM_BLOCKS - 1) ++#define TEST_GPT_ARRAY_LBA (TEST_GPT_PRIMARY_LBA + 1) ++#define TEST_GPT_BACKUP_ARRAY_LBA (TEST_GPT_BACKUP_LBA - 1) ++#define TEST_GPT_FIRST_USABLE_LBA (TEST_GPT_ARRAY_LBA + 2) ++#define TEST_GPT_LAST_USABLE_LBA (TEST_GPT_BACKUP_LBA - 2) ++#define TEST_GPT_DISK_GUID MAKE_EFI_GUID(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) ++#define TEST_GPT_ENTRY_SIZE 128 ++ ++/* Test data. These are defined to be not fragmented */ ++#define TEST_GPT_FIRST_PARTITION_START TEST_GPT_FIRST_USABLE_LBA ++#define TEST_GPT_FIRST_PARTITION_END (TEST_GPT_FIRST_PARTITION_START + 3) ++#define TEST_GPT_SECOND_PARTITION_START (TEST_GPT_FIRST_PARTITION_END + 1) ++#define TEST_GPT_SECOND_PARTITION_END (TEST_GPT_SECOND_PARTITION_START + 50) ++#define TEST_GPT_THIRD_PARTITION_START (TEST_GPT_SECOND_PARTITION_END + 1) ++#define TEST_GPT_THIRD_PARTITION_END (TEST_GPT_THIRD_PARTITION_START + 1) ++ ++/* Populates a backup header from a primary header and calculates the new CRC32 */ ++#define MAKE_BACKUP_HEADER(backup, primary) \ ++ do { \ ++ memcpy(&backup, &primary, TEST_GPT_HEADER_SIZE); \ ++ backup.header_crc = TEST_GPT_CRC32; \ ++ backup.current_lba = primary.backup_lba; \ ++ backup.backup_lba = primary.current_lba; \ ++ backup.array_lba = TEST_GPT_BACKUP_ARRAY_LBA; \ ++ } while (0) ++ ++/* MBR partition entry */ ++struct mbr_entry_t { ++ /* Indicates if bootable */ ++ uint8_t status; ++ /* For legacy MBR, not used by UEFI firmware. For protective MBR, set to ++ * 0x000200 ++ */ ++ uint8_t first_sector[TEST_MBR_CHS_ADDRESS_LEN]; ++ /* Type of partition */ ++ uint8_t os_type; ++ /* For legacy MBR, not used by UEFI firmware. For protective MBR, last ++ * block on disk. ++ */ ++ uint8_t last_sector[TEST_MBR_CHS_ADDRESS_LEN]; ++ /* For legacy MBR, starting LBA of partition. For protective MBR, set to ++ * 0x00000001 ++ */ ++ uint32_t first_lba; ++ /* For legacy MBR, size of partition. For protective MBR, size of disk ++ * minus one ++ */ ++ uint32_t size; ++} __attribute__((packed)); ++ ++/* Master Boot Record. */ ++struct mbr_t { ++ /* Unused bytes */ ++ uint8_t unused[TEST_MBR_UNUSED_BYTES]; ++ /* Array of four MBR partition records. For protective MBR, only the first ++ * is valid ++ */ ++ struct mbr_entry_t partitions[TEST_MBR_NUM_PARTITIONS]; ++ /* 0xAA55 */ ++ uint16_t sig; ++} __attribute__((packed)); ++ ++/* A gpt partition entry */ ++struct gpt_entry_t { ++ struct efi_guid_t type; /* Partition type */ ++ struct efi_guid_t guid; /* Unique GUID */ ++ uint64_t start; /* Starting LBA for partition */ ++ uint64_t end; /* Ending LBA for partition */ ++ uint64_t attr; /* Attribute bits */ ++ char name[GPT_ENTRY_NAME_LENGTH]; /* Human readable name for partition */ ++} __attribute__((packed)); ++ ++/* The gpt header */ ++struct gpt_header_t { ++ char signature[TEST_GPT_SIG_LEN]; /* "EFI PART" */ ++ uint32_t revision; /* Revision number. */ ++ uint32_t size; /* Size of this header */ ++ uint32_t header_crc; /* CRC of this header */ ++ uint32_t reserved; /* Reserved */ ++ uint64_t current_lba; /* LBA of this header */ ++ uint64_t backup_lba; /* LBA of backup GPT header */ ++ uint64_t first_lba; /* First usable LBA */ ++ uint64_t last_lba; /* Last usable LBA */ ++ struct efi_guid_t disk_guid; /* Disk GUID */ ++ uint64_t array_lba; /* First LBA of array of partition entries */ ++ uint32_t num_partitions; /* Number of partition entries in array */ ++ uint32_t entry_size; /* Size of a single partition entry */ ++ uint32_t array_crc; /* CRC of partition entry array */ ++} __attribute__((packed)); ++ ++static void register_mocked_read(void *buf, size_t num_bytes); ++static ssize_t test_driver_read(uint64_t lba, void *buf); ++ ++/* LBA driver used in test module */ ++static struct gpt_flash_driver_t mock_driver = { ++ .init = NULL, ++ .uninit = NULL, ++ .read = test_driver_read, ++}; ++ ++/* Valid MBR. Only signature is required to be valid */ ++static struct mbr_t default_mbr = { ++ .unused = {0}, ++ .sig = TEST_MBR_SIG, ++}; ++static struct mbr_t test_mbr; ++ ++/* Default GPT header. CRC values need to be populated to be valid. */ ++static struct gpt_header_t default_header = { ++ .signature = TEST_GPT_SIG_INITIALISER, ++ .revision = TEST_GPT_REVISION, ++ .size = TEST_GPT_HEADER_SIZE, ++ .header_crc = TEST_GPT_CRC32, ++ .reserved = 0, ++ .current_lba = TEST_GPT_PRIMARY_LBA, ++ .backup_lba = TEST_GPT_BACKUP_LBA, ++ .first_lba = TEST_GPT_FIRST_USABLE_LBA, ++ .last_lba = TEST_GPT_LAST_USABLE_LBA, ++ .disk_guid = TEST_GPT_DISK_GUID, ++ .array_lba = TEST_GPT_ARRAY_LBA, ++ .num_partitions = TEST_MAX_PARTITIONS, ++ .entry_size = TEST_GPT_ENTRY_SIZE, ++ .array_crc = TEST_GPT_CRC32 ++}; ++static struct gpt_header_t test_header; ++ ++/* Default entry array. This is valid, though fragmented. */ ++static struct gpt_entry_t default_partition_array[TEST_DEFAULT_NUM_PARTITIONS] = { ++ { ++ .type = MAKE_EFI_GUID(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), ++ .guid = MAKE_EFI_GUID(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), ++ .start = TEST_GPT_FIRST_PARTITION_START, ++ .end = TEST_GPT_FIRST_PARTITION_END, ++ .attr = 0, ++ .name = "First partition" ++ }, ++ { ++ .type = MAKE_EFI_GUID(2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), ++ .guid = MAKE_EFI_GUID(2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), ++ .start = TEST_GPT_SECOND_PARTITION_START, ++ .end = TEST_GPT_SECOND_PARTITION_END, ++ .attr = 0, ++ .name = "Second partition" ++ }, ++ { ++ .type = MAKE_EFI_GUID(3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11), ++ .guid = MAKE_EFI_GUID(3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11), ++ .start = TEST_GPT_THIRD_PARTITION_START, ++ .end = TEST_GPT_THIRD_PARTITION_END, ++ .attr = 0, ++ .name = "Third partition" ++ } ++}; ++static struct gpt_entry_t test_partition_array[TEST_MAX_PARTITIONS]; ++ ++/* Set to determine what is "read" by the flash driver. Allows for the mocking ++ * of multiple read calls ++ */ ++static unsigned int num_mocked_reads = 0; ++static unsigned int registered_mocked_reads = 0; ++static uint8_t mock_read_buffer[TEST_MOCK_BUFFER_SIZE][TEST_BLOCK_SIZE] = {0}; ++ ++/* Turn ascii string to unicode */ ++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'; ++ } ++} ++ ++/* Tell the test what to return from the next read call. This is very much ++ * whitebox testing ++ */ ++static void register_mocked_read(void *data, size_t num_bytes) ++{ ++ memcpy(mock_read_buffer[registered_mocked_reads++], data, num_bytes); ++} ++ ++/* Driver function that always succeeds in reading the data it has been given */ ++static ssize_t test_driver_read(uint64_t lba, void *buf) ++{ ++ memcpy(buf, mock_read_buffer[num_mocked_reads++], TEST_BLOCK_SIZE); ++ return TEST_BLOCK_SIZE; ++} ++ ++/* Creates backup table from test table and registers a read for it */ ++static void setup_backup_gpt(void) ++{ ++ struct gpt_header_t backup_header; ++ MAKE_BACKUP_HEADER(backup_header, test_header); ++ ++ register_mocked_read(&backup_header, sizeof(backup_header)); ++} ++ ++/* Uses the test MBR and GPT header to initialise for tests */ ++static psa_status_t setup_test_gpt(void) ++{ ++ /* 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 (if the ++ * number in the header is non-zero) ++ */ ++ if (test_header.num_partitions != 0) { ++ register_mocked_read(&test_partition_array, sizeof(test_partition_array)); ++ } ++ ++ /* Expect fourth the backup to be read */ ++ setup_backup_gpt(); ++ ++ return gpt_init(&mock_driver, TEST_MAX_PARTITIONS); ++} ++ ++/* Ensures a valid GPT populated with the default entries is initialised */ ++static void setup_valid_gpt(void) ++{ ++ TEST_ASSERT_EQUAL(PSA_SUCCESS, setup_test_gpt()); ++} ++ ++/* Ensures a valid but empty GPT is initialised */ ++static void setup_empty_gpt(void) ++{ ++ test_header.num_partitions = 0; ++ TEST_ASSERT_EQUAL(PSA_SUCCESS, setup_test_gpt()); ++} ++ ++void setUp(void) ++{ ++ /* Default starting points */ ++ test_mbr = default_mbr; ++ test_header = default_header; ++ memcpy(&test_partition_array, &default_partition_array, sizeof(default_partition_array)); ++ for (size_t i = 0; i < TEST_DEFAULT_NUM_PARTITIONS; ++i) { ++ char unicode_name[GPT_ENTRY_NAME_LENGTH] = {'\0'}; ++ ascii_to_unicode(test_partition_array[i].name, unicode_name); ++ memcpy(test_partition_array[i].name, unicode_name, GPT_ENTRY_NAME_LENGTH); ++ } ++ ++ test_mbr.partitions[0].os_type = TEST_MBR_TYPE_GPT; ++ ++ /* Ignore all logging calls */ ++ tfm_log_Ignore(); ++ ++ num_mocked_reads = 0; ++ registered_mocked_reads = 0; ++ memset(mock_read_buffer, 0, sizeof(mock_read_buffer)); ++} ++ ++void tearDown(void) ++{ ++ num_mocked_reads = 0; ++ registered_mocked_reads = 0; ++ memset(mock_read_buffer, 0, sizeof(mock_read_buffer)); ++ memset(&test_partition_array, 0, sizeof(test_partition_array)); ++ gpt_uninit(); ++} ++ ++void test_gpt_init_should_loadWhenGptGood(void) ++{ ++ setup_valid_gpt(); ++} ++ ++void test_gpt_init_should_overwriteOldGpt(void) ++{ ++ setup_valid_gpt(); ++ gpt_uninit(); ++ ++ /* Use a different disk GUID */ ++ const struct efi_guid_t new_guid = MAKE_EFI_GUID(1, 1, 3, 4, 5, 6 ,7 ,8, 9, 10, 11); ++ test_header.disk_guid = new_guid; ++ ++ setup_valid_gpt(); ++} ++ ++void test_gpt_init_should_failWhenMbrSigBad(void) ++{ ++ test_mbr.sig--; ++ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, setup_test_gpt()); ++} ++ ++void test_gpt_init_should_failWhenMbrTypeInvalid(void) ++{ ++ test_mbr.partitions[0].os_type--; ++ TEST_ASSERT_EQUAL(PSA_ERROR_NOT_SUPPORTED, setup_test_gpt()); ++} ++ ++void test_gpt_init_should_failWhenFlashDriverNotFullyDefined(void) ++{ ++ gpt_flash_read_t read_fn = mock_driver.read; ++ mock_driver.read = NULL; ++ TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, gpt_init(&mock_driver, TEST_MAX_PARTITIONS)); ++ mock_driver.read = read_fn; ++} ++ ++void test_gpt_entry_read_should_populateEntry(void) ++{ ++ /* Start with a populated GPT */ ++ setup_valid_gpt(); ++ ++ /* Ensure an entry is found */ ++ struct partition_entry_t entry; ++ struct gpt_entry_t *desired = &(test_partition_array[TEST_DEFAULT_NUM_PARTITIONS - 1]); ++ struct efi_guid_t test_guid = desired->guid; ++ struct efi_guid_t test_type = desired->type; ++ register_mocked_read(&test_partition_array, sizeof(test_partition_array)); ++ TEST_ASSERT_EQUAL(PSA_SUCCESS, gpt_entry_read(&test_guid, &entry)); ++ ++ /* Ensure this is the correct entry */ ++ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_guid, &(entry.partition_guid))); ++ TEST_ASSERT_EQUAL(0, efi_guid_cmp(&test_type, &(entry.type_guid))); ++ TEST_ASSERT_EQUAL(desired->start, entry.start); ++ ++ /* Size is number of blocks, so subtract one */ ++ TEST_ASSERT_EQUAL(desired->end, entry.start + entry.size - 1); ++ ++ /* Name is unicode */ ++ TEST_ASSERT_EQUAL_MEMORY(desired->name, entry.name, GPT_ENTRY_NAME_LENGTH); ++} ++ ++void test_gpt_entry_read_should_failWhenEntryNotExisting(void) ++{ ++ /* Start with an empty GPT */ ++ setup_empty_gpt(); ++ ++ /* Try to read something */ ++ struct partition_entry_t entry; ++ struct efi_guid_t non_existing = NULL_GUID; ++ TEST_ASSERT_EQUAL(PSA_ERROR_DOES_NOT_EXIST, gpt_entry_read(&non_existing, &entry)); ++ ++ /* 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_read(&non_existing, &entry)); ++} +diff --git a/lib/gpt/unittests/gpt/utcfg.cmake b/lib/gpt/unittests/gpt/utcfg.cmake +new file mode 100644 +index 000000000..37d72d138 +--- /dev/null ++++ b/lib/gpt/unittests/gpt/utcfg.cmake +@@ -0,0 +1,28 @@ ++#------------------------------------------------------------------------------- ++# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors ++# ++# SPDX-License-Identifier: BSD-3-Clause ++# ++#------------------------------------------------------------------------------- ++ ++# Define what is being unit tested and by what ++set(UNIT_UNDER_TEST ${TFM_ROOT_DIR}/lib/gpt/src/gpt.c) ++set(UNIT_TEST_SUITE ${CMAKE_CURRENT_LIST_DIR}/test_gpt.c) ++ ++# Dependencies for the UUT, that get linked into the executable ++ ++# Include directories for compilation ++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/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) ++ ++# Compile-time definitions ++list(APPEND UNIT_TEST_COMPILE_DEFS LOG_LEVEL=LOG_LEVEL_VERBOSE) ++list(APPEND UNIT_TEST_COMPILE_DEFS TFM_GPT_BLOCK_SIZE=512) ++ diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0020-lib-gpt-Expanded-how-GPT-partition-can-be-identified.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0020-lib-gpt-Expanded-how-GPT-partition-can-be-identified.patch new file mode 100644 index 00000000..dca104f3 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0020-lib-gpt-Expanded-how-GPT-partition-can-be-identified.patch @@ -0,0 +1,308 @@ +From b3775fd8aa2078e5e86d5cdb4164e6fc31fabbfc Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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)); ++} diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0021-lib-gpt-Added-operations-to-modify-partitions.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0021-lib-gpt-Added-operations-to-modify-partitions.patch new file mode 100644 index 00000000..04348b58 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0021-lib-gpt-Added-operations-to-modify-partitions.patch @@ -0,0 +1,961 @@ +From 02ec696240d0225ed6473ea5b01ec6617d897a41 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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) diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0022-lib-gpt-Added-operation-to-move-entry.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0022-lib-gpt-Added-operation-to-move-entry.patch new file mode 100644 index 00000000..f6341e2d --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0022-lib-gpt-Added-operation-to-move-entry.patch @@ -0,0 +1,374 @@ +From 7a453edd736c919eccc40eec567e8e97c0597bba Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 */ diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0023-lib-gpt-Added-ability-to-create-and-remove-partition.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0023-lib-gpt-Added-ability-to-create-and-remove-partition.patch new file mode 100644 index 00000000..bb8d0a3c --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0023-lib-gpt-Added-ability-to-create-and-remove-partition.patch @@ -0,0 +1,713 @@ +From bec8f44a2732c20e8f69a06841637673af90c37e Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 + $ ++ $ + ) + + 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 + #include + +-#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 diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0024-lib-gpt-Added-table-validation-operations.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0024-lib-gpt-Added-table-validation-operations.patch new file mode 100644 index 00000000..95335926 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0024-lib-gpt-Added-table-validation-operations.patch @@ -0,0 +1,412 @@ +From c0037dc1779d181ce7d7dbd5871519c9d218440a Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0025-lib-gpt-Added-defragmentation-operation.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0025-lib-gpt-Added-defragmentation-operation.patch new file mode 100644 index 00000000..58da3276 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0025-lib-gpt-Added-defragmentation-operation.patch @@ -0,0 +1,280 @@ +From ba38f0f304ad69047ce9830b81a4f9cfbccb8fcb Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 + #include ++#include + #include + #include + +@@ -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 diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0026-lib-GPT-Fix-cppcheck-warnings.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0026-lib-GPT-Fix-cppcheck-warnings.patch new file mode 100644 index 00000000..58175cd1 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0026-lib-GPT-Fix-cppcheck-warnings.patch @@ -0,0 +1,74 @@ +From f9e4d1f48a4553278dc4de82b0d2f4d82b1e5193 Mon Sep 17 00:00:00 2001 +From: Antonio de Angelis +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 +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 + #include + #include + #include +@@ -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 + */ diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0027-lib-efi_guid-Remove-unecessary-include-folder.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0027-lib-efi_guid-Remove-unecessary-include-folder.patch new file mode 100644 index 00000000..f713ad2a --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0027-lib-efi_guid-Remove-unecessary-include-folder.patch @@ -0,0 +1,28 @@ +From 31cd6d9eb82792efd5af7d99802581eace13a083 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 + $ +- PRIVATE +- ${CMAKE_CURRENT_SOURCE_DIR}/src + ) + + target_link_libraries(tfm_efi_guid diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0028-lib-efi_guid-Correct-included-folder.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0028-lib-efi_guid-Correct-included-folder.patch new file mode 100644 index 00000000..56d3a6e6 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0028-lib-efi_guid-Correct-included-folder.patch @@ -0,0 +1,28 @@ +From 0b6a2e681b0f76c425896990ebc4afcbc65419d3 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 +- $ ++ inc + ) + + target_link_libraries(tfm_efi_guid diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0029-lib-efi_soft_crc-Correct-include-directory.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0029-lib-efi_soft_crc-Correct-include-directory.patch new file mode 100644 index 00000000..c3340774 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0029-lib-efi_soft_crc-Correct-include-directory.patch @@ -0,0 +1,25 @@ +From f1862245d39a726c8e37f58498dd433c6fd99d1b Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 +- $ ++ inc + ) diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0030-lib-gpt-Add-missing-link-library.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0030-lib-gpt-Add-missing-link-library.patch new file mode 100644 index 00000000..64bdc489 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0030-lib-gpt-Add-missing-link-library.patch @@ -0,0 +1,27 @@ +From 343bba6c20802555dfb92c3e2b22a7e07c10a57a Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0031-lib-gpt-Correct-variable-name-used.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0031-lib-gpt-Correct-variable-name-used.patch new file mode 100644 index 00000000..280b9774 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0031-lib-gpt-Correct-variable-name-used.patch @@ -0,0 +1,24 @@ +From 1ae97df8db8babcaa999e47d9641c83c4ee8424a Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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) + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0032-lib-gpt-Correct-include-directory.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0032-lib-gpt-Correct-include-directory.patch new file mode 100644 index 00000000..6121d293 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0032-lib-gpt-Correct-include-directory.patch @@ -0,0 +1,27 @@ +From eb934a532bbc8385cd9b062fc80cece61350f086 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 +- $ ++ inc + $ + ) + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0033-lib-gpt-Move-contents-of-CMake-config-file.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0033-lib-gpt-Move-contents-of-CMake-config-file.patch new file mode 100644 index 00000000..b3a9ee74 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0033-lib-gpt-Move-contents-of-CMake-config-file.patch @@ -0,0 +1,51 @@ +From ce3a4f3dd8900c068f2bfe951d55b895e3c10d43 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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") diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m-corstone1000.inc b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m-corstone1000.inc index 7382d877..b55a61ac 100644 --- a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m-corstone1000.inc +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m-corstone1000.inc @@ -48,6 +48,23 @@ SRC_URI:append:corstone1000 = " \ 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 \ " SRCREV_tfm-psa-adac:corstone1000 = "f2809ae231be33a1afcd7714f40756c67d846c88" From patchwork Thu Mar 26 13:28:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Frazer Carsley X-Patchwork-Id: 84518 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 08C6D10A62D2 for ; Thu, 26 Mar 2026 13:29:21 +0000 (UTC) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.47422.1774531757109817897 for ; Thu, 26 Mar 2026 06:29:17 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: body hash did not verify" header.i=@arm.com header.s=foss header.b=n22SEM+9; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: frazer.carsley@arm.com) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A40841AED; Thu, 26 Mar 2026 06:29:10 -0700 (PDT) Received: from e138143.arm.com (unknown [10.57.12.40]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A0A3A3F836; Thu, 26 Mar 2026 06:29:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1774531756; bh=H5Ai6I+rRC561Z9uqgp0bky/yR8J7ScD+n3qzsv+LSU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=n22SEM+9ArApQ6klGuRUXpIOB5iilyB97ZHLl3Rn7FkOZHa5x450vz1etsaMPZchK czUyFY8O/Jh2hwqH6mtOtyN/cAeJz8G0q4Kf5hKm7KT6nojgYGC56TI6FVPznhzwwv gak0LYWrnClAlv5SvfAawJFoKmzg+5J1RdUuGRT0= From: Frazer Carsley To: meta-arm@lists.yoctoproject.org Cc: Frazer Carsley Subject: [PATCH 2/2] arm-bsp/tf-m:cs1k: modified mcuboot to use GPT library Date: Thu, 26 Mar 2026 13:28:40 +0000 Message-ID: <20260326132857.1590256-3-frazer.carsley@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260326132857.1590256-1-frazer.carsley@arm.com> References: <20260326132857.1590256-1-frazer.carsley@arm.com> MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 26 Mar 2026 13:29:21 -0000 X-Groupsio-URL: https://lists.yoctoproject.org/g/meta-arm/message/6975 Corstone1000 used to use its own implementation of a GPT parser for use in a capsule update. The patches in this commit replace what exists with the generic GPT library, as well as other minor self-explanatory fixes. The wic file has undergone two changes as a result of this: 1. The partition type GUID of each of the four partitions that can be updated by a capsule update must match the GUID of each capsule. This allows for the existing partition to be matched with its updated image. Different machines (e.g. MPS3 vs FVP) have different GUIDs for these images hence the need for separate files. 2. The second bank has been removed from provisioning. Because the library supports dynamic creation of partitions, the second bank no longer needs to be provisioned at build time. However, a small reserved partition is still created above the 32KiB mark to force wic to size the disk as 64KiB and write this into the GPT header for the library to read on initialisation. Finally, the size of bl1_1 is reduced by one of the patches in this commit, so this is also reflected in the recipe. Signed-off-by: Frazer Carsley --- .../conf/machine/corstone1000-fvp.conf | 2 + .../conf/machine/corstone1000-mps3.conf | 2 + .../conf/machine/include/corstone1000.inc | 1 - ...34-plat-cs1k-Fixed-formatting-errors.patch | 261 + ...5-plat-cs1k-Removed-unused-variables.patch | 43 + ...plat-cs1k-Fixed-bad-function-returns.patch | 40 + ...at-cs1k-Improved-logging-in-function.patch | 48 + ...038-plat-cs1k-Remove-unused-function.patch | 93 + ...039-plat-cs1k-Reduce-BL1-binary-size.patch | 464 ++ ...-plat-cs1k-Update-license-identifier.patch | 35 + ...-cs1k-Changed-to-use-new-GPT-library.patch | 4536 +++++++++++++++++ ...s1k-Move-variable-from-stack-to-data.patch | 55 + ...eate-and-remove-FWU-image-partitions.patch | 521 ++ .../trusted-firmware-m-corstone1000.inc | 14 +- ...=> corstone1000-flash-firmware-fvp.wks.in} | 22 +- .../corstone1000-flash-firmware-mps3.wks.in | 34 + 16 files changed, 6154 insertions(+), 17 deletions(-) create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0034-plat-cs1k-Fixed-formatting-errors.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0035-plat-cs1k-Removed-unused-variables.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0036-plat-cs1k-Fixed-bad-function-returns.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0037-plat-cs1k-Improved-logging-in-function.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0038-plat-cs1k-Remove-unused-function.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0039-plat-cs1k-Reduce-BL1-binary-size.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0040-plat-cs1k-Update-license-identifier.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0041-plat-cs1k-Changed-to-use-new-GPT-library.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0042-plat-cs1k-Move-variable-from-stack-to-data.patch create mode 100644 meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0043-plat-cs1k-Create-and-remove-FWU-image-partitions.patch rename meta-arm-bsp/wic/{corstone1000-flash-firmware.wks.in => corstone1000-flash-firmware-fvp.wks.in} (65%) create mode 100644 meta-arm-bsp/wic/corstone1000-flash-firmware-mps3.wks.in diff --git a/meta-arm-bsp/conf/machine/corstone1000-fvp.conf b/meta-arm-bsp/conf/machine/corstone1000-fvp.conf index 07f29960..e447b56e 100644 --- a/meta-arm-bsp/conf/machine/corstone1000-fvp.conf +++ b/meta-arm-bsp/conf/machine/corstone1000-fvp.conf @@ -15,6 +15,8 @@ TFM_PLATFORM_IS_FVP = "TRUE" CORSTONE_1000_TYPE = "CORSTONE_1000_TYPE_CORTEX_A35_FVP" +WKS_FILE:firmware ?= "corstone1000-flash-firmware-fvp.wks.in" + # testimage config TEST_TARGET = "OEFVPTarget" TEST_TARGET_IP = "127.0.0.1:2222" diff --git a/meta-arm-bsp/conf/machine/corstone1000-mps3.conf b/meta-arm-bsp/conf/machine/corstone1000-mps3.conf index 2b5aed4e..9327de65 100644 --- a/meta-arm-bsp/conf/machine/corstone1000-mps3.conf +++ b/meta-arm-bsp/conf/machine/corstone1000-mps3.conf @@ -10,3 +10,5 @@ TFA_TARGET_PLATFORM = "fpga" MACHINE_FEATURES += "coresight" CORSTONE_1000_TYPE = "CORSTONE_1000_TYPE_CORTEX_A35_MPS3" + +WKS_FILE:firmware ?= "corstone1000-flash-firmware-mps3.wks.in" diff --git a/meta-arm-bsp/conf/machine/include/corstone1000.inc b/meta-arm-bsp/conf/machine/include/corstone1000.inc index ebc8f7a6..6f82c597 100644 --- a/meta-arm-bsp/conf/machine/include/corstone1000.inc +++ b/meta-arm-bsp/conf/machine/include/corstone1000.inc @@ -52,7 +52,6 @@ IMAGE_FSTYPES += "wic" # Need to clear the suffix so TESTIMAGE_AUTO works IMAGE_NAME_SUFFIX = "" WKS_FILE ?= "efi-disk-no-swap.wks.in" -WKS_FILE:firmware ?= "corstone1000-flash-firmware.wks.in" # making sure EXTRA_IMAGEDEPENDS will be used while creating the image WKS_FILE_DEPENDS:append = " ${EXTRA_IMAGEDEPENDS}" diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0034-plat-cs1k-Fixed-formatting-errors.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0034-plat-cs1k-Fixed-formatting-errors.patch new file mode 100644 index 00000000..28429f70 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0034-plat-cs1k-Fixed-formatting-errors.patch @@ -0,0 +1,261 @@ +From 9402dd67413e74284bc598225b4c5399fbd1a099 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 + $<$:${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 + $ +- ${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; iactive_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; + } + } diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0035-plat-cs1k-Removed-unused-variables.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0035-plat-cs1k-Removed-unused-variables.patch new file mode 100644 index 00000000..5c8464b0 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0035-plat-cs1k-Removed-unused-variables.patch @@ -0,0 +1,43 @@ +From c579565c25937ae9455efe9cc3fbcace84c3e580 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +Date: Mon, 29 Dec 2025 11:28:47 +0000 +Subject: [PATCH] plat: cs1k: Removed unused variables + +Change-Id: I0dd3ff834c47c58dc833586c74791deca679a3ab +Signed-off-by: Frazer Carsley +Upstream-Status: Backport +--- + .../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 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 +@@ -1511,7 +1511,6 @@ static psa_status_t fwu_accept_image(struct fwu_metadata *metadata, + uint8_t number) + { + uint8_t current_state; +- uint32_t image_bank_offset; + uint32_t active_bank_index; + uint32_t fwu_image_index; + psa_status_t ret; +@@ -1848,7 +1847,6 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u + { + int ret; + uint32_t active_index; +- uint32_t bank_offset; + uint32_t previous_active_index; + uint8_t fwu_image_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; + } else if (active_index == BANK_1) { + previous_active_index = BANK_0; +- bank_offset = BANK_0_PARTITION_OFFSET; + } else { + FWU_LOG_MSG("ERROR: %s: active_index %d\n\r",__func__,active_index); + ret = PSA_ERROR_DATA_INVALID; diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0036-plat-cs1k-Fixed-bad-function-returns.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0036-plat-cs1k-Fixed-bad-function-returns.patch new file mode 100644 index 00000000..35643451 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0036-plat-cs1k-Fixed-bad-function-returns.patch @@ -0,0 +1,40 @@ +From 50db5724ef37d5c7cec019254d135b3dcfd0d340 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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 = diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0037-plat-cs1k-Improved-logging-in-function.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0037-plat-cs1k-Improved-logging-in-function.patch new file mode 100644 index 00000000..3f302770 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0037-plat-cs1k-Improved-logging-in-function.patch @@ -0,0 +1,48 @@ +From f48a0a6b60309433269c7927dac992eff06f3745 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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); diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0038-plat-cs1k-Remove-unused-function.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0038-plat-cs1k-Remove-unused-function.patch new file mode 100644 index 00000000..aae01d8d --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0038-plat-cs1k-Remove-unused-function.patch @@ -0,0 +1,93 @@ +From bd6d7dc80556e8c4261343141d675e865d4e960b Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +Date: Fri, 2 Jan 2026 13:33:25 +0000 +Subject: [PATCH] plat: cs1k: Remove unused function + +Change-Id: I6e054213dc1ec94a6dc8304705d4cb6e6da701cc +Signed-off-by: Frazer Carsley +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) + { diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0039-plat-cs1k-Reduce-BL1-binary-size.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0039-plat-cs1k-Reduce-BL1-binary-size.patch new file mode 100644 index 00000000..9190c04f --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0039-plat-cs1k-Reduce-BL1-binary-size.patch @@ -0,0 +1,464 @@ +From 939d18a0d8dcedd2b5c4b6220e1a0f6c6855fcf6 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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) diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0040-plat-cs1k-Update-license-identifier.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0040-plat-cs1k-Update-license-identifier.patch new file mode 100644 index 00000000..0859734f --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0040-plat-cs1k-Update-license-identifier.patch @@ -0,0 +1,35 @@ +From b4fd75b96b49756c4815685fc19089793fcc9356 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +Date: Wed, 14 Jan 2026 14:00:12 +0000 +Subject: [PATCH] plat: cs1k: Update license identifier + +Change-Id: I26af0dbf66359e76b7164b3abdbbf3ace3f358c6 +Signed-off-by: Frazer Carsley +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 + * diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0041-plat-cs1k-Changed-to-use-new-GPT-library.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0041-plat-cs1k-Changed-to-use-new-GPT-library.patch new file mode 100644 index 00000000..a508252b --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0041-plat-cs1k-Changed-to-use-new-GPT-library.patch @@ -0,0 +1,4536 @@ +From 1b058b6ccc4318f6805d96da5073debf99c764a5 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +Date: Mon, 2 Mar 2026 14:37:12 +0000 +Subject: [PATCH] plat: cs1k: Changed to use new GPT library + +Corstone1000 already had a basic GPT parser implementation however +lacked full GPT support. Since the addition of the new GPT library, this +commit removes Corstone1000's parser and uses the library instead for +parsing/read operations. Because Corstone1000's firmware update +mechanism uses two banks with fixed offsets in each for the different +images/partitions, the GPT library is not used to modify any partitions. + +The GPT library requires callers to register a pseudo-device driver and +this is implemented by the io_gpt module. As such, there is no need +anymore for the abstraction provided by the previous io_* modules, as +this new module handles the translation between LBAs and +sectors/addresses of flash. + +Change-Id: I1bde0e482a4c5286997ae383f90648e9f8043083 +Signed-off-by: Frazer Carsley +Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/49429] +--- + .../target/arm/corstone1000/CMakeLists.txt | 68 ++- + .../arm/corstone1000/bl2/boot_hal_bl2.c | 67 ++- + .../arm/corstone1000/bootloader/fwu_agent.h | 21 +- + .../bootloader/mcuboot/tfm_mcuboot_fwu.c | 328 +++++++---- + .../bootloader/mcuboot/uefi_fmp.c | 13 +- + .../arm/corstone1000/bootloader/uefi_fmp.h | 3 +- + .../ci_regression_tests/CMakeLists.txt | 12 - + .../Driver_Flash_SRAM_Emu.c | 327 ----------- + .../ci_regression_tests/s_io_storage_test.c | 147 ----- + .../ci_regression_tests/s_io_storage_test.h | 15 - + .../corstone1000/ci_regression_tests/s_test.c | 3 +- + .../ci_regression_tests/s_test_config.cmake | 13 - + .../ci_regression_tests/test_flash.h | 25 - + .../ext/target/arm/corstone1000/config.cmake | 4 + + .../corstone1000/fip_parser/external/uuid.h | 74 --- + .../arm/corstone1000/fip_parser/fip_parser.c | 12 +- + .../arm/corstone1000/fip_parser/fip_parser.h | 26 +- + .../ext/target/arm/corstone1000/io/io_block.c | 528 ------------------ + .../ext/target/arm/corstone1000/io/io_block.h | 40 -- + .../ext/target/arm/corstone1000/io/io_defs.h | 27 - + .../target/arm/corstone1000/io/io_driver.h | 54 -- + .../ext/target/arm/corstone1000/io/io_flash.c | 183 ------ + .../ext/target/arm/corstone1000/io/io_flash.h | 37 -- + .../ext/target/arm/corstone1000/io/io_gpt.c | 179 ++++++ + .../ext/target/arm/corstone1000/io/io_gpt.h | 25 + + .../target/arm/corstone1000/io/io_storage.c | 289 ---------- + .../target/arm/corstone1000/io/io_storage.h | 92 --- + .../target/arm/corstone1000/partition/efi.h | 37 -- + .../target/arm/corstone1000/partition/gpt.c | 58 -- + .../target/arm/corstone1000/partition/gpt.h | 51 -- + .../target/arm/corstone1000/partition/mbr.h | 29 - + .../arm/corstone1000/partition/partition.c | 324 ----------- + .../arm/corstone1000/partition/partition.h | 48 -- + .../target/arm/corstone1000/partition/uuid.h | 76 --- + .../ext/target/arm/corstone1000/platform.c | 71 +-- + .../ext/target/arm/corstone1000/platform.h | 32 +- + .../arm/corstone1000/soft_crc/soft_crc.c | 121 ---- + .../arm/corstone1000/soft_crc/soft_crc.h | 18 - + 38 files changed, 606 insertions(+), 2871 deletions(-) + delete mode 100644 platform/ext/target/arm/corstone1000/ci_regression_tests/Driver_Flash_SRAM_Emu.c + delete mode 100644 platform/ext/target/arm/corstone1000/ci_regression_tests/s_io_storage_test.c + delete mode 100644 platform/ext/target/arm/corstone1000/ci_regression_tests/s_io_storage_test.h + delete mode 100644 platform/ext/target/arm/corstone1000/ci_regression_tests/s_test_config.cmake + delete mode 100644 platform/ext/target/arm/corstone1000/ci_regression_tests/test_flash.h + delete mode 100644 platform/ext/target/arm/corstone1000/fip_parser/external/uuid.h + delete mode 100644 platform/ext/target/arm/corstone1000/io/io_block.c + delete mode 100644 platform/ext/target/arm/corstone1000/io/io_block.h + delete mode 100644 platform/ext/target/arm/corstone1000/io/io_defs.h + delete mode 100644 platform/ext/target/arm/corstone1000/io/io_driver.h + delete mode 100644 platform/ext/target/arm/corstone1000/io/io_flash.c + delete mode 100644 platform/ext/target/arm/corstone1000/io/io_flash.h + create mode 100644 platform/ext/target/arm/corstone1000/io/io_gpt.c + create mode 100644 platform/ext/target/arm/corstone1000/io/io_gpt.h + delete mode 100644 platform/ext/target/arm/corstone1000/io/io_storage.c + delete mode 100644 platform/ext/target/arm/corstone1000/io/io_storage.h + delete mode 100644 platform/ext/target/arm/corstone1000/partition/efi.h + delete mode 100644 platform/ext/target/arm/corstone1000/partition/gpt.c + delete mode 100644 platform/ext/target/arm/corstone1000/partition/gpt.h + delete mode 100644 platform/ext/target/arm/corstone1000/partition/mbr.h + delete mode 100644 platform/ext/target/arm/corstone1000/partition/partition.c + delete mode 100644 platform/ext/target/arm/corstone1000/partition/partition.h + delete mode 100644 platform/ext/target/arm/corstone1000/partition/uuid.h + delete mode 100644 platform/ext/target/arm/corstone1000/soft_crc/soft_crc.c + delete mode 100644 platform/ext/target/arm/corstone1000/soft_crc/soft_crc.h + +diff --git a/platform/ext/target/arm/corstone1000/CMakeLists.txt b/platform/ext/target/arm/corstone1000/CMakeLists.txt +index 58edae74e..7168c1ca9 100644 +--- a/platform/ext/target/arm/corstone1000/CMakeLists.txt ++++ b/platform/ext/target/arm/corstone1000/CMakeLists.txt +@@ -116,9 +116,11 @@ target_include_directories(platform_s + INTERFACE + cc312 + bootloader +- soft_crc + io + partition ++ ${CMAKE_SOURCE_DIR}/lib/ext/efi_soft_crc/inc ++ ${CMAKE_SOURCE_DIR}/lib/efi_guid/inc ++ ${CMAKE_SOURCE_DIR}/lib/gpt/inc + ) + + target_sources(platform_s +@@ -135,19 +137,23 @@ target_sources(platform_s + $<$:${CMAKE_CURRENT_SOURCE_DIR}/services/src/tfm_platform_system.c> + bootloader/mcuboot/tfm_mcuboot_fwu.c + bootloader/mcuboot/uefi_fmp.c +- soft_crc/soft_crc.c +- io/io_block.c +- io/io_flash.c +- io/io_storage.c +- partition/partition.c +- partition/gpt.c + $<$>:${PLATFORM_DIR}/ext/accelerator/cc312/otp_cc312.c> + rse_comms_permissions_hal.c + mem_check_v6m_v7m_hal.c + ${PLATFORM_DIR}/ext/common/mem_check_v6m_v7m.c ++ io/io_gpt.c + platform.c + ) + ++target_link_libraries(platform_s ++ PUBLIC ++ tfm_log ++ PRIVATE ++ tfm_efi_soft_crc ++ tfm_efi_guid ++ tfm_gpt ++) ++ + if (PLATFORM_IS_FVP) + target_sources(platform_s + PRIVATE +@@ -167,6 +173,9 @@ target_compile_definitions(platform_s + PUBLIC + $<$:EXTERNAL_SYSTEM_SUPPORT> + $<$:PLATFORM_IS_FVP> ++ TFM_GPT_BLOCK_SIZE=${TFM_GPT_BLOCK_SIZE} ++ PLAT_MAX_PARTITION_ENTRIES=${PLAT_MAX_PARTITION_ENTRIES} ++ LOG_LEVEL=${GPT_LOG_LEVEL} + PRIVATE + $<$:TFM_S_REG_TEST> + $<$:ENABLE_FWU_AGENT_DEBUG_LOGS> +@@ -200,7 +209,6 @@ target_sources(platform_bl1_1 + ./bl1/provisioning.c + ./bootloader/mcuboot/tfm_mcuboot_fwu.c + ./bootloader/mcuboot/uefi_fmp.c +- ./soft_crc/soft_crc.c + $<$>:${PLATFORM_DIR}/ext/accelerator/cc312/otp_cc312.c> + $<$>:${CMAKE_CURRENT_SOURCE_DIR}/bl1/cc312_rom_crypto.c> + $<$>:${CMAKE_CURRENT_SOURCE_DIR}/bl1/cc312_rom_trng.c> +@@ -231,7 +239,6 @@ target_include_directories(platform_bl1_1_interface + ./Native_Driver + ./CMSIS_Driver/Config + ./bootloader +- ./soft_crc + ${PLATFORM_DIR}/ext/target/arm/drivers/flash/cfi + ${PLATFORM_DIR}/ext/target/arm/drivers/flash/common + ${PLATFORM_DIR}/ext/target/arm/drivers/flash/strata +@@ -243,16 +250,22 @@ target_include_directories(platform_bl1_1_interface + $<$:${CMAKE_SOURCE_DIR}/platform/ext/accelerator/interface> + ${PLATFORM_DIR}/ext/accelerator/cc312/ + ${CMAKE_SOURCE_DIR}/lib/fih/inc/ ++ ${CMAKE_SOURCE_DIR}/lib/gpt/inc # for GPT_ENTRY_NAME_LENGTH + ) + + target_link_libraries(platform_bl1_1 + PRIVATE + $<$>:cc3xx> ++ tfm_efi_soft_crc ++ tfm_efi_guid + ) + + target_include_directories(platform_bl1_1 + PRIVATE + ${CMAKE_SOURCE_DIR}/interface/include # for psa/error.h ++ ${CMAKE_SOURCE_DIR}/lib/ext/efi_soft_crc/inc ++ ${CMAKE_SOURCE_DIR}/lib/efi_guid/inc ++ ${CMAKE_SOURCE_DIR}/lib/gpt/inc + ) + + target_sources(platform_bl1_2 +@@ -281,7 +294,6 @@ target_include_directories(platform_bl1_2 + ./Native_Driver + ./CMSIS_Driver/Config + ./bootloader +- ./soft_crc + ${PLATFORM_DIR}/ext/target/arm/drivers/flash/common + ${PLATFORM_DIR}/ext/target/arm/drivers/flash/cfi + ${PLATFORM_DIR}/ext/target/arm/drivers/flash/strata +@@ -290,6 +302,15 @@ target_include_directories(platform_bl1_2 + ${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}/lib/ext/efi_soft_crc/inc ++ ${CMAKE_SOURCE_DIR}/lib/efi_guid/inc ++ ${CMAKE_SOURCE_DIR}/lib/gpt/inc # for GPT_ENTRY_NAME_LENGTH ++) ++ ++target_link_libraries(platform_bl1_2 ++ PRIVATE ++ tfm_efi_soft_crc ++ tfm_efi_guid + ) + + #========================= Platform BL2 =======================================# +@@ -309,12 +330,7 @@ target_sources(platform_bl2 + bootloader/mcuboot/tfm_mcuboot_fwu.c + bl2/security_cnt_bl2.c + $<$>:${PLATFORM_DIR}/ext/accelerator/cc312/otp_cc312.c> +- io/io_block.c +- io/io_flash.c +- io/io_storage.c +- soft_crc/soft_crc.c +- partition/partition.c +- partition/gpt.c ++ io/io_gpt.c + platform.c + ) + +@@ -334,6 +350,10 @@ target_sources(platform_bl2 + endif() + + target_compile_definitions(platform_bl2 ++ PUBLIC ++ TFM_GPT_BLOCK_SIZE=${TFM_GPT_BLOCK_SIZE} ++ PLAT_MAX_PARTITION_ENTRIES=${PLAT_MAX_PARTITION_ENTRIES} ++ LOG_LEVEL=${GPT_LOG_LEVEL} + PRIVATE + $<$:PLATFORM_IS_FVP> + $<$:TFM_S_REG_TEST> +@@ -353,6 +373,14 @@ target_sources(bl2 + target_link_libraries(bl2 + PRIVATE + $<$:trusted-firmware-m-psa-adac> ++ tfm_log ++) ++ ++target_link_libraries(platform_bl2 ++ PRIVATE ++ tfm_gpt ++ tfm_efi_soft_crc ++ tfm_efi_guid + ) + + target_compile_definitions(bl2 +@@ -365,6 +393,10 @@ target_compile_definitions(bl2 + target_include_directories(bl2 + PRIVATE + ${CMAKE_SOURCE_DIR}/interface/include # for psa/error.h ++ ${CMAKE_SOURCE_DIR}/lib/efi_guid/inc # for efi_guid_structs.h ++ ${CMAKE_SOURCE_DIR}/lib/gpt/inc ++ ${CMAKE_SOURCE_DIR}/lib/tfm_log/inc ++ ${CMAKE_SOURCE_DIR}/lib/tfm_vprintf/inc + ) + + target_compile_definitions(bootutil +@@ -379,7 +411,6 @@ target_include_directories(platform_bl2 + fip_parser + Native_Driver + bootloader +- soft_crc + io + ${PLATFORM_DIR}/ext/target/arm/drivers/flash/common + ${PLATFORM_DIR}/ext/target/arm/drivers/flash/cfi +@@ -398,6 +429,9 @@ target_include_directories(platform_bl2 + ${CMAKE_BINARY_DIR}/bl2/ext/mcuboot # for mcuboot_config.h only + $ + ${CMAKE_SOURCE_DIR}/interface/include # for psa/error.h ++ ${CMAKE_SOURCE_DIR}/lib/ext/efi_soft_crc/inc ++ ${CMAKE_SOURCE_DIR}/lib/efi_guid/inc ++ ${CMAKE_SOURCE_DIR}/lib/gpt/inc + ) + + #========================= ns_agent_mailbox ===================================# +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 bf7b62881..1ed111af6 100644 +--- a/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c ++++ b/platform/ext/target/arm/corstone1000/bl2/boot_hal_bl2.c +@@ -5,6 +5,7 @@ + * + */ + ++#include + #include + #include + #include "tfm_hal_device_header.h" +@@ -31,8 +32,8 @@ + #include "crypto_hw.h" + #endif + +-#include "efi.h" +-#include "partition.h" ++#include "gpt.h" ++#include "io_gpt.h" + #include "platform.h" + + static const char* const tfm_part_names[] = {"tfm_primary", "tfm_secondary"}; +@@ -49,6 +50,14 @@ REGION_DECLARE(Image$$, ARM_LIB_HEAP, $$ZI$$Limit)[]; + #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0])) + extern struct flash_area flash_map[]; + ++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'; ++ } ++} ++ + static bool fill_flash_map_with_tfm_data(uint8_t boot_index) { + + if (boot_index >= ARRAY_SIZE(tfm_part_names)) { +@@ -56,14 +65,28 @@ static bool fill_flash_map_with_tfm_data(uint8_t boot_index) { + boot_index, ARRAY_SIZE(tfm_part_names)); + return false; + } +- const partition_entry_t *tfm_entry = +- get_partition_entry(tfm_part_names[boot_index]); +- if (tfm_entry == NULL) { ++ ++ /* Convert ascii to unicode so GPT library understands */ ++ char unicode_name[GPT_ENTRY_NAME_LENGTH] = {'\0'}; ++ ascii_to_unicode(tfm_part_names[boot_index], unicode_name); ++ struct partition_entry_t tfm_entry; ++ psa_status_t ret = gpt_entry_read_by_name( ++ unicode_name, ++ 0, ++ &tfm_entry); ++ if (ret == PSA_ERROR_DOES_NOT_EXIST) { ++ BOOT_LOG_ERR("Could not find partition %s", tfm_part_names[boot_index]); ++ return false; ++ } else if (ret == PSA_ERROR_STORAGE_FAILURE) { ++ BOOT_LOG_ERR("%s: I/O error occurred with flash device", __func__); ++ return false; ++ } else if (ret < 0) { + BOOT_LOG_ERR("Could not find partition %s", tfm_part_names[boot_index]); + return false; + } +- flash_map[0].fa_off = tfm_entry->start; +- flash_map[0].fa_size = tfm_entry->length; ++ ++ flash_map[0].fa_off = tfm_entry.start * TFM_GPT_BLOCK_SIZE; ++ flash_map[0].fa_size = tfm_entry.size * TFM_GPT_BLOCK_SIZE; + return true; + } + +@@ -80,15 +103,27 @@ static bool fill_flash_map_with_fip_data(uint8_t boot_index) { + boot_index, ARRAY_SIZE(fip_part_names)); + return false; + } +- const partition_entry_t *fip_entry = +- get_partition_entry(fip_part_names[boot_index]); +- if (fip_entry == NULL) { ++ ++ struct partition_entry_t fip_entry; ++ char unicode_name[GPT_ENTRY_NAME_LENGTH] = {'\0'}; ++ ascii_to_unicode(fip_part_names[boot_index], unicode_name); ++ psa_status_t ret = gpt_entry_read_by_name( ++ unicode_name, ++ 0, ++ &fip_entry); ++ if (ret == PSA_ERROR_DOES_NOT_EXIST) { ++ BOOT_LOG_ERR("Could not find partition %s", fip_part_names[boot_index]); ++ return false; ++ } else if (ret == PSA_ERROR_STORAGE_FAILURE) { ++ BOOT_LOG_ERR("%s: I/O error occurred with flash device", __func__); ++ return false; ++ } else if (ret < 0) { + BOOT_LOG_ERR("Could not find partition %s", fip_part_names[boot_index]); + return false; + } + +- fip_offset = fip_entry->start; +- fip_size = fip_entry->length; ++ fip_offset = fip_entry.start * TFM_GPT_BLOCK_SIZE; ++ fip_size = fip_entry.size * TFM_GPT_BLOCK_SIZE; + + /* parse directly from flash using XIP mode */ + /* FIP is large so its not a good idea to load it in memory */ +@@ -130,20 +165,21 @@ int32_t boot_platform_init(void) + } + + plat_io_storage_init(); +- partition_init(PLATFORM_GPT_IMAGE); ++ gpt_init(&io_gpt_flash_driver, PLAT_GPT_MAX_PARTITIONS); + + boot_index = bl2_get_boot_bank(); + ++ result = 0; + if (!fill_flash_map_with_tfm_data(boot_index) + #ifndef TFM_S_REG_TEST + || !fill_flash_map_with_fip_data(boot_index) + #endif + ) { + BOOT_LOG_ERR("Filling flash map has failed!"); +- return 1; ++ result = 1; + } + +- return 0; ++ return result; + } + + int32_t boot_platform_post_init(void) +@@ -223,5 +259,6 @@ void boot_platform_start_next_image(struct boot_arm_vector_table *vt) + __DSB(); + __ISB(); + ++ gpt_uninit(); + boot_jump_to_next_image(vt_cpy->reset); + } +diff --git a/platform/ext/target/arm/corstone1000/bootloader/fwu_agent.h b/platform/ext/target/arm/corstone1000/bootloader/fwu_agent.h +index aa5af15b2..4393f5f7b 100644 +--- a/platform/ext/target/arm/corstone1000/bootloader/fwu_agent.h ++++ b/platform/ext/target/arm/corstone1000/bootloader/fwu_agent.h +@@ -9,7 +9,8 @@ + #define FWU_AGENT_H + + #include "psa/error.h" +-#include "../fip_parser/external/uuid.h" ++#include "efi_guid_structs.h" ++#include "gpt.h" + + #define ENABLE_FWU_AGENT_DEBUG_LOGS + #ifdef ENABLE_FWU_AGENT_DEBUG_LOGS +@@ -29,6 +30,9 @@ + /* Version used for the very first image of the device. */ + #define FWU_IMAGE_INITIAL_VERSION 0 + ++/* Maximum ascii name length of image */ ++#define FWU_IMAGE_NAME_LENGTH (GPT_ENTRY_NAME_LENGTH >> 1) ++ + #define EFI_SYSTEM_RESOURCE_TABLE_FIRMWARE_RESOURCE_VERSION 1 + typedef struct { + uint32_t signature; +@@ -43,21 +47,24 @@ typedef struct { + size_t image_size_recvd; + } __packed fmp_header_image_info_t; + +-/* Store image information common for both the banks */ ++/* Image information common for both the banks */ + typedef struct { + /* Total size of the image */ + uint32_t image_size; + +- /* Offset of image within a bank */ ++ /* Offset of image within a bank. */ + uint32_t image_offset; + +- /* Image GUID */ +- struct efi_guid image_guid; +-} __packed fwu_bank_image_info_t; ++ /* Name of the image in ascii */ ++ char image_name[FWU_IMAGE_NAME_LENGTH]; ++ ++ /* Image-type GUID */ ++ struct efi_guid_t image_type; ++} fwu_image_info_t; + + /* ESRT v1 */ + struct __attribute__((__packed__)) efi_system_resource_entry { +- struct efi_guid fw_class; ++ struct efi_guid_t fw_class; + uint32_t fw_type; + uint32_t fw_version; + uint32_t lowest_supported_fw_version; +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 dc7503d41..5e1c4ecc5 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 +@@ -4,17 +4,19 @@ + * SPDX-License-Identifier: BSD-3-Clause + * + */ ++#include + #include + #include "psa/crypto.h" + #include "psa/error.h" + #include "tfm_bootloader_fwu_abstraction.h" ++#include "efi_soft_crc.h" + + #include + #include + #include "fwu_agent.h" + #include "Driver_Flash.h" ++#include "efi_guid_structs.h" + #include "flash_layout.h" +-#include "fip_parser/external/uuid.h" + #include "region_defs.h" + #include "flash_common.h" + #include "platform_base_address.h" +@@ -23,10 +25,10 @@ + #include "tfm_plat_defs.h" + #include "uefi_fmp.h" + #include "uart_stdout.h" +-#include "soft_crc.h" + #ifndef BL1_BUILD +-#include "partition.h" ++#include "gpt.h" + #include "platform.h" ++#include "io_gpt.h" + #endif + + #define FWU_METADATA_VERSION 2 +@@ -72,7 +74,7 @@ + struct fwu_image_properties { + + /* The UUID of the image in this bank */ +- uuid_t img_uuid; ++ struct efi_guid_t img_uuid; + + /* [0]: bit describing the image acceptance status – + * status - 1 means the image is accepted +@@ -90,10 +92,10 @@ struct fwu_image_properties { + struct fwu_image_entry { + + /* The UUID identifying the image type */ +- uuid_t img_type_uuid; ++ struct efi_guid_t img_type_uuid; + + /* The UUID of the storage volume where the image is located */ +- uuid_t location_uuid; ++ struct efi_guid_t location_uuid; + + /* The Properties of images with img_type_uuid in the different FW banks */ + struct fwu_image_properties img_props[NR_OF_FW_BANKS]; +@@ -206,99 +208,114 @@ struct __attribute__((__packed__)) fwu_esrt_data_wrapper { + * The GUIDs are generating with the UUIDv5 format. + * Namespace used for FVP GUIDs: 989f3a4e-46e0-4cd0-9877-a25c70c01329 + * Namespace used for MPS3 GUIDs: df1865d1-90fb-4d59-9c38-c9f2c1bba8cc +- * Names: the image names stated in the fw_name field + */ +-fwu_bank_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = { ++const fwu_image_info_t fwu_image[NR_OF_IMAGES_IN_FW_BANK] = { + #if PLATFORM_IS_FVP + // FVP payloads GUIDs +- // bl2_signed + { ++ .image_name = "bl2_secondary", + .image_size = SE_BL2_PARTITION_SIZE, + .image_offset = SE_BL2_PARTITION_BANK_OFFSET, +- .image_guid = { ++ .image_type = { + .time_low = 0xf1d883f9, + .time_mid = 0xdfeb, + .time_hi_and_version = 0x5363, +- .clock_seq_and_node = {0x98, 0xd8, 0x68, 0x6e, 0xe3, 0xb6, 0x9f, 0x4f} ++ .clock_seq_hi_and_reserved = 0x98, ++ .clock_seq_low = 0xd8, ++ .node = {0x68, 0x6e, 0xe3, 0xb6, 0x9f, 0x4f} + }, + }, +- // tfm_s_signed + { ++ .image_name = "tfm_secondary", + .image_size = TFM_PARTITION_SIZE, + .image_offset = TFM_PARTITION_BANK_OFFSET, +- .image_guid = { ++ .image_type = { + .time_low = 0x7fad470e, + .time_mid = 0x5ec5, + .time_hi_and_version = 0x5c03, +- .clock_seq_and_node = {0xa2, 0xc1, 0x47, 0x56, 0xb4, 0x95, 0xde, 0x61} ++ .clock_seq_hi_and_reserved = 0xa2, ++ .clock_seq_low = 0xc1, ++ .node = {0x47, 0x56, 0xb4, 0x95, 0xde, 0x61} + }, + }, +- // signed_fip-corstone1000 + { ++ .image_name = "FIP_B", + .image_size = FIP_PARTITION_SIZE, + .image_offset = FIP_PARTITION_BANK_OFFSET, +- .image_guid = { ++ .image_type = { + .time_low = 0xf1933675, + .time_mid = 0x5a8c, + .time_hi_and_version = 0x5b6d, +- .clock_seq_and_node = {0x9e, 0xf4, 0x84, 0x67, 0x39, 0xe8, 0x9b, 0xc8} ++ .clock_seq_hi_and_reserved = 0x9e, ++ .clock_seq_low = 0xf4, ++ .node = {0x84, 0x67, 0x39, 0xe8, 0x9b, 0xc8} + }, + }, +- // Image.gz-initramfs-corstone1000-fvp + { ++ .image_name = "kernel_secondary", + .image_size = INITRAMFS_PARTITION_SIZE, + .image_offset = INITRAMFS_PARTITION_BANK_OFFSET, +- .image_guid = { ++ .image_type = { + .time_low = 0xf771aff9, + .time_mid = 0xc7e9, + .time_hi_and_version = 0x5f99, +- .clock_seq_and_node = {0x9e, 0xda, 0x23, 0x69, 0xdd, 0x69, 0x4f, 0x61} ++ .clock_seq_hi_and_reserved = 0x9e, ++ .clock_seq_low = 0xda, ++ .node = {0x23, 0x69, 0xdd, 0x69, 0x4f, 0x61} + }, + }, + #else + // MPS3 payloads GUIDs +- // bl2_signed payload GUID + { ++ .image_name = "bl2_secondary", + .image_size = SE_BL2_PARTITION_SIZE, + .image_offset = SE_BL2_PARTITION_BANK_OFFSET, +- .image_guid = { ++ .image_type = { + .time_low = 0xfbfbefaa, + .time_mid = 0x0a56, + .time_hi_and_version = 0x50d5, +- .clock_seq_and_node = {0xb6, 0x51, 0x74, 0x09, 0x1d, 0x3d, 0x62, 0xcf} ++ .clock_seq_hi_and_reserved = 0xb6, ++ .clock_seq_low = 0x51, ++ .node = {0x74, 0x09, 0x1d, 0x3d, 0x62, 0xcf} + }, + }, +- // tfm_s_signed + { ++ .image_name = "tfm_secondary", + .image_size = TFM_PARTITION_SIZE, + .image_offset = TFM_PARTITION_BANK_OFFSET, +- .image_guid = { ++ .image_type = { + .time_low = 0xaf4cc7ad, + .time_mid = 0xee2e, + .time_hi_and_version = 0x5a39, +- .clock_seq_and_node = {0xaa, 0xd5, 0xfa, 0xc8, 0xa1, 0xe6, 0x17, 0x3c} +- }, ++ .clock_seq_hi_and_reserved = 0xaa, ++ .clock_seq_low = 0xd5, ++ .node = {0xfa, 0xc8, 0xa1, 0xe6, 0x17, 0x3c} ++ } + }, +- // signed_fip-corstone1000 + { ++ .image_name = "FIP_B", + .image_size = FIP_PARTITION_SIZE, + .image_offset = FIP_PARTITION_BANK_OFFSET, +- .image_guid = { ++ .image_type = { + .time_low = 0x55302f96, + .time_mid = 0xc4f0, + .time_hi_and_version = 0x5cf9, +- .clock_seq_and_node = {0x86, 0x24, 0xe7, 0xcc, 0x38, 0x8f, 0x2b, 0x68} +- }, ++ .clock_seq_hi_and_reserved = 0x86, ++ .clock_seq_low = 0x24, ++ .node = {0xe7, 0xcc, 0x38, 0x8f, 0x2b, 0x68} ++ } + }, +- // Image.gz-initramfs-corstone1000-mps3 + { ++ .image_name = "kernel_secondary", + .image_size = INITRAMFS_PARTITION_SIZE, + .image_offset = INITRAMFS_PARTITION_BANK_OFFSET, +- .image_guid = { ++ .image_type = { + .time_low = 0x3e8ac972, + .time_mid = 0xc33c, + .time_hi_and_version = 0x5cc9, +- .clock_seq_and_node = {0x90, 0xa0, 0xcd, 0xd3, 0x15, 0x96, 0x83, 0xea} ++ .clock_seq_hi_and_reserved = 0x90, ++ .clock_seq_low = 0xa0, ++ .node = {0xcd, 0xd3, 0x15, 0x96, 0x83, 0xea} + }, + }, + #endif +@@ -370,8 +387,8 @@ static psa_status_t private_metadata_read( + static psa_status_t private_metadata_read( + struct fwu_private_metadata* priv_metadata) + { +- partition_entry_t *part; +- uuid_t private_uuid = PRIVATE_METADATA_TYPE_UUID; ++ struct partition_entry_t part; ++ struct efi_guid_t private_uuid = PRIVATE_METADATA_TYPE_UUID; + + FWU_LOG_FUNC_ENTER; + +@@ -380,13 +397,19 @@ static psa_status_t private_metadata_read( + return PSA_ERROR_INVALID_ARGUMENT; + } + +- part = get_partition_entry_by_type(&private_uuid); +- if (!part) { ++ psa_status_t ret = gpt_entry_read_by_type(&private_uuid, 0, &part); ++ if (ret == PSA_ERROR_DOES_NOT_EXIST) { + FWU_LOG_MSG("Private metadata partition not found\n\r"); +- return PSA_ERROR_GENERIC_ERROR; ++ return ret; ++ } else if (ret == PSA_ERROR_STORAGE_FAILURE) { ++ FWU_LOG_MSG("%s : ERROR - flash failure reading private metadata\n\r", __func__); ++ return ret; ++ } else if (ret < 0) { ++ FWU_LOG_MSG("Unable to find private metadata partition, ret: %d\n\r", ret); ++ return ret; + } + +- int ret = FWU_METADATA_FLASH_DEV.ReadData(part->start, priv_metadata, ++ ret = FWU_METADATA_FLASH_DEV.ReadData(part.start * TFM_GPT_BLOCK_SIZE, priv_metadata, + sizeof(*priv_metadata)); + if (ret < 0) { + FWU_LOG_MSG("%s: ERROR - Flash read failed (ret = %d)\n\r", __func__, ret); +@@ -444,8 +467,8 @@ static psa_status_t private_metadata_write( + static psa_status_t private_metadata_write( + struct fwu_private_metadata* priv_metadata) + { +- uuid_t private_uuid = PRIVATE_METADATA_TYPE_UUID; +- partition_entry_t *part; ++ struct efi_guid_t private_uuid = PRIVATE_METADATA_TYPE_UUID; ++ struct partition_entry_t part; + + FWU_LOG_MSG("%s: enter: boot_index = %u\n\r", __func__, + priv_metadata->boot_index); +@@ -455,19 +478,25 @@ static psa_status_t private_metadata_write( + return PSA_ERROR_INVALID_ARGUMENT; + } + +- part = get_partition_entry_by_type(&private_uuid); +- if (!part) { ++ psa_status_t ret = gpt_entry_read_by_type(&private_uuid, 0, &part); ++ if (ret == PSA_ERROR_DOES_NOT_EXIST) { + FWU_LOG_MSG("Private metadata partition not found\n\r"); +- return PSA_ERROR_GENERIC_ERROR; ++ return ret; ++ } else if (ret == PSA_ERROR_STORAGE_FAILURE) { ++ FWU_LOG_MSG("%s: ERROR - flash failure reading private metadata\n\r", __func__); ++ return ret; ++ } else if (ret < 0) { ++ FWU_LOG_MSG("Unable to find private metadata partition, ret: %d\n\r", ret); ++ return ret; + } + +- int ret = FWU_METADATA_FLASH_DEV.EraseSector(part->start); ++ ret = FWU_METADATA_FLASH_DEV.EraseSector(part.start * TFM_GPT_BLOCK_SIZE); + if (ret != ARM_DRIVER_OK) { + FWU_LOG_MSG("%s: ERROR - Flash erase failed (ret = %d)\n\r", __func__, ret); + return PSA_ERROR_STORAGE_FAILURE; + } + +- ret = FWU_METADATA_FLASH_DEV.ProgramData(part->start, ++ ret = FWU_METADATA_FLASH_DEV.ProgramData(part.start * TFM_GPT_BLOCK_SIZE, + priv_metadata, sizeof(*priv_metadata)); + if (ret < 0) { + FWU_LOG_MSG("%s: ERROR - Flash write failed (ret = %d)\n\r", __func__, ret); +@@ -494,8 +523,10 @@ static psa_status_t metadata_validate(struct fwu_metadata *metadata) + return PSA_ERROR_INVALID_ARGUMENT; + } + +- uint32_t calculated_crc32 = crc32((uint8_t *)&(metadata->version), +- sizeof(*metadata) - sizeof(uint32_t)); ++ uint32_t calculated_crc32 = efi_soft_crc32_update( ++ 0, ++ (uint8_t *)&(metadata->version), ++ sizeof(*metadata) - sizeof(uint32_t)); + + if (metadata->crc_32 != calculated_crc32) { + FWU_LOG_MSG("%s: failed: crc32 calculated: 0x%x, given: 0x%x\n\r", __func__, +@@ -558,8 +589,8 @@ static psa_status_t metadata_read(struct fwu_metadata *metadata, uint8_t replica + #else + static psa_status_t metadata_read(struct fwu_metadata *metadata, uint8_t replica_num) + { +- uuid_t metadata_uuid = FWU_METADATA_TYPE_UUID; +- partition_entry_t *part; ++ struct efi_guid_t metadata_uuid = FWU_METADATA_TYPE_UUID; ++ struct partition_entry_t part; + + FWU_LOG_FUNC_ENTER; + +@@ -568,24 +599,32 @@ static psa_status_t metadata_read(struct fwu_metadata *metadata, uint8_t replica + return PSA_ERROR_INVALID_ARGUMENT; + } + +- if (replica_num == 1) { +- part = get_partition_entry_by_type(&metadata_uuid); +- } else if (replica_num == 2) { +- part = get_partition_replica_by_type(&metadata_uuid); +- } else { ++ psa_status_t ret; ++ switch (replica_num) { ++ case 1: ++ case 2: ++ ret = gpt_entry_read_by_type(&metadata_uuid, replica_num - 1, &part); ++ break; ++ default: + FWU_LOG_MSG("%s: replica_num must be 1 or 2\n\r", __func__); + return PSA_ERROR_GENERIC_ERROR; + } + +- if (!part) { ++ if (ret == PSA_ERROR_DOES_NOT_EXIST) { + FWU_LOG_MSG("%s: FWU metadata partition not found\n\r", __func__); +- return PSA_ERROR_GENERIC_ERROR; ++ return ret; ++ } else if (ret == PSA_ERROR_STORAGE_FAILURE) { ++ FWU_LOG_MSG("%s: ERROR - flash failure reading private metadata\n\r", __func__); ++ return ret; ++ } else if (ret < 0) { ++ FWU_LOG_MSG("%s: Unable to find FWU partition, ret: %d\n\r", __func__, ret); ++ return ret; + } + + FWU_LOG_MSG("%s: enter: flash addr = %u, size = %d\n\r", __func__, +- part->start, sizeof(*metadata)); ++ part.start * TFM_GPT_BLOCK_SIZE, sizeof(*metadata)); + +- int ret = FWU_METADATA_FLASH_DEV.ReadData(part->start, ++ ret = FWU_METADATA_FLASH_DEV.ReadData(part.start * TFM_GPT_BLOCK_SIZE, + metadata, sizeof(*metadata)); + if (ret < 0) { + FWU_LOG_MSG("%s: ERROR - Flash read failed (ret = %d)\n\r", __func__, ret); +@@ -663,8 +702,8 @@ static psa_status_t metadata_write( + static psa_status_t metadata_write( + struct fwu_metadata *metadata, uint8_t replica_num) + { +- uuid_t metadata_uuid = FWU_METADATA_TYPE_UUID; +- partition_entry_t *part; ++ struct efi_guid_t metadata_uuid = FWU_METADATA_TYPE_UUID; ++ struct partition_entry_t part; + + FWU_LOG_FUNC_ENTER; + +@@ -673,30 +712,38 @@ static psa_status_t metadata_write( + return PSA_ERROR_INVALID_ARGUMENT; + } + +- if (replica_num == 1) { +- part = get_partition_entry_by_type(&metadata_uuid); +- } else if (replica_num == 2) { +- part = get_partition_replica_by_type(&metadata_uuid); +- } else { ++ psa_status_t ret; ++ switch (replica_num) { ++ case 1: ++ case 2: ++ ret = gpt_entry_read_by_type(&metadata_uuid, replica_num - 1, &part); ++ break; ++ default: + FWU_LOG_MSG("%s: replica_num must be 1 or 2\n\r", __func__); + return PSA_ERROR_GENERIC_ERROR; + } + +- if (!part) { ++ if (ret == PSA_ERROR_DOES_NOT_EXIST) { + FWU_LOG_MSG("%s: FWU metadata partition not found\n\r", __func__); +- return PSA_ERROR_GENERIC_ERROR; ++ return ret; ++ } else if (ret == PSA_ERROR_STORAGE_FAILURE) { ++ FWU_LOG_MSG("%s: ERROR - flash failure reading private metadata\n\r", __func__); ++ return PSA_ERROR_STORAGE_FAILURE; ++ } else if (ret < 0) { ++ FWU_LOG_MSG("%s: Unable to find FWU partition, ret: %d\n\r", __func__, ret); ++ return ret; + } + + FWU_LOG_MSG("%s: enter: flash addr = %u, size = %d\n\r", __func__, +- part->start, sizeof(*metadata)); ++ part.start * TFM_GPT_BLOCK_SIZE, sizeof(*metadata)); + +- int ret = FWU_METADATA_FLASH_DEV.EraseSector(part->start); ++ ret = FWU_METADATA_FLASH_DEV.EraseSector(part.start * TFM_GPT_BLOCK_SIZE); + if (ret != ARM_DRIVER_OK) { + FWU_LOG_MSG("%s: ERROR - Flash erase failed (ret = %d)\n\r", __func__, ret); + return PSA_ERROR_STORAGE_FAILURE; + } + +- ret = FWU_METADATA_FLASH_DEV.ProgramData(part->start, ++ ret = FWU_METADATA_FLASH_DEV.ProgramData(part.start * TFM_GPT_BLOCK_SIZE, + metadata, sizeof(*metadata)); + if (ret < 0) { + FWU_LOG_MSG("%s: ERROR - Flash write failed (ret = %d)\n\r", __func__, ret); +@@ -733,8 +780,41 @@ static psa_status_t metadata_write_both_replica( + return PSA_SUCCESS; + } + ++#ifndef BL1_BUILD ++/* Ensure both GPT headers are valid */ ++psa_status_t ensure_gpt_headers_valid(void) ++{ ++ psa_status_t ret = gpt_validate(true); ++ if (ret == PSA_ERROR_INVALID_SIGNATURE) { ++ ret = gpt_restore(true); ++ if (ret == PSA_ERROR_INVALID_SIGNATURE) { ++ FWU_LOG_MSG("Invalid primary GPT\r\n"); ++ return ret; ++ } ++ } ++ ++ ret = gpt_validate(false); ++ if (ret == PSA_ERROR_INVALID_SIGNATURE) { ++ ret = gpt_restore(false); ++ if (ret == PSA_ERROR_INVALID_SIGNATURE) { ++ FWU_LOG_MSG("Invalid primary GPT\r\n"); ++ return ret; ++ } ++ } ++ ++ return PSA_SUCCESS; ++} ++#endif /* BL1_BUILD */ ++ + psa_status_t fwu_metadata_check_and_correct_integrity(void) + { ++#ifndef BL1_BUILD ++ psa_status_t ret = ensure_gpt_headers_valid(); ++ if (ret != PSA_SUCCESS) { ++ return ret; ++ } ++#endif ++ + psa_status_t ret_replica_1 = PSA_ERROR_GENERIC_ERROR; + psa_status_t ret_replica_2 = PSA_ERROR_GENERIC_ERROR; + +@@ -760,14 +840,22 @@ psa_status_t fwu_metadata_init(void) + psa_status_t ret; + ARM_FLASH_INFO* flash_info; + ++ if (is_initialized) { ++ return PSA_SUCCESS; ++ } ++ + #ifndef BL1_BUILD + plat_io_storage_init(); +- partition_init(PLATFORM_GPT_IMAGE); +-#endif ++ ret = gpt_init(&io_gpt_flash_driver, PLAT_MAX_PARTITION_ENTRIES); ++ if (ret < 0) { ++ return ret; ++ } + +- if (is_initialized) { +- return PSA_SUCCESS; ++ ret = ensure_gpt_headers_valid(); ++ if (ret != PSA_SUCCESS) { ++ return ret; + } ++#endif + + /* Code assumes everything fits into a sector */ + if (sizeof(struct fwu_metadata) > FWU_METADATA_FLASH_SECTOR_SIZE) { +@@ -830,17 +918,19 @@ static psa_status_t fwu_metadata_configure(void) + + _metadata.fw_desc.img_entry[i].img_props[BANK_0].accepted = IMAGE_ACCEPTED; + _metadata.fw_desc.img_entry[i].img_props[BANK_0].version = image_version; +- memcpy(&(_metadata.fw_desc.img_entry[i].img_props[BANK_0].img_uuid), (const void *)&fwu_image[i].image_guid, sizeof(struct efi_guid)); ++ memcpy(&(_metadata.fw_desc.img_entry[i].img_props[BANK_0].img_uuid), (const void *)&fwu_image[i].image_type, sizeof(struct efi_guid_t)); + + _metadata.fw_desc.img_entry[i].img_props[BANK_1].accepted = INVALID_IMAGE; + _metadata.fw_desc.img_entry[i].img_props[BANK_1].version = INVALID_VERSION; +- memcpy(&(_metadata.fw_desc.img_entry[i].img_props[BANK_1].img_uuid), (const void *)&fwu_image[i].image_guid, sizeof(struct efi_guid)); ++ memcpy(&(_metadata.fw_desc.img_entry[i].img_props[BANK_1].img_uuid), (const void *)&fwu_image[i].image_type, sizeof(struct efi_guid_t)); + } + + /* Calculate CRC32 for fwu metadata. The first filed in the _metadata has to be the crc_32. + * This should be omited from the calculation. */ +- _metadata.crc_32 = crc32((uint8_t *)&_metadata.version, +- sizeof(struct fwu_metadata) - sizeof(uint32_t)); ++ _metadata.crc_32 = efi_soft_crc32_update( ++ 0, ++ (uint8_t *)&_metadata.version, ++ sizeof(struct fwu_metadata) - sizeof(uint32_t)); + + ret = metadata_write_both_replica(&_metadata); + if (ret) { +@@ -1045,8 +1135,10 @@ static psa_status_t fwu_select_previous( + if (ret) { + return ret; + } +- metadata->crc_32 = crc32((uint8_t *)&metadata->version, +- sizeof(struct fwu_metadata) - sizeof(uint32_t)); ++ metadata->crc_32 = efi_soft_crc32_update( ++ 0, ++ (uint8_t *)&metadata->version, ++ sizeof(struct fwu_metadata) - sizeof(uint32_t)); + + ret = metadata_write_both_replica(metadata); + if (ret) { +@@ -1243,7 +1335,7 @@ 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, ++ fmp_set_image_info(&fwu_image[i].image_type, + priv_metadata.fmp_version[i], + priv_metadata.fmp_last_attempt_version[i], + priv_metadata.fmp_last_attempt_status[i]); +@@ -1274,7 +1366,7 @@ psa_status_t corstone1000_fwu_host_ack(void) + if (ret == PSA_SUCCESS) { + disable_host_ack_timer(); + for (int i = 0; i < NR_OF_IMAGES_IN_FW_BANK; i++) { +- fmp_set_image_info(&fwu_image[i].image_guid, ++ fmp_set_image_info(&fwu_image[i].image_type, + priv_metadata.fmp_version[i], + priv_metadata.fmp_last_attempt_version[i], + priv_metadata.fmp_last_attempt_status[i]); +@@ -1428,7 +1520,7 @@ static psa_status_t get_esrt_data(struct fwu_esrt_data_wrapper *esrt) + + for (int i = 0; i < NR_OF_IMAGES_IN_FW_BANK; i++) + { +- memcpy(&esrt->entries[i].fw_class, &fwu_image[i].image_guid, sizeof(struct efi_guid)); ++ memcpy(&esrt->entries[i].fw_class, &fwu_image[i].image_type, sizeof(struct efi_guid_t)); + esrt->entries[i].fw_version = priv_metadata.fmp_version[i]; + esrt->entries[i].lowest_supported_fw_version = FWU_IMAGE_INITIAL_VERSION; + esrt->entries[i].last_attempt_version = priv_metadata.fmp_last_attempt_version[i]; +@@ -1491,8 +1583,10 @@ static psa_status_t fwu_accept_image(struct fwu_metadata *metadata, + if (ret) { + return ret; + } +- metadata->crc_32 = crc32((uint8_t *)&metadata->version, +- sizeof(struct fwu_metadata) - sizeof(uint32_t)); ++ metadata->crc_32 = efi_soft_crc32_update( ++ 0, ++ (uint8_t *)&metadata->version, ++ sizeof(struct fwu_metadata) - sizeof(uint32_t)); + + ret = metadata_write_both_replica(metadata); + if (ret) { +@@ -1658,9 +1752,7 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component, + psa_status_t ret; + int drv_ret; + int image_index; +- uint32_t bank_offset; + uint32_t active_index; +- uint32_t previous_active_index; + uint32_t nr_images; + uint32_t current_state; + uint32_t image_offset; +@@ -1717,7 +1809,7 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component, + priv_metadata.fmp_last_attempt_status[fwu_image_index] = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL; + private_metadata_write(&priv_metadata); + +- fmp_set_image_info(&fwu_image[fwu_image_index].image_guid, ++ fmp_set_image_info(&fwu_image[fwu_image_index].image_type, + priv_metadata.fmp_version[fwu_image_index], + priv_metadata.fmp_last_attempt_version[fwu_image_index], + priv_metadata.fmp_last_attempt_status[fwu_image_index]); +@@ -1727,11 +1819,11 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component, + goto out; + } + ++#ifdef BL1_BUILD ++ uint32_t bank_offset; + if (active_index == BANK_0) { +- previous_active_index = BANK_1; + bank_offset = BANK_1_PARTITION_OFFSET; + } else if (active_index == BANK_1) { +- previous_active_index = BANK_0; + bank_offset = BANK_0_PARTITION_OFFSET; + } else { + FWU_LOG_MSG("ERROR: %s: active_index %d\n\r",__func__,active_index); +@@ -1740,6 +1832,38 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component, + } + + image_offset = bank_offset + fwu_image[fwu_image_index].image_offset; ++#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_DATA_INVALID; ++ goto out; ++ } ++ ++ ret = gpt_entry_read_by_type(&(fwu_image[fwu_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[fwu_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[fwu_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[fwu_image_index].image_names[previous_active_index], ret); ++ goto out; ++ } ++ ++ image_offset = part.start * TFM_GPT_BLOCK_SIZE; ++#endif /* BL1_BUILD */ + + /* Firmware update process can only start in regular state. */ + current_state = get_fwu_image_state(&_metadata, &priv_metadata, fwu_image_index); +@@ -1762,7 +1886,7 @@ psa_status_t fwu_bootloader_load_image(psa_fwu_component_t component, + + private_metadata_write(&priv_metadata); + +- fmp_set_image_info(&fwu_image[fwu_image_index].image_guid, ++ fmp_set_image_info(&fwu_image[fwu_image_index].image_type, + priv_metadata.fmp_version[fwu_image_index], + priv_metadata.fmp_last_attempt_version[fwu_image_index], + priv_metadata.fmp_last_attempt_status[fwu_image_index]); +@@ -1828,8 +1952,10 @@ static psa_status_t fwu_update_metadata(const psa_fwu_component_t *candidates, u + _metadata.fw_desc.img_entry[fwu_image_index].img_props[previous_active_index].version = fmp_header_image_info[fwu_image_index].fmp_hdr.fw_version; + } + +- _metadata.crc_32 = crc32((uint8_t *)&_metadata.version, +- sizeof(struct fwu_metadata) - sizeof(uint32_t)); ++ _metadata.crc_32 = efi_soft_crc32_update( ++ 0, ++ (uint8_t *)&_metadata.version, ++ sizeof(struct fwu_metadata) - sizeof(uint32_t)); + + ret = metadata_write_both_replica(&_metadata); + if (ret) { +@@ -1960,8 +2086,10 @@ static psa_status_t maintain_bank_consistency(void) + goto out; + } + +- _metadata.crc_32 = crc32((uint8_t *)&_metadata.version, +- sizeof(struct fwu_metadata) - sizeof(uint32_t)); ++ _metadata.crc_32 = efi_soft_crc32_update( ++ 0, ++ (uint8_t *)&_metadata.version, ++ sizeof(struct fwu_metadata) - sizeof(uint32_t)); + + ret = metadata_write_both_replica(&_metadata); + if (ret) { +@@ -2057,7 +2185,7 @@ psa_status_t fwu_bootloader_mark_image_accepted(const psa_fwu_component_t *trial + + current_state = get_fwu_image_state(&_metadata, &priv_metadata, fwu_image_index); + if (current_state == PSA_FWU_READY) { +- fmp_set_image_info(&fwu_image[fwu_image_index].image_guid, ++ fmp_set_image_info(&fwu_image[fwu_image_index].image_type, + priv_metadata.fmp_version[fwu_image_index], + priv_metadata.fmp_last_attempt_version[fwu_image_index], + priv_metadata.fmp_last_attempt_status[fwu_image_index]); +@@ -2091,7 +2219,7 @@ psa_status_t fwu_bootloader_mark_image_accepted(const psa_fwu_component_t *trial + } + + fwu_image_index = trials[i] - FWU_FAKE_IMAGES_INDEX_COUNT; +- fmp_set_image_info(&fwu_image[fwu_image_index].image_guid, ++ fmp_set_image_info(&fwu_image[fwu_image_index].image_type, + priv_metadata.fmp_version[fwu_image_index], + priv_metadata.fmp_last_attempt_version[fwu_image_index], + priv_metadata.fmp_last_attempt_status[fwu_image_index]); +@@ -2107,7 +2235,6 @@ out: + /* Reject the staged image. */ + psa_status_t fwu_bootloader_reject_staged_image(psa_fwu_component_t component) + { +- + if (!is_image_index_valid(component)) { + FWU_LOG_MSG("%s: Invalid image index received \n\r", __func__); + return PSA_ERROR_INVALID_ARGUMENT; +@@ -2224,7 +2351,6 @@ psa_status_t fwu_bootloader_get_image_info(psa_fwu_component_t component, + + FWU_LOG_FUNC_ENTER; + +- + Select_Write_Mode_For_Shared_Flash(); + if (private_metadata_read(&priv_metadata)) { + ret = PSA_ERROR_GENERIC_ERROR; +diff --git a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/uefi_fmp.c b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/uefi_fmp.c +index 3edd4ebd0..c41b1f9ea 100644 +--- a/platform/ext/target/arm/corstone1000/bootloader/mcuboot/uefi_fmp.c ++++ b/platform/ext/target/arm/corstone1000/bootloader/mcuboot/uefi_fmp.c +@@ -10,6 +10,7 @@ + #include "tfm_hal_device_header.h" + #include "uefi_fmp.h" + #include "flash_layout.h" ++#include "efi_guid_structs.h" + + /* The count will increase when partial update is supported. + * At present, only full WIC is considered as updatable image. +@@ -45,7 +46,7 @@ typedef uint8_t DescriptorCount_t; + + typedef __PACKED_STRUCT { + uint8_t ImageIndex; +- struct efi_guid ImageTypeId; ++ struct efi_guid_t ImageTypeId; + uint64_t ImageId; + uefi_ptr_t PtrImageIdName; + uint32_t Version; +@@ -101,7 +102,7 @@ struct corstone_image_info image_info[NUMBER_OF_FMP_IMAGES] = { + }; + static EFI_FIRMWARE_MANAGEMENT_PROTOCOL_IMAGE_INFO fmp_info[NUMBER_OF_FMP_IMAGES]; + +-extern fwu_bank_image_info_t fwu_image[]; ++extern const fwu_image_info_t fwu_image[]; + + static bool is_fmp_info_initialized = false; + +@@ -127,8 +128,8 @@ static void init_fmp_info(void) + + fmp_info[i].ImageDescriptor.ImageIndex = i+1; + +- memcpy(&fmp_info[i].ImageDescriptor.ImageTypeId, &fwu_image[i].image_guid, +- sizeof(struct efi_guid)); ++ memcpy(&fmp_info[i].ImageDescriptor.ImageTypeId, &fwu_image[i].image_type, ++ sizeof(struct efi_guid_t)); + + fmp_info[i].ImageDescriptor.ImageId = i+1; + fmp_info[i].ImageDescriptor.Version = FWU_IMAGE_INITIAL_VERSION; +@@ -150,7 +151,7 @@ static void init_fmp_info(void) + return; + } + +-psa_status_t fmp_set_image_info(struct efi_guid *guid, ++psa_status_t fmp_set_image_info(const struct efi_guid_t *guid, + uint32_t current_version, uint32_t attempt_version, + uint32_t last_attempt_status) + { +@@ -164,7 +165,7 @@ psa_status_t fmp_set_image_info(struct efi_guid *guid, + + for (int i = 0; i < NUMBER_OF_FMP_IMAGES; i++) { + if ((memcmp(guid, &fmp_info[i].ImageDescriptor.ImageTypeId, +- sizeof(struct efi_guid))) == 0) ++ sizeof(struct efi_guid_t))) == 0) + { + FWU_LOG_MSG("FMP image update: image id = %u\n\r", + fmp_info[i].ImageDescriptor.ImageId); +diff --git a/platform/ext/target/arm/corstone1000/bootloader/uefi_fmp.h b/platform/ext/target/arm/corstone1000/bootloader/uefi_fmp.h +index 36c604714..e185448ef 100644 +--- a/platform/ext/target/arm/corstone1000/bootloader/uefi_fmp.h ++++ b/platform/ext/target/arm/corstone1000/bootloader/uefi_fmp.h +@@ -11,7 +11,6 @@ + + #include + #include "fwu_agent.h" +-#include "../fip_parser/external/uuid.h" + + /* + * Last Attempt Status Value +@@ -40,7 +39,7 @@ + * attempt_version: attempted versions for the image + * + */ +-psa_status_t fmp_set_image_info(struct efi_guid *guid, ++psa_status_t fmp_set_image_info(const struct efi_guid_t *guid, + uint32_t current_version, uint32_t attempt_version, + uint32_t last_attempt_status); + +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 3b023c813..e92723026 100644 +--- a/platform/ext/target/arm/corstone1000/ci_regression_tests/CMakeLists.txt ++++ b/platform/ext/target/arm/corstone1000/ci_regression_tests/CMakeLists.txt +@@ -9,26 +9,18 @@ + + cmake_policy(SET CMP0079 NEW) + +-include(${CMAKE_CURRENT_SOURCE_DIR}/s_test_config.cmake) +- + ####################### Secure ################################################# + + target_sources(tfm_test_suite_extra_s + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/s_test.c + ../Native_Driver/firewall.c +- ../io/io_storage.c +- ../io/io_block.c +- ../io/io_flash.c +- Driver_Flash_SRAM_Emu.c +- s_io_storage_test.c + ) + + target_include_directories(tfm_test_suite_extra_s + PRIVATE + ../Device/Include + ../Native_Driver +- ../io + ) + + target_link_libraries(tfm_test_suite_extra_s +@@ -39,10 +31,6 @@ target_link_libraries(tfm_test_suite_extra_s + target_compile_definitions(tfm_test_suite_extra_s + PRIVATE + $<$:PLATFORM_IS_FVP> +- TEST_FLASH_SIZE_IN_BYTES=${TEST_FLASH_SIZE_IN_BYTES} +- TEST_FLASH_SECTOR_SIZE_IN_BYTES=${TEST_FLASH_SECTOR_SIZE_IN_BYTES} +- 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/ci_regression_tests/Driver_Flash_SRAM_Emu.c b/platform/ext/target/arm/corstone1000/ci_regression_tests/Driver_Flash_SRAM_Emu.c +deleted file mode 100644 +index 06b6b51c0..000000000 +--- a/platform/ext/target/arm/corstone1000/ci_regression_tests/Driver_Flash_SRAM_Emu.c ++++ /dev/null +@@ -1,327 +0,0 @@ +-/* +- * Copyright (c) 2013-2022 ARM Limited. All rights reserved. +- * +- * SPDX-License-Identifier: Apache-2.0 +- * +- * Licensed under the Apache License, Version 2.0 (the License); you may +- * not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an AS IS BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#include +-#include +-#include "Driver_Flash.h" +-#include "test_flash.h" +-#include "tfm_sp_log.h" +- +-#ifndef ARG_UNUSED +-#define ARG_UNUSED(arg) ((void)arg) +-#endif +- +-/* Driver version */ +-#define ARM_FLASH_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1, 1) +-#define ARM_FLASH_DRV_ERASE_VALUE 0xFF +- +- +-/** +- * There is no real flash memory. This driver just emulates a flash +- * interface and behaviour on top of the SRAM memory. +- */ +- +-/** +- * Data width values for ARM_FLASH_CAPABILITIES::data_width +- * \ref ARM_FLASH_CAPABILITIES +- */ +- enum { +- DATA_WIDTH_8BIT = 0u, +- DATA_WIDTH_16BIT, +- DATA_WIDTH_32BIT, +- DATA_WIDTH_ENUM_SIZE +-}; +- +-static const uint32_t data_width_byte[DATA_WIDTH_ENUM_SIZE] = { +- sizeof(uint8_t), +- sizeof(uint16_t), +- sizeof(uint32_t), +-}; +- +- +-/* +- * ARM FLASH device structure +- * +- */ +-struct arm_flash_dev_t { +- const uint8_t* memory_base; /*!< FLASH memory base address */ +- ARM_FLASH_INFO *data; /*!< FLASH data */ +-}; +- +-/* Flash emulated memory */ +-static uint8_t flash_memory[TEST_FLASH_SIZE_IN_BYTES] +- __attribute__((aligned(TEST_FLASH_SECTOR_SIZE_IN_BYTES))); +- +-/* Flash Status */ +-static ARM_FLASH_STATUS FlashStatus = {0, 0, 0}; +- +-/* Driver Version */ +-static const ARM_DRIVER_VERSION DriverVersion = { +- ARM_FLASH_API_VERSION, +- ARM_FLASH_DRV_VERSION +-}; +- +-/* Driver Capabilities */ +-static const ARM_FLASH_CAPABILITIES DriverCapabilities = { +- 0, /* event_ready */ +- 0, /* data_width = 0:8-bit, 1:16-bit, 2:32-bit */ +- 1 /* erase_chip */ +-}; +- +-static int32_t is_range_valid(struct arm_flash_dev_t *flash_dev, +- uint32_t offset) +-{ +- uint32_t flash_limit = 0; +- int32_t rc = 0; +- +- flash_limit = (flash_dev->data->sector_count * flash_dev->data->sector_size); +- if (offset > flash_limit) { +- rc = -1; +- } +- return rc; +-} +- +-static int32_t is_write_aligned(struct arm_flash_dev_t *flash_dev, +- uint32_t param) +-{ +- int32_t rc = 0; +- +- if ((param % flash_dev->data->program_unit) != 0) { +- rc = -1; +- } +- return rc; +-} +- +-static int32_t is_sector_aligned(struct arm_flash_dev_t *flash_dev, +- uint32_t offset) +-{ +- int32_t rc = 0; +- +- if ((offset % flash_dev->data->sector_size) != 0) { +- rc = -1; +- } +- return rc; +-} +- +-static int32_t is_flash_ready_to_write(const uint8_t *start_addr, uint32_t cnt) +-{ +- int32_t rc = 0; +- uint32_t i; +- +- for (i = 0; i < cnt; i++) { +- if(start_addr[i] != ARM_FLASH_DRV_ERASE_VALUE) { +- rc = -1; +- break; +- } +- } +- +- return rc; +-} +- +-static ARM_FLASH_INFO ARM_TEST_FLASH_DEV_DATA = { +- .sector_info = NULL,/* Uniform sector layout */ +- .sector_count = TEST_FLASH_SIZE_IN_BYTES / TEST_FLASH_SECTOR_SIZE_IN_BYTES, +- .sector_size = TEST_FLASH_SECTOR_SIZE_IN_BYTES, +- .page_size = TEST_FLASH_PAGE_SIZE, +- .program_unit = TEST_FLASH_PROGRAM_UNIT, +- .erased_value = ARM_FLASH_DRV_ERASE_VALUE}; +- +-static struct arm_flash_dev_t ARM_TEST_FLASH_DEV = { +- .memory_base = flash_memory, +- .data = &(ARM_TEST_FLASH_DEV_DATA)}; +- +-static struct arm_flash_dev_t *TEST_FLASH_DEV = &ARM_TEST_FLASH_DEV; +- +-/* +- * Functions +- */ +- +-static ARM_DRIVER_VERSION ARM_Flash_GetVersion(void) +-{ +- return DriverVersion; +-} +- +-static ARM_FLASH_CAPABILITIES ARM_Flash_GetCapabilities(void) +-{ +- return DriverCapabilities; +-} +- +-static int32_t ARM_Flash_Initialize(ARM_Flash_SignalEvent_t cb_event) +-{ +- ARG_UNUSED(cb_event); +- +- if (DriverCapabilities.data_width >= DATA_WIDTH_ENUM_SIZE) { +- return ARM_DRIVER_ERROR; +- } +- +- /* Nothing to be done */ +- return ARM_DRIVER_OK; +-} +- +-static int32_t ARM_Flash_Uninitialize(void) +-{ +- /* Nothing to be done */ +- return ARM_DRIVER_OK; +-} +- +-static int32_t ARM_Flash_PowerControl(ARM_POWER_STATE state) +-{ +- switch (state) { +- case ARM_POWER_FULL: +- /* Nothing to be done */ +- return ARM_DRIVER_OK; +- break; +- +- case ARM_POWER_OFF: +- case ARM_POWER_LOW: +- default: +- return ARM_DRIVER_ERROR_UNSUPPORTED; +- } +-} +- +-static int32_t ARM_Flash_ReadData(uint32_t addr, void *data, uint32_t cnt) +-{ +- int32_t rc = 0; +- +- /* The addr given is a relative address*/ +- uint32_t offset = addr; +- addr += (uint32_t)(TEST_FLASH_DEV->memory_base); +- +- /* Conversion between data items and bytes */ +- cnt *= data_width_byte[DriverCapabilities.data_width]; +- +- /* Check flash memory boundaries */ +- rc = is_range_valid(TEST_FLASH_DEV, offset + cnt); +- if (rc != 0) { +- return ARM_DRIVER_ERROR_PARAMETER; +- } +- +- /* Flash interface just emulated over SRAM, use memcpy */ +- memcpy(data, (void *)addr, cnt); +- +- /* Conversion between bytes and data items */ +- cnt /= data_width_byte[DriverCapabilities.data_width]; +- +- return cnt; +-} +- +-static int32_t ARM_Flash_ProgramData(uint32_t addr, const void *data, +- uint32_t cnt) +-{ +- int32_t rc = 0; +- +- /* The addr given is a relative address*/ +- uint32_t offset = addr; +- addr += (uint32_t)(TEST_FLASH_DEV->memory_base); +- +- /* Conversion between data items and bytes */ +- cnt *= data_width_byte[DriverCapabilities.data_width]; +- +- /* Check flash memory boundaries and alignment with minimal write size */ +- rc = is_range_valid(TEST_FLASH_DEV, offset + cnt); +- rc |= is_write_aligned(TEST_FLASH_DEV, offset); +- rc |= is_write_aligned(TEST_FLASH_DEV, cnt); +- if (rc != 0) { +- return ARM_DRIVER_ERROR_PARAMETER; +- } +- +- /* Check if the flash area to write the data was erased previously */ +- rc = is_flash_ready_to_write((const uint8_t*)addr, cnt); +- if (rc != 0) { +- return ARM_DRIVER_ERROR; +- } +- +- /* Flash interface just emulated over SRAM, use memcpy */ +- memcpy((void *)addr, data, cnt); +- +- /* Conversion between bytes and data items */ +- cnt /= data_width_byte[DriverCapabilities.data_width]; +- +- return cnt; +-} +- +-static int32_t ARM_Flash_EraseSector(uint32_t addr) +-{ +- uint32_t rc = 0; +- +- /* The addr given is a relative address*/ +- uint32_t offset = addr; +- addr += (uint32_t)(TEST_FLASH_DEV->memory_base); +- +- rc = is_range_valid(TEST_FLASH_DEV, offset); +- rc |= is_sector_aligned(TEST_FLASH_DEV, offset); +- if (rc != 0) { +- return ARM_DRIVER_ERROR_PARAMETER; +- } +- +- /* Flash interface just emulated over SRAM, use memset */ +- memset((void *)addr, +- TEST_FLASH_DEV->data->erased_value, +- TEST_FLASH_DEV->data->sector_size); +- return ARM_DRIVER_OK; +-} +- +-static int32_t ARM_Flash_EraseChip(void) +-{ +- uint32_t i; +- uint32_t addr = TEST_FLASH_DEV->memory_base; +- int32_t rc = ARM_DRIVER_ERROR_UNSUPPORTED; +- +- /* Check driver capability erase_chip bit */ +- if (DriverCapabilities.erase_chip == 1) { +- for (i = 0; i < TEST_FLASH_DEV->data->sector_count; i++) { +- /* Flash interface just emulated over SRAM, use memset */ +- memset((void *)addr, +- TEST_FLASH_DEV->data->erased_value, +- TEST_FLASH_DEV->data->sector_size); +- +- addr += TEST_FLASH_DEV->data->sector_size; +- rc = ARM_DRIVER_OK; +- } +- } +- return rc; +-} +- +-static ARM_FLASH_STATUS ARM_Flash_GetStatus(void) +-{ +- return FlashStatus; +-} +- +-static ARM_FLASH_INFO * ARM_Flash_GetInfo(void) +-{ +- return TEST_FLASH_DEV->data; +-} +- +- +-/* Global Variables */ +- +-ARM_DRIVER_FLASH Driver_TEST_FLASH = { +- ARM_Flash_GetVersion, +- ARM_Flash_GetCapabilities, +- ARM_Flash_Initialize, +- ARM_Flash_Uninitialize, +- ARM_Flash_PowerControl, +- ARM_Flash_ReadData, +- ARM_Flash_ProgramData, +- ARM_Flash_EraseSector, +- ARM_Flash_EraseChip, +- ARM_Flash_GetStatus, +- ARM_Flash_GetInfo +-}; +- +-uintptr_t flash_base_address = flash_memory; +diff --git a/platform/ext/target/arm/corstone1000/ci_regression_tests/s_io_storage_test.c b/platform/ext/target/arm/corstone1000/ci_regression_tests/s_io_storage_test.c +deleted file mode 100644 +index fb589c9d2..000000000 +--- a/platform/ext/target/arm/corstone1000/ci_regression_tests/s_io_storage_test.c ++++ /dev/null +@@ -1,147 +0,0 @@ +-/* +- * Copyright (c) 2022, Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- * +- */ +- +-#include +-#include "s_io_storage_test.h" +-#include "Driver_Flash.h" +-#include "flash_layout.h" +-#include "io_block.h" +-#include "io_driver.h" +-#include "io_flash.h" +-#include "tfm_sp_log.h" +- +-#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(*(array))) +- +-extern ARM_DRIVER_FLASH Driver_FLASH0; +-extern ARM_DRIVER_FLASH Driver_TEST_FLASH; +-extern uintptr_t flash_base_address; +- +-void s_test_io_storage_multiple_flash_simultaneous(struct test_result_t *ret) { +- /* FLASH0 */ +- static io_dev_connector_t* flash0_dev_con; +- static uint8_t local_block_flash0[FLASH_SECTOR_SIZE]; +- ARM_FLASH_INFO* flash0_info = Driver_FLASH0.GetInfo(); +- size_t flash0_block_size = flash0_info->sector_size; +- io_flash_dev_spec_t flash0_dev_spec = { +- .buffer = local_block_flash0, +- .bufferlen = flash0_block_size, +- .base_addr = FLASH_BASE_ADDRESS, +- .flash_driver = &Driver_FLASH0, +- }; +- io_block_spec_t flash0_spec = { +- .offset = FLASH_BASE_ADDRESS, +- .length = flash0_info->sector_count * flash0_info->sector_size}; +- uintptr_t flash0_dev_handle = NULL; +- uintptr_t flash0_handle = NULL; +- +- /* EMU TEST FLASH */ +- static io_dev_connector_t* flash_emu_dev_con; +- static uint8_t local_block_flash_emu[TEST_FLASH_SECTOR_SIZE_IN_BYTES] +- __attribute__((aligned(TEST_FLASH_SECTOR_SIZE_IN_BYTES))); +- ARM_FLASH_INFO* flash_emu_info = Driver_TEST_FLASH.GetInfo(); +- size_t flash_emu_block_size = flash_emu_info->sector_size; +- io_flash_dev_spec_t flash_emu_dev_spec = { +- .buffer = local_block_flash_emu, +- .bufferlen = flash_emu_block_size, +- .base_addr = flash_base_address, +- .flash_driver = &Driver_TEST_FLASH, +- }; +- io_block_spec_t flash_emu_spec = { +- .offset = flash_base_address, +- .length = flash_emu_info->sector_count * flash_emu_info->sector_size}; +- uintptr_t flash_emu_dev_handle = NULL; +- uintptr_t flash_emu_handle = NULL; +- +- /* Common */ +- int rc = -1; +- static uint8_t test_data[] = {0xEE, 0xDD, 0xCC, 0xBB, 0xAA, +- 0x10, 0x50, 0xA0, 0xD0, 0x51, +- 0x55, 0x44, 0x33, 0x22, 0x11}; +- static uint8_t actual_data[15]; +- size_t bytes_written_count = 0; +- size_t bytes_read_count = 0; +- +- memset(local_block_flash0, -1, sizeof(local_block_flash0)); +- memset(local_block_flash_emu, -1, sizeof(local_block_flash_emu)); +- +- /* Register */ +- register_io_dev_flash(&flash0_dev_con); +- register_io_dev_flash(&flash_emu_dev_con); +- +- io_dev_open(flash0_dev_con, &flash0_dev_spec, &flash0_dev_handle); +- io_dev_open(flash_emu_dev_con, &flash_emu_dev_spec, &flash_emu_dev_handle); +- +- /* Write Data */ +- io_open(flash0_dev_handle, &flash0_spec, &flash0_handle); +- io_open(flash_emu_dev_handle, &flash_emu_spec, &flash_emu_handle); +- +- io_seek(flash0_handle, IO_SEEK_SET, +- BANK_1_PARTITION_OFFSET + flash0_info->sector_size - 7); +- io_seek(flash_emu_handle, IO_SEEK_SET, flash_emu_info->sector_size - 7); +- +- io_write(flash0_handle, test_data, ARRAY_LENGTH(test_data), +- &bytes_written_count); +- if (bytes_written_count != ARRAY_LENGTH(test_data)) { +- LOG_ERRFMT("io_write failed to write %d bytes for flash0", +- ARRAY_LENGTH(test_data)); +- LOG_ERRFMT("bytes_written_count %d for flash0", bytes_written_count); +- ret->val = TEST_FAILED; +- } +- io_write(flash_emu_handle, test_data, ARRAY_LENGTH(test_data), +- &bytes_written_count); +- if (bytes_written_count != ARRAY_LENGTH(test_data)) { +- LOG_ERRFMT("io_write failed to write %d bytes for flash emu", +- ARRAY_LENGTH(test_data)); +- LOG_ERRFMT("bytes_written_count %d for flash emu", bytes_written_count); +- ret->val = TEST_FAILED; +- } +- io_close(flash0_handle); +- io_close(flash_emu_handle); +- +- /* Read Data */ +- io_open(flash0_dev_handle, &flash0_spec, &flash0_handle); +- io_open(flash_emu_dev_handle, &flash_emu_spec, &flash_emu_handle); +- +- io_seek(flash0_handle, IO_SEEK_SET, +- BANK_1_PARTITION_OFFSET + flash0_info->sector_size - 7); +- io_seek(flash_emu_handle, IO_SEEK_SET, flash_emu_info->sector_size - 7); +- +- /* Flash0 */ +- io_read(flash0_handle, actual_data, ARRAY_LENGTH(actual_data), +- &bytes_read_count); +- if (bytes_read_count != ARRAY_LENGTH(test_data)) { +- LOG_ERRFMT("io_read failed to read %d bytes for flash0", +- ARRAY_LENGTH(test_data)); +- LOG_ERRFMT("bytes_read_count %d for flash0", bytes_read_count); +- ret->val = TEST_FAILED; +- } +- if (memcmp((uint8_t*)test_data, actual_data, ARRAY_LENGTH(actual_data)) != +- 0) { +- LOG_ERRFMT("Data written != Data read\r\n"); +- ret->val = TEST_FAILED; +- } +- +- memset(actual_data, -1, sizeof(actual_data)); +- +- /* Flash Emu */ +- io_read(flash_emu_handle, actual_data, ARRAY_LENGTH(actual_data), +- &bytes_read_count); +- if (bytes_read_count != ARRAY_LENGTH(test_data)) { +- LOG_ERRFMT("io_read failed to read %d bytes for flash emu", +- ARRAY_LENGTH(test_data)); +- LOG_ERRFMT("bytes_read_count %d for flash emu", bytes_read_count); +- ret->val = TEST_FAILED; +- } +- if (memcmp((uint8_t*)test_data, actual_data, ARRAY_LENGTH(actual_data)) != +- 0) { +- LOG_ERRFMT("Data written != Data read\r\n"); +- ret->val = TEST_FAILED; +- } +- +- LOG_INFFMT("PASS: %s\n\r", __func__); +- ret->val = TEST_PASSED; +-} +diff --git a/platform/ext/target/arm/corstone1000/ci_regression_tests/s_io_storage_test.h b/platform/ext/target/arm/corstone1000/ci_regression_tests/s_io_storage_test.h +deleted file mode 100644 +index fa9012776..000000000 +--- a/platform/ext/target/arm/corstone1000/ci_regression_tests/s_io_storage_test.h ++++ /dev/null +@@ -1,15 +0,0 @@ +-/* +- * Copyright (c) 2022, Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- * +- */ +- +-#ifndef __S_IO_STORAGE_TEST_H__ +-#define __S_IO_STORAGE_TEST_H__ +- +-#include "extra_s_tests.h" +- +-void s_test_io_storage_multiple_flash_simultaneous(struct test_result_t *ret); +- +-#endif /* __S_IO_STORAGE_TEST_H__ */ +\ No newline at end of file +diff --git a/platform/ext/target/arm/corstone1000/ci_regression_tests/s_test.c b/platform/ext/target/arm/corstone1000/ci_regression_tests/s_test.c +index 9a8453ff5..6bfdf2aeb 100644 +--- a/platform/ext/target/arm/corstone1000/ci_regression_tests/s_test.c ++++ b/platform/ext/target/arm/corstone1000/ci_regression_tests/s_test.c +@@ -10,8 +10,7 @@ + #include "extra_s_tests.h" + #include "platform_base_address.h" + #include "firewall.h" +-#include "tfm_sp_log.h" +-#include "s_io_storage_test.h" ++#include "tfm_log_unpriv.h" + + /* TODO: if needed each test function can be made as a separate test case, in + * such case EXTRA_TEST_XX definitions can be removed */ +diff --git a/platform/ext/target/arm/corstone1000/ci_regression_tests/s_test_config.cmake b/platform/ext/target/arm/corstone1000/ci_regression_tests/s_test_config.cmake +deleted file mode 100644 +index 05b7cd785..000000000 +--- a/platform/ext/target/arm/corstone1000/ci_regression_tests/s_test_config.cmake ++++ /dev/null +@@ -1,13 +0,0 @@ +-#------------------------------------------------------------------------------- +-# Copyright (c) 2021-22, Arm Limited. All rights reserved. +-# +-# SPDX-License-Identifier: BSD-3-Clause +-# +-#------------------------------------------------------------------------------- +- +-############ Define secure test specific cmake configurations here ############# +- +-set (TEST_FLASH_SIZE_IN_BYTES 48U CACHE STRING "The size of the emulated flash used in io tests") +-set (TEST_FLASH_SECTOR_SIZE_IN_BYTES 16U CACHE STRING "The sector size of the emulated flash used in io tests") +-set (TEST_FLASH_PAGE_SIZE 8U CACHE STRING "The page size of the emulated flash used in io tests") +-set (TEST_FLASH_PROGRAM_UNIT 1U CACHE STRING "The program unit of the emulated flash used in io tests") +diff --git a/platform/ext/target/arm/corstone1000/ci_regression_tests/test_flash.h b/platform/ext/target/arm/corstone1000/ci_regression_tests/test_flash.h +deleted file mode 100644 +index 4d073a1d7..000000000 +--- a/platform/ext/target/arm/corstone1000/ci_regression_tests/test_flash.h ++++ /dev/null +@@ -1,25 +0,0 @@ +-/* +- * Copyright (c) 2017-2022 Arm Limited. All rights reserved. +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef __TEST_FLASH_H__ +-#define __TEST_FLASH_H__ +- +-#define TEST_FLASH_SIZE_IN_BYTES (48) // 48 bytes +-#define TEST_FLASH_SECTOR_SIZE_IN_BYTES (16) // 16 bytes +-#define TEST_FLASH_PAGE_SIZE (8U) // 8 bytes +-#define TEST_FLASH_PROGRAM_UNIT (1U) /* 1 B */ +- +-#endif /* __TEST_FLASH_H__ */ +diff --git a/platform/ext/target/arm/corstone1000/config.cmake b/platform/ext/target/arm/corstone1000/config.cmake +index 032265cdf..ada6426e3 100644 +--- a/platform/ext/target/arm/corstone1000/config.cmake ++++ b/platform/ext/target/arm/corstone1000/config.cmake +@@ -47,6 +47,7 @@ set(DEFAULT_MCUBOOT_SECURITY_COUNTERS OFF CACHE BOOL "Whethe + # LOG LEVEL + set(TFM_SPM_LOG_LEVEL TFM_SPM_LOG_LEVEL_INFO CACHE STRING "Set default SPM log level as INFO level") + set(TFM_PARTITION_LOG_LEVEL TFM_PARTITION_LOG_LEVEL_INFO CACHE STRING "Set default Secure Partition log level as INFO level") ++set(GPT_LOG_LEVEL LOG_LEVEL_INFO CACHE STRING "Set default GPT library log level as INFO level") + + # Partition + set(TFM_PARTITION_PLATFORM ON CACHE BOOL "Enable Platform partition") +@@ -62,6 +63,9 @@ set(TFM_FWU_BOOTLOADER_LIB "${CMAKE_CURRENT_LIST_DIR}/bootloader/ + set(TFM_CONFIG_FWU_MAX_MANIFEST_SIZE 0 CACHE STRING "The maximum permitted size for manifest in psa_fwu_start(), in bytes.") + set(TFM_CONFIG_FWU_MAX_WRITE_SIZE 4096 CACHE STRING "The maximum permitted size for block in psa_fwu_write, in bytes.") + set(FWU_SUPPORT_TRIAL_STATE ON CACHE BOOL "Device support TRIAL component state.") ++set(PLATFORM_GPT_LIBRARY ON CACHE BOOL "Build the GPT library") ++set(TFM_GPT_BLOCK_SIZE 512 CACHE STRING "The block size of a device formatted as a GUID Partition Table.") ++set(PLAT_MAX_PARTITION_ENTRIES 16 CACHE STRING "The maximum number of GPT partition entries.") + + 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.") +diff --git a/platform/ext/target/arm/corstone1000/fip_parser/external/uuid.h b/platform/ext/target/arm/corstone1000/fip_parser/external/uuid.h +deleted file mode 100644 +index 2ced3a3fa..000000000 +--- a/platform/ext/target/arm/corstone1000/fip_parser/external/uuid.h ++++ /dev/null +@@ -1,74 +0,0 @@ +-/*- +- * Copyright (c) 2002 Marcel Moolenaar +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * +- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- * +- * $FreeBSD$ +- */ +- +-/* +- * Portions copyright (c) 2014-2020, ARM Limited and Contributors. +- * All rights reserved. +- */ +- +-#ifndef UUID_H +-#define UUID_H +- +-/* Length of a node address (an IEEE 802 address). */ +-#define _UUID_NODE_LEN 6 +- +-/* Length of UUID string including dashes. */ +-#define _UUID_STR_LEN 36 +- +-/* +- * See also: +- * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt +- * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm +- * +- * A DCE 1.1 compatible source representation of UUIDs. +- */ +-struct uuid { +- uint8_t time_low[4]; +- uint8_t time_mid[2]; +- uint8_t time_hi_and_version[2]; +- uint8_t clock_seq_hi_and_reserved; +- uint8_t clock_seq_low; +- uint8_t node[_UUID_NODE_LEN]; +-}; +- +-struct efi_guid { +- uint32_t time_low; +- uint16_t time_mid; +- uint16_t time_hi_and_version; +- uint8_t clock_seq_and_node[8]; +-}; +- +-union uuid_helper_t { +- struct uuid uuid_struct; +- struct efi_guid efi_guid; +-}; +- +-/* XXX namespace pollution? */ +-typedef struct uuid uuid_t; +- +-#endif /* UUID_H */ +diff --git a/platform/ext/target/arm/corstone1000/fip_parser/fip_parser.c b/platform/ext/target/arm/corstone1000/fip_parser/fip_parser.c +index 5d264b3a6..cce657fbb 100644 +--- a/platform/ext/target/arm/corstone1000/fip_parser/fip_parser.c ++++ b/platform/ext/target/arm/corstone1000/fip_parser/fip_parser.c +@@ -19,6 +19,8 @@ + #include "fip_parser.h" + #include "bootutil/bootutil_log.h" + ++#include "efi_guid_structs.h" ++ + #include + #include + +@@ -27,13 +29,14 @@ int parse_fip_and_extract_tfa_info(uint32_t address, uint32_t fip_size, + { + FIP_TOC_HEADER *toc_header = NULL; + FIP_TOC_ENTRY *toc_entry = NULL; +- uuid_t uuid_null = {0}; +- uuid_t tfa_uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2; ++ struct efi_guid_t uuid_null = NULL_GUID; ++ struct efi_guid_t tfa_uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2; + char *iter; + + toc_header = (FIP_TOC_HEADER *) address; + + if (toc_header->name != TOC_HEADER_NAME) { ++ BOOT_LOG_ERR("TOC header name does not match"); + return FIP_PARSER_ERROR; + } + +@@ -43,11 +46,11 @@ int parse_fip_and_extract_tfa_info(uint32_t address, uint32_t fip_size, + iter <= (char *)toc_header + fip_size; + iter = iter + sizeof(FIP_TOC_ENTRY), toc_entry++) { + +- if (!memcmp(iter, &uuid_null, sizeof(uuid_t))) { ++ if (efi_guid_cmp((struct efi_guid_t *)iter, &uuid_null) == 0) { + return FIP_PARSER_ERROR; + } + +- if (!memcmp(iter, &tfa_uuid, sizeof(uuid_t))) { ++ if (efi_guid_cmp((struct efi_guid_t *)iter, &tfa_uuid) == 0) { + BOOT_LOG_INF("TF-A FIP at : address = 0x%x : size = 0x%x \n\r", + toc_entry->address, + toc_entry->size); +@@ -57,5 +60,6 @@ int parse_fip_and_extract_tfa_info(uint32_t address, uint32_t fip_size, + } + } + ++ BOOT_LOG_ERR("Unable to find TF-A FIP\r\n"); + return FIP_PARSER_ERROR; + } +diff --git a/platform/ext/target/arm/corstone1000/fip_parser/fip_parser.h b/platform/ext/target/arm/corstone1000/fip_parser/fip_parser.h +index b01000e00..92f35459c 100644 +--- a/platform/ext/target/arm/corstone1000/fip_parser/fip_parser.h ++++ b/platform/ext/target/arm/corstone1000/fip_parser/fip_parser.h +@@ -24,8 +24,9 @@ extern "C" + { + #endif + ++#include "efi_guid_structs.h" ++ + #include +-#include "external/uuid.h" + + /* Return code of fip parser APIs */ + #define FIP_PARSER_SUCCESS (0) +@@ -35,10 +36,13 @@ extern "C" + #define TOC_HEADER_NAME 0xAA640001 + + /* ToC Entry UUIDs */ +-#define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \ +- {{0x5f, 0xf9, 0xec, 0x0b}, {0x4d, 0x22}, \ +- {0x3e, 0x4d}, 0xa5, 0x44, \ +- {0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a} } ++#define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \ ++ MAKE_EFI_GUID( \ ++ 0x0BECF95F, \ ++ 0x224D, \ ++ 0x4D3E, \ ++ 0xA5, 0x44, \ ++ 0xC3, 0x9D, 0x81, 0xC7, 0x3F, 0x0A) + + typedef struct _FIP_TOC_HEADER { + uint32_t name; +@@ -52,12 +56,12 @@ typedef struct _FIP_TOC_HEADER { + */ + + typedef struct _FIP_TOC_ENTRY { +- uuid_t uuid; +- uint32_t address; +- uint32_t pad1; +- uint32_t size; +- uint32_t pad2; +- uint64_t flags; ++ struct efi_guid_t uuid; ++ uint32_t address; ++ uint32_t pad1; ++ uint32_t size; ++ uint32_t pad2; ++ uint64_t flags; + } FIP_TOC_ENTRY; + + int parse_fip_and_extract_tfa_info(uint32_t address, uint32_t fip_size, +diff --git a/platform/ext/target/arm/corstone1000/io/io_block.c b/platform/ext/target/arm/corstone1000/io/io_block.c +deleted file mode 100644 +index a5c021ac5..000000000 +--- a/platform/ext/target/arm/corstone1000/io/io_block.c ++++ /dev/null +@@ -1,528 +0,0 @@ +-/* +- * Copyright (c) 2022 Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: Apache-2.0 +- * +- * Licensed under the Apache License, Version 2.0 (the License); you may +- * not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an AS IS BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#include "io_block.h" +- +-#include +-#include +-#include +- +-#include "io_defs.h" +-#include "io_driver.h" +-#include "io_storage.h" +- +-typedef struct { +- io_block_dev_spec_t *dev_spec; +- uintptr_t base; +- uint32_t file_pos; +- uint32_t size; +-} block_dev_state_t; +- +-#define is_power_of_2(x) (((x) != 0U) && (((x) & ((x)-1U)) == 0U)) +- +-io_type_t device_type_block(void); +- +-static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, +- io_entity_t *entity); +-static int block_seek(io_entity_t *entity, int mode, size_t offset); +-static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, +- size_t *length_read); +-static int block_write(io_entity_t *entity, const uintptr_t buffer, +- size_t length, size_t *length_written); +-static int block_close(io_entity_t *entity); +-static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); +-static int block_dev_close(io_dev_info_t *dev_info); +- +-static const io_dev_connector_t block_dev_connector = {.dev_open = +- block_dev_open}; +- +-static const io_dev_funcs_t block_dev_funcs = { +- .type = device_type_block, +- .open = block_open, +- .seek = block_seek, +- .size = NULL, +- .read = block_read, +- .write = block_write, +- .close = block_close, +- .dev_init = NULL, +- .dev_close = block_dev_close, +-}; +- +-static block_dev_state_t state_pool[MAX_IO_BLOCK_DEVICES]; +-static io_dev_info_t dev_info_pool[MAX_IO_BLOCK_DEVICES]; +- +-/* Track number of allocated block state */ +-static unsigned int block_dev_count; +- +-io_type_t device_type_block(void) { return IO_TYPE_BLOCK; } +- +-/* Locate a block state in the pool, specified by address */ +-static int find_first_block_state(const io_block_dev_spec_t *dev_spec, +- unsigned int *index_out) { +- unsigned int index; +- int result = -ENOENT; +- +- for (index = 0U; index < MAX_IO_BLOCK_DEVICES; ++index) { +- /* dev_spec is used as identifier since it's unique */ +- if (state_pool[index].dev_spec == dev_spec) { +- result = 0; +- *index_out = index; +- break; +- } +- } +- return result; +-} +- +-/* Allocate a device info from the pool and return a pointer to it */ +-static int allocate_dev_info(io_dev_info_t **dev_info) { +- int result = -ENOMEM; +- assert(dev_info != NULL); +- +- if (block_dev_count < MAX_IO_BLOCK_DEVICES) { +- unsigned int index = 0; +- result = find_first_block_state(NULL, &index); +- assert(result == 0); +- /* initialize dev_info */ +- dev_info_pool[index].funcs = &block_dev_funcs; +- dev_info_pool[index].info = (uintptr_t)&state_pool[index]; +- *dev_info = &dev_info_pool[index]; +- ++block_dev_count; +- } +- +- return result; +-} +- +-/* Release a device info to the pool */ +-static int free_dev_info(io_dev_info_t *dev_info) { +- int result; +- unsigned int index = 0; +- block_dev_state_t *state; +- assert(dev_info != NULL); +- +- state = (block_dev_state_t *)dev_info->info; +- result = find_first_block_state(state->dev_spec, &index); +- if (result == 0) { +- /* free if device info is valid */ +- memset(state, 0, sizeof(block_dev_state_t)); +- memset(dev_info, 0, sizeof(io_dev_info_t)); +- --block_dev_count; +- } +- +- return result; +-} +- +-static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, +- io_entity_t *entity) { +- block_dev_state_t *cur; +- io_block_spec_t *region; +- +- assert((dev_info->info != (uintptr_t)NULL) && (spec != (uintptr_t)NULL) && +- (entity->info == (uintptr_t)NULL)); +- +- region = (io_block_spec_t *)spec; +- cur = (block_dev_state_t *)dev_info->info; +- assert(((region->offset % cur->dev_spec->block_size) == 0) && +- ((region->length % cur->dev_spec->block_size) == 0)); +- +- cur->base = region->offset; +- cur->size = region->length; +- cur->file_pos = 0; +- +- entity->info = (uintptr_t)cur; +- return 0; +-} +- +-/* parameter offset is relative address at here */ +-static int block_seek(io_entity_t *entity, int mode, size_t offset) { +- block_dev_state_t *cur; +- +- assert(entity->info != (uintptr_t)NULL); +- +- cur = (block_dev_state_t *)entity->info; +- +- assert((offset >= 0) && ((uint32_t)offset < cur->size)); +- switch (mode) { +- case IO_SEEK_SET: +- cur->file_pos = (uint32_t)offset; +- break; +- case IO_SEEK_CUR: +- cur->file_pos += (uint32_t)offset; +- break; +- default: +- return -EINVAL; +- } +- assert(cur->file_pos < cur->size); +- return 0; +-} +- +-/* +- * This function allows the caller to read any number of bytes +- * from any position. It hides from the caller that the low level +- * driver only can read aligned blocks of data. For this reason +- * we need to handle the use case where the first byte to be read is not +- * aligned to start of the block, the last byte to be read is also not +- * aligned to the end of a block, and there are zero or more blocks-worth +- * of data in between. +- * +- * In such a case we need to read more bytes than requested (i.e. full +- * blocks) and strip-out the leading bytes (aka skip) and the trailing +- * bytes (aka padding). See diagram below +- * +- * cur->file_pos ------------ +- * | +- * cur->base | +- * | | +- * v v<---- length ----> +- * -------------------------------------------------------------- +- * | | block#1 | | block#n | +- * | block#0 | + | ... | + | +- * | | <- skip -> + | | + <- padding ->| +- * ------------------------+----------------------+-------------- +- * ^ ^ +- * | | +- * v iteration#1 iteration#n v +- * -------------------------------------------------- +- * | | | | +- * |<---- request ---->| ... |<----- request ---->| +- * | | | | +- * -------------------------------------------------- +- * / / | | +- * / / | | +- * / / | | +- * / / | | +- * / / | | +- * / / | | +- * / / | | +- * / / | | +- * / / | | +- * / / | | +- * <---- request ------> <------ request -----> +- * --------------------- ----------------------- +- * | | | | | | +- * |<-skip->|<-nbytes->| -------->|<-nbytes->|<-padding->| +- * | | | | | | | +- * --------------------- | ----------------------- +- * ^ \ \ | | | +- * | \ \ | | | +- * | \ \ | | | +- * buf->offset \ \ buf->offset | | +- * \ \ | | +- * \ \ | | +- * \ \ | | +- * \ \ | | +- * \ \ | | +- * \ \ | | +- * \ \ | | +- * -------------------------------- +- * | | | | +- * buffer-------------->| | ... | | +- * | | | | +- * -------------------------------- +- * <-count#1->| | +- * <---------- count#n --------> +- * <---------- length ----------> +- * +- * Additionally, the IO driver has an underlying buffer that is at least +- * one block-size and may be big enough to allow. +- */ +-static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, +- size_t *length_read) { +- block_dev_state_t *cur; +- io_block_spec_t *buf; +- io_block_ops_t *ops; +- int lba; +- size_t block_size, left; +- size_t nbytes; /* number of bytes read in one iteration */ +- size_t request; /* number of requested bytes in one iteration */ +- size_t count; /* number of bytes already read */ +- /* +- * number of leading bytes from start of the block +- * to the first byte to be read +- */ +- size_t skip; +- +- /* +- * number of trailing bytes between the last byte +- * to be read and the end of the block +- */ +- size_t padding; +- +- assert(entity->info != (uintptr_t)NULL); +- cur = (block_dev_state_t *)entity->info; +- ops = &(cur->dev_spec->ops); +- buf = &(cur->dev_spec->buffer); +- block_size = cur->dev_spec->block_size; +- assert((length <= cur->size) && (length > 0U) && (ops->read != 0)); +- +- /* +- * We don't know the number of bytes that we are going +- * to read in every iteration, because it will depend +- * on the low level driver. +- */ +- count = 0; +- for (left = length; left > 0U; left -= nbytes) { +- /* +- * We must only request operations aligned to the block +- * size. Therefore if file_pos is not block-aligned, +- * we have to request the operation to start at the +- * previous block boundary and skip the leading bytes. And +- * similarly, the number of bytes requested must be a +- * block size multiple +- */ +- skip = cur->file_pos & (block_size - 1U); +- +- /* +- * Calculate the block number containing file_pos +- * - e.g. block 3. +- */ +- lba = (cur->file_pos + cur->base) / block_size; +- +- if ((skip + left) > buf->length) { +- /* +- * The underlying read buffer is too small to +- * read all the required data - limit to just +- * fill the buffer, and then read again. +- */ +- request = buf->length; +- } else { +- /* +- * The underlying read buffer is big enough to +- * read all the required data. Calculate the +- * number of bytes to read to align with the +- * block size. +- */ +- request = skip + left; +- request = (request + (block_size - 1U)) & ~(block_size - 1U); +- } +- request = ops->read(lba, buf->offset, request); +- +- if (request <= skip) { +- /* +- * We couldn't read enough bytes to jump over +- * the skip bytes, so we should have to read +- * again the same block, thus generating +- * the same error. +- */ +- return -EIO; +- } +- +- /* +- * Need to remove skip and padding bytes,if any, from +- * the read data when copying to the user buffer. +- */ +- nbytes = request - skip; +- padding = (nbytes > left) ? nbytes - left : 0U; +- nbytes -= padding; +- +- memcpy((void *)(buffer + count), (void *)(buf->offset + skip), nbytes); +- +- cur->file_pos += nbytes; +- count += nbytes; +- } +- assert(count == length); +- *length_read = count; +- +- return 0; +-} +- +-/* +- * This function allows the caller to write any number of bytes +- * from any position. It hides from the caller that the low level +- * driver only can write aligned blocks of data. +- * See comments for block_read for more details. +- */ +-static int block_write(io_entity_t *entity, const uintptr_t buffer, +- size_t length, size_t *length_written) { +- block_dev_state_t *cur; +- io_block_spec_t *buf; +- io_block_ops_t *ops; +- int lba; +- size_t block_size, left; +- size_t nbytes; /* number of bytes read in one iteration */ +- size_t request; /* number of requested bytes in one iteration */ +- size_t count; /* number of bytes already read */ +- /* +- * number of leading bytes from start of the block +- * to the first byte to be read +- */ +- size_t skip; +- +- /* +- * number of trailing bytes between the last byte +- * to be read and the end of the block +- */ +- size_t padding; +- assert(entity->info != (uintptr_t)NULL); +- cur = (block_dev_state_t *)entity->info; +- ops = &(cur->dev_spec->ops); +- buf = &(cur->dev_spec->buffer); +- block_size = cur->dev_spec->block_size; +- assert((length <= cur->size) && (length > 0U) && (ops->read != 0) && +- (ops->write != 0)); +- +- /* +- * We don't know the number of bytes that we are going +- * to write in every iteration, because it will depend +- * on the low level driver. +- */ +- count = 0; +- for (left = length; left > 0U; left -= nbytes) { +- /* +- * We must only request operations aligned to the block +- * size. Therefore if file_pos is not block-aligned, +- * we have to request the operation to start at the +- * previous block boundary and skip the leading bytes. And +- * similarly, the number of bytes requested must be a +- * block size multiple +- */ +- skip = cur->file_pos & (block_size - 1U); +- +- /* +- * Calculate the block number containing file_pos +- * - e.g. block 3. +- */ +- lba = (cur->file_pos + cur->base) / block_size; +- +- if ((skip + left) > buf->length) { +- /* +- * The underlying read buffer is too small to +- * read all the required data - limit to just +- * fill the buffer, and then read again. +- */ +- request = buf->length; +- } else { +- /* +- * The underlying read buffer is big enough to +- * read all the required data. Calculate the +- * number of bytes to read to align with the +- * block size. +- */ +- request = skip + left; +- request = (request + (block_size - 1U)) & ~(block_size - 1U); +- } +- +- /* +- * The number of bytes that we are going to write +- * from the user buffer will depend of the size +- * of the current request. +- */ +- nbytes = request - skip; +- padding = (nbytes > left) ? nbytes - left : 0U; +- nbytes -= padding; +- +- /* +- * If we have skip or padding bytes then we have to preserve +- * some content and it means that we have to read before +- * writing +- */ +- if ((skip > 0U) || (padding > 0U)) { +- request = ops->read(lba, buf->offset, request); +- /* +- * The read may return size less than +- * requested. Round down to the nearest block +- * boundary +- */ +- request &= ~(block_size - 1U); +- if (request <= skip) { +- /* +- * We couldn't read enough bytes to jump over +- * the skip bytes, so we should have to read +- * again the same block, thus generating +- * the same error. +- */ +- return -EIO; +- } +- nbytes = request - skip; +- padding = (nbytes > left) ? nbytes - left : 0U; +- nbytes -= padding; +- } +- +- memcpy((void *)(buf->offset + skip), (void *)(buffer + count), nbytes); +- +- request = ops->write(lba, buf->offset, request); +- if (request <= skip) return -EIO; +- +- /* +- * And the previous write operation may modify the size +- * of the request, so again, we have to calculate the +- * number of bytes that we consumed from the user +- * buffer +- */ +- nbytes = request - skip; +- padding = (nbytes > left) ? nbytes - left : 0U; +- nbytes -= padding; +- +- cur->file_pos += nbytes; +- count += nbytes; +- } +- assert(count == length); +- *length_written = count; +- +- return 0; +-} +- +-static int block_close(io_entity_t *entity) { +- entity->info = (uintptr_t)NULL; +- return 0; +-} +- +-static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) { +- block_dev_state_t *cur; +- io_block_spec_t *buffer; +- io_dev_info_t *info; +- size_t block_size; +- int result; +- assert(dev_info != NULL); +- result = allocate_dev_info(&info); +- if (result != 0) return -ENOENT; +- +- cur = (block_dev_state_t *)info->info; +- /* dev_spec is type of io_block_dev_spec_t. */ +- cur->dev_spec = (io_block_dev_spec_t *)dev_spec; +- buffer = &(cur->dev_spec->buffer); +- block_size = cur->dev_spec->block_size; +- +- assert((block_size > 0U) && (is_power_of_2(block_size) != 0U) && +- ((buffer->length % block_size) == 0U)); +- +- *dev_info = info; /* cast away const */ +- (void)block_size; +- (void)buffer; +- return 0; +-} +- +-static int block_dev_close(io_dev_info_t *dev_info) { +- return free_dev_info(dev_info); +-} +- +-/* Exported functions */ +- +-/* Register the Block driver with the IO abstraction */ +-int register_io_dev_block(const io_dev_connector_t **dev_con) { +- int result; +- +- assert(dev_con != NULL); +- +- /* +- * Since dev_info isn't really used in io_register_device, always +- * use the same device info at here instead. +- */ +- result = io_register_device(&dev_info_pool[0]); +- if (result == 0) *dev_con = &block_dev_connector; +- return result; +-} +diff --git a/platform/ext/target/arm/corstone1000/io/io_block.h b/platform/ext/target/arm/corstone1000/io/io_block.h +deleted file mode 100644 +index 1603aa74c..000000000 +--- a/platform/ext/target/arm/corstone1000/io/io_block.h ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* +- * Copyright (c) 2022 Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: Apache-2.0 +- * +- * Licensed under the Apache License, Version 2.0 (the License); you may +- * not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an AS IS BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef __IO_BLOCK_H__ +-#define __IO_BLOCK_H__ +- +-#include "io_storage.h" +- +-/* block devices ops */ +-typedef struct io_block_ops { +- size_t (*read)(int lba, uintptr_t buf, size_t size); +- size_t (*write)(int lba, const uintptr_t buf, size_t size); +-} io_block_ops_t; +- +-typedef struct io_block_dev_spec { +- io_block_spec_t buffer; +- io_block_ops_t ops; +- size_t block_size; +-} io_block_dev_spec_t; +- +-struct io_dev_connector; +- +-int register_io_dev_block(const struct io_dev_connector **dev_con); +- +-#endif /* __IO_BLOCK_H__ */ +\ No newline at end of file +diff --git a/platform/ext/target/arm/corstone1000/io/io_defs.h b/platform/ext/target/arm/corstone1000/io/io_defs.h +deleted file mode 100644 +index acba969ed..000000000 +--- a/platform/ext/target/arm/corstone1000/io/io_defs.h ++++ /dev/null +@@ -1,27 +0,0 @@ +-/* +- * Copyright (c) 2022 Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: Apache-2.0 +- * +- * Licensed under the Apache License, Version 2.0 (the License); you may +- * not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an AS IS BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef __IO_DEFS_H__ +-#define __IO_DEFS_H__ +- +-#define MAX_IO_DEVICES (2) +-#define MAX_IO_HANDLES (2) +-#define MAX_IO_BLOCK_DEVICES (2) +-#define MAX_IO_FLASH_DEVICES (2) +- +-#endif /* __IO_DEFS_H__ */ +\ No newline at end of file +diff --git a/platform/ext/target/arm/corstone1000/io/io_driver.h b/platform/ext/target/arm/corstone1000/io/io_driver.h +deleted file mode 100644 +index cf9e21a6d..000000000 +--- a/platform/ext/target/arm/corstone1000/io/io_driver.h ++++ /dev/null +@@ -1,54 +0,0 @@ +-/* +- * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#ifndef __IO_DRIVER_H__ +-#define __IO_DRIVER_H__ +- +-#include +-#include +- +-/* Generic IO entity structure,representing an accessible IO construct on the +- * device, such as a file */ +-typedef struct io_entity { +- struct io_dev_info *dev_handle; +- uintptr_t info; +-} io_entity_t; +- +-/* Device info structure, providing device-specific functions and a means of +- * adding driver-specific state */ +-typedef struct io_dev_info { +- const struct io_dev_funcs *funcs; +- uintptr_t info; +-} io_dev_info_t; +- +-/* Structure used to create a connection to a type of device */ +-typedef struct io_dev_connector { +- /* dev_open opens a connection to a particular device driver */ +- int (*dev_open)(const uintptr_t dev_spec, io_dev_info_t **dev_info); +-} io_dev_connector_t; +- +-/* Structure to hold device driver function pointers */ +-typedef struct io_dev_funcs { +- io_type_t (*type)(void); +- int (*open)(io_dev_info_t *dev_info, const uintptr_t spec, +- io_entity_t *entity); +- int (*seek)(io_entity_t *entity, int mode, size_t offset); +- int (*size)(io_entity_t *entity, size_t *length); +- int (*read)(io_entity_t *entity, uintptr_t buffer, size_t length, +- size_t *length_read); +- int (*write)(io_entity_t *entity, const uintptr_t buffer, size_t length, +- size_t *length_written); +- int (*close)(io_entity_t *entity); +- int (*dev_init)(io_dev_info_t *dev_info, const uintptr_t init_params); +- int (*dev_close)(io_dev_info_t *dev_info); +-} io_dev_funcs_t; +- +-/* Operations intended to be performed during platform initialisation */ +- +-/* Register an IO device */ +-int io_register_device(const io_dev_info_t *dev_info); +- +-#endif /* __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 +deleted file mode 100644 +index b90a81a48..000000000 +--- a/platform/ext/target/arm/corstone1000/io/io_flash.c ++++ /dev/null +@@ -1,183 +0,0 @@ +-/* +- * Copyright (c) 2022 Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: Apache-2.0 +- * +- * Licensed under the Apache License, Version 2.0 (the License); you may +- * not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an AS IS BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#include "io_flash.h" +- +-#include +-#include +- +-#include "Driver_Flash.h" +-#include "io_block.h" +-#include "io_defs.h" +-#include "io_driver.h" +-#include "io_storage.h" +- +-#if MAX_IO_FLASH_DEVICES > MAX_IO_BLOCK_DEVICES +-#error \ +- "FLASH devices are BLOCK devices .. MAX_IO_FLASH_DEVICES should be less or equal to MAX_IO_BLOCK_DEVICES" +-#endif +- +-/* Private Prototypes */ +- +-static int flash_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); +-static size_t flash_read(int lba, uintptr_t buf, size_t size, size_t flash_id); +-static size_t flash_write(int lba, const uintptr_t buf, size_t size, +- size_t flash_id); +-static size_t flash0_read(int lba, uintptr_t buf, size_t size); +-static size_t flash0_write(int lba, uintptr_t buf, size_t size); +-static size_t flash1_read(int lba, uintptr_t buf, size_t size); +-static size_t flash1_write(int lba, uintptr_t buf, size_t size); +- +-/** Private Data **/ +- +-/* Flash device data */ +-static const io_dev_connector_t flash_dev_connector = {.dev_open = +- flash_dev_open}; +-static size_t flash_dev_count = 0; +-static io_flash_dev_spec_t *flash_dev_specs[MAX_IO_FLASH_DEVICES]; +- +-/* Block device data */ +-static io_dev_connector_t block_dev_connectors[MAX_IO_FLASH_DEVICES]; +-static io_block_dev_spec_t block_dev_spec[MAX_IO_FLASH_DEVICES]; +- +-/* Flash devices read/write function pointers */ +-static io_block_ops_t flashs_ops[MAX_IO_FLASH_DEVICES] = { +- [0] = {.read = flash0_read, .write = flash0_write}, +- [1] = {.read = flash1_read, .write = flash1_write}, +-}; +- +-/* Flash ops functions */ +-static size_t flash_read(int lba, uintptr_t buf, size_t size, size_t flash_id) { +- ARM_DRIVER_FLASH *flash_driver = +- ((ARM_DRIVER_FLASH *)flash_dev_specs[flash_id]->flash_driver); +- ARM_FLASH_INFO *info = flash_driver->GetInfo(); +- uint32_t addr = info->sector_size * lba; +- uint32_t offset = addr - flash_dev_specs[flash_id]->base_addr; +- size_t rem = info->sector_count * info->sector_size - offset; +- size_t cnt = size < rem ? size : rem; +- +- return flash_driver->ReadData(offset, (void *)buf, cnt); +-} +- +-static size_t flash_write(int lba, const uintptr_t buf, size_t size, +- size_t flash_id) { +- ARM_DRIVER_FLASH *flash_driver = +- ((ARM_DRIVER_FLASH *)flash_dev_specs[flash_id]->flash_driver); +- ARM_FLASH_INFO *info = flash_driver->GetInfo(); +- int32_t rc = 0; +- uint32_t addr = info->sector_size * lba; +- uint32_t offset = addr - flash_dev_specs[flash_id]->base_addr; +- size_t rem = info->sector_count * info->sector_size - offset; +- size_t cnt = size < rem ? size : rem; +- +- flash_driver->EraseSector(offset); +- rc = flash_driver->ProgramData(offset, (const void *)buf, cnt); +- return rc; +-} +- +-/* Flash ops functions wrapper for each device */ +- +-static size_t flash0_read(int lba, uintptr_t buf, size_t size) { +- return flash_read(lba, buf, size, 0); +-} +- +-static size_t flash0_write(int lba, uintptr_t buf, size_t size) { +- return flash_write(lba, buf, size, 0); +-} +- +-static size_t flash1_read(int lba, uintptr_t buf, size_t size) { +- return flash_read(lba, buf, size, 1); +-} +- +-static size_t flash1_write(int lba, uintptr_t buf, size_t size) { +- return flash_write(lba, buf, size, 1); +-} +- +-/** +- * Helper function to find the index of stored flash_dev_specs or +- * return a free slot in case of a new dev_spec +- */ +-static int find_flash_dev_specs(const uintptr_t dev_spec) { +- /* Search in the saved ones */ +- for (int i = 0; i < flash_dev_count; ++i) { +- if (flash_dev_specs[i] != NULL && +- flash_dev_specs[i]->flash_driver == +- ((io_flash_dev_spec_t *)dev_spec)->flash_driver) { +- return i; +- } +- } +- /* Find the first empty flash_dev_specs to be used */ +- for (int i = 0; i < flash_dev_count; ++i) { +- if (flash_dev_specs[i] == NULL) { +- return i; +- } +- } +- return -1; +-} +- +-/** +- * This function should be called +- */ +-static int flash_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) { +- ARM_DRIVER_FLASH *flash_driver; +- assert(dev_info != NULL); +- assert(dev_spec != NULL); +- +- size_t index = find_flash_dev_specs(dev_spec); +- +- /* Check if Flash ops functions are defined for this flash */ +- assert(flashs_ops[index].read && flashs_ops[index].write); +- +- 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; +- block_dev_spec[index].buffer.length = flash_dev_specs[index]->bufferlen; +- block_dev_spec[index].ops = flashs_ops[index]; +- +- flash_driver->Initialize(NULL); +- +- block_dev_connectors[index].dev_open((uintptr_t)&block_dev_spec[index], dev_info); +- +- return 0; +-} +- +-/* Exported functions */ +- +-/** +- * Register the flash device. +- * Internally it register a block device. +- */ +-int register_io_dev_flash(const io_dev_connector_t **dev_con) { +- int result; +- +- if (flash_dev_count >= MAX_IO_FLASH_DEVICES) { +- return -ENOENT; +- } +- assert(dev_con != NULL); +- +- result = register_io_dev_block(dev_con); +- if (result == 0) { +- /* Store the block dev connector */ +- block_dev_connectors[flash_dev_count++] = **dev_con; +- /* Override dev_con with the flash dev connector */ +- *dev_con = &flash_dev_connector; +- } +- return result; +-} +diff --git a/platform/ext/target/arm/corstone1000/io/io_flash.h b/platform/ext/target/arm/corstone1000/io/io_flash.h +deleted file mode 100644 +index 8bc38b582..000000000 +--- a/platform/ext/target/arm/corstone1000/io/io_flash.h ++++ /dev/null +@@ -1,37 +0,0 @@ +-/* +- * Copyright (c) 2022 Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: Apache-2.0 +- * +- * Licensed under the Apache License, Version 2.0 (the License); you may +- * not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an AS IS BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef __IO_FLASH_H__ +-#define __IO_FLASH_H__ +- +-#include "io_storage.h" +- +-typedef struct io_flash_dev_spec { +- uintptr_t buffer; +- size_t bufferlen; +- uint32_t base_addr; +- uintptr_t flash_driver; +-} io_flash_dev_spec_t; +- +-struct io_dev_connector; +- +-/* Register the flash driver with the IO abstraction internally it register a +- * block device*/ +-int register_io_dev_flash(const struct io_dev_connector **dev_con); +- +-#endif /* __IO_FLASH_H__ */ +diff --git a/platform/ext/target/arm/corstone1000/io/io_gpt.c b/platform/ext/target/arm/corstone1000/io/io_gpt.c +new file mode 100644 +index 000000000..513c77016 +--- /dev/null ++++ b/platform/ext/target/arm/corstone1000/io/io_gpt.c +@@ -0,0 +1,179 @@ ++/* ++ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "io_gpt.h" ++ ++#include "Driver_Flash.h" ++#include "gpt_flash.h" ++#include "flash_layout.h" ++ ++/* Check if globals in module have been initialised */ ++#define CHECK_INIT \ ++ do { \ ++ if (!flash_driver) { \ ++ return GPT_FLASH_NOT_INIT; \ ++ } \ ++ } while (0) ++ ++/* Check the given flash access is valid */ ++#define CHECK_BOUNDS(addr, size) \ ++ do { \ ++ if (size > FLASH_TOTAL_SIZE || addr > FLASH_TOTAL_SIZE - size) { \ ++ return GPT_FLASH_BAD_PARAM; \ ++ } \ ++ } while (0) ++ ++/* Aligns address to flash sector sizes */ ++#define ALIGN_TO_SECTOR(addr) (((addr) / FLASH_SECTOR_SIZE) * FLASH_SECTOR_SIZE) ++ ++/* Number of LBAs per sector of flash */ ++#define LBAS_PER_SECTOR (FLASH_SECTOR_SIZE / TFM_GPT_BLOCK_SIZE) ++ ++/* Returns the offset within a sector for the given lba */ ++static inline uint64_t sector_offset(uint64_t lba) ++{ ++ return (lba % LBAS_PER_SECTOR) * TFM_GPT_BLOCK_SIZE; ++} ++ ++/* The actual flash driver under the hood */ ++static ARM_DRIVER_FLASH *flash_driver = NULL; ++ ++/* Buffer used to store sector of flash data */ ++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}; ++ ++/* 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 ++ * shouldn't have been erased ++ */ ++static gpt_flash_err_t partially_erase_sector(uint32_t sector_addr, ++ uint32_t offset) ++{ ++ if (flash_driver->ReadData( ++ sector_addr, ++ sector_buf, ++ FLASH_SECTOR_SIZE) != FLASH_SECTOR_SIZE) ++ { ++ return GPT_FLASH_GENERIC_ERROR; ++ } ++ ++ if (flash_driver->EraseSector(sector_addr) != ARM_DRIVER_OK) { ++ return GPT_FLASH_GENERIC_ERROR; ++ } ++ ++ memset(sector_buf + offset, flash_driver->GetInfo()->erased_value, TFM_GPT_BLOCK_SIZE); ++ if (flash_driver->ProgramData( ++ sector_addr, ++ sector_buf, ++ FLASH_SECTOR_SIZE) != FLASH_SECTOR_SIZE) ++ { ++ return GPT_FLASH_GENERIC_ERROR; ++ } ++ ++ return GPT_FLASH_SUCCESS; ++} ++ ++/* Reads the requested LBA into the given buffer */ ++static ssize_t flash_read(uint64_t lba, void *buf) ++{ ++ CHECK_INIT; ++ ++ uint64_t read_addr = lba * TFM_GPT_BLOCK_SIZE; ++ CHECK_BOUNDS(read_addr, TFM_GPT_BLOCK_SIZE); ++ ++ if (flash_driver->ReadData(read_addr, buf, TFM_GPT_BLOCK_SIZE) != TFM_GPT_BLOCK_SIZE) { ++ return GPT_FLASH_GENERIC_ERROR; ++ } ++ ++ return TFM_GPT_BLOCK_SIZE; ++} ++ ++/* Writes the given buffer to the requested LBA */ ++static ssize_t flash_write(uint64_t lba, const void *buf) ++{ ++ CHECK_INIT; ++ ++ uint64_t write_addr = lba * TFM_GPT_BLOCK_SIZE; ++ CHECK_BOUNDS(write_addr, TFM_GPT_BLOCK_SIZE); ++ ++ if (flash_driver->ProgramData(write_addr, buf, TFM_GPT_BLOCK_SIZE) != TFM_GPT_BLOCK_SIZE) { ++ return GPT_FLASH_GENERIC_ERROR; ++ } ++ ++ return TFM_GPT_BLOCK_SIZE; ++} ++ ++/* Erases a consecutive number of blocks, beginning with the given LBA */ ++static ssize_t flash_erase(uint64_t lba, size_t num_blocks) ++{ ++ CHECK_INIT; ++ ++ if (num_blocks == 0) { ++ return GPT_FLASH_BAD_PARAM; ++ } ++ ++ /* Convert blocks to sectors. The first and final sectors may be partially erased */ ++ size_t num_sectors = num_blocks / LBAS_PER_SECTOR; ++ if (num_sectors == 0) { ++ /* Partially erase first sector and thats it */ ++ num_sectors = 1; ++ } ++ ++ uint64_t erase_addr = ALIGN_TO_SECTOR(lba * TFM_GPT_BLOCK_SIZE); ++ CHECK_BOUNDS(erase_addr, FLASH_SECTOR_SIZE); ++ ++ uint64_t last_erase_addr = erase_addr + ((num_sectors - 1) * FLASH_SECTOR_SIZE); ++ CHECK_BOUNDS(last_erase_addr, FLASH_SECTOR_SIZE); ++ ++ /* Whole sector erases until last sector */ ++ for (size_t i = 0; i < num_sectors - 1; ++i) { ++ int32_t ret = flash_driver->EraseSector(erase_addr + i * FLASH_SECTOR_SIZE); ++ if (ret != ARM_DRIVER_OK) { ++ return i; ++ } ++ } ++ ++ 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; ++ } ++ } else { ++ /* Partial erase of final sector */ ++ if (partially_erase_sector( ++ last_erase_addr, ++ sector_offset(lba)) != GPT_FLASH_SUCCESS) ++ { ++ return num_sectors == 0 ? GPT_FLASH_GENERIC_ERROR : (num_sectors - 1) * LBAS_PER_SECTOR; ++ } ++ } ++ ++ return num_blocks; ++} ++ ++int register_flash_io_gpt(ARM_DRIVER_FLASH *driver) ++{ ++ /* Initialise the driver */ ++ driver->Initialize(NULL); ++ ++ /* Store everything needed */ ++ flash_driver = driver; ++ ++ io_gpt_flash_driver.read = flash_read; ++ io_gpt_flash_driver.write = flash_write; ++ io_gpt_flash_driver.erase = flash_erase; ++ ++ return 0; ++} +diff --git a/platform/ext/target/arm/corstone1000/io/io_gpt.h b/platform/ext/target/arm/corstone1000/io/io_gpt.h +new file mode 100644 +index 000000000..96dcda04e +--- /dev/null ++++ b/platform/ext/target/arm/corstone1000/io/io_gpt.h +@@ -0,0 +1,25 @@ ++/* ++ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ * ++ */ ++ ++#ifndef __IO_GPT_H__ ++#define __IO_GPT_H__ ++ ++#include "io_gpt.h" ++ ++#include "Driver_Flash.h" ++#include "gpt_flash.h" ++ ++/* The pseudo flash driver used by the GPT library. Each LBA maps ++ * FLASH_SECTOR_SIZE:TFM_GPT_BLOCK_SIZE to a sector of flash (so 1024:512 means ++ * two LBAs per sector of flash) ++ */ ++extern struct gpt_flash_driver_t io_gpt_flash_driver; ++ ++/* Sets up the gpt_flash_driver with the given driver and initialises the latter */ ++int register_flash_io_gpt(ARM_DRIVER_FLASH *driver); ++ ++#endif /* __IO_GPT_H__ */ +diff --git a/platform/ext/target/arm/corstone1000/io/io_storage.c b/platform/ext/target/arm/corstone1000/io/io_storage.c +deleted file mode 100644 +index f26f4980f..000000000 +--- a/platform/ext/target/arm/corstone1000/io/io_storage.c ++++ /dev/null +@@ -1,289 +0,0 @@ +-/* +- * Copyright (c) 2022 Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: Apache-2.0 +- * +- * Licensed under the Apache License, Version 2.0 (the License); you may +- * not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an AS IS BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#include +-#include +-#include +- +-#include "io_defs.h" +-#include "io_driver.h" +- +-/* Storage for a fixed maximum number of IO entities, definable by platform */ +-static io_entity_t entity_pool[MAX_IO_HANDLES]; +- +-/* Simple way of tracking used storage - each entry is NULL or a pointer to an +- * entity */ +-static io_entity_t *entity_map[MAX_IO_HANDLES]; +- +-/* Track number of allocated entities */ +-static unsigned int entity_count; +- +-/* Array of fixed maximum of registered devices, definable by platform */ +-static const io_dev_info_t *devices[MAX_IO_DEVICES]; +- +-/* Number of currently registered devices */ +-static unsigned int dev_count; +- +-/* Return a boolean value indicating whether a device connector is valid */ +-static bool is_valid_dev_connector(const io_dev_connector_t *dev_con) { +- return (dev_con != NULL) && (dev_con->dev_open != NULL); +-} +- +-/* Return a boolean value indicating whether a device handle is valid */ +-static bool is_valid_dev(const uintptr_t dev_handle) { +- const io_dev_info_t *dev = (io_dev_info_t *)dev_handle; +- +- return (dev != NULL) && (dev->funcs != NULL) && +- (dev->funcs->type != NULL) && (dev->funcs->type() < IO_TYPE_MAX); +-} +- +-/* Return a boolean value indicating whether an IO entity is valid */ +-static bool is_valid_entity(const uintptr_t handle) { +- const io_entity_t *entity = (io_entity_t *)handle; +- +- return (entity != NULL) && (is_valid_dev((uintptr_t)entity->dev_handle)); +-} +- +-/* Return a boolean value indicating whether a seek mode is valid */ +-static bool is_valid_seek_mode(io_seek_mode_t mode) { +- return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX)); +-} +- +-/* Open a connection to a specific device */ +-static int io_storage_dev_open(const io_dev_connector_t *dev_con, +- const uintptr_t dev_spec, +- io_dev_info_t **dev_info) { +- assert(dev_info != NULL); +- assert(is_valid_dev_connector(dev_con)); +- +- return dev_con->dev_open(dev_spec, dev_info); +-} +- +-/* Set a handle to track an entity */ +-static void set_handle(uintptr_t *handle, io_entity_t *entity) { +- assert(handle != NULL); +- *handle = (uintptr_t)entity; +-} +- +-/* Locate an entity in the pool, specified by address */ +-static int find_first_entity(const io_entity_t *entity, +- unsigned int *index_out) { +- int result = -ENOENT; +- for (unsigned int index = 0; index < MAX_IO_HANDLES; ++index) { +- if (entity_map[index] == entity) { +- result = 0; +- *index_out = index; +- break; +- } +- } +- return result; +-} +- +-/* Allocate an entity from the pool and return a pointer to it */ +-static int allocate_entity(io_entity_t **entity) { +- int result = -ENOMEM; +- assert(entity != NULL); +- +- if (entity_count < MAX_IO_HANDLES) { +- unsigned int index = 0; +- result = find_first_entity(NULL, &index); +- assert(result == 0); +- *entity = &entity_pool[index]; +- entity_map[index] = &entity_pool[index]; +- ++entity_count; +- } +- +- return result; +-} +- +-/* Release an entity back to the pool */ +-static int free_entity(const io_entity_t *entity) { +- int result; +- unsigned int index = 0; +- assert(entity != NULL); +- +- result = find_first_entity(entity, &index); +- if (result == 0) { +- entity_map[index] = NULL; +- --entity_count; +- } +- +- return result; +-} +- +-/* Exported API */ +- +-/* Register an io device */ +-int io_register_device(const io_dev_info_t *dev_info) { +- int result = -ENOMEM; +- assert(dev_info != NULL); +- +- if (dev_count < MAX_IO_DEVICES) { +- devices[dev_count] = dev_info; +- dev_count++; +- result = 0; +- } +- +- return result; +-} +- +-/* Open a connection to an IO device */ +-int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec, +- uintptr_t *handle) { +- assert(handle != NULL); +- return io_storage_dev_open(dev_con, dev_spec, (io_dev_info_t **)handle); +-} +- +-/* Initialise an IO device explicitly - to permit lazy initialisation or +- * re-initialisation */ +-int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params) { +- int result = 0; +- assert(dev_handle != (uintptr_t)NULL); +- assert(is_valid_dev(dev_handle)); +- +- io_dev_info_t *dev = (io_dev_info_t *)dev_handle; +- +- /* Absence of registered function implies NOP here */ +- if (dev->funcs->dev_init != NULL) { +- result = dev->funcs->dev_init(dev, init_params); +- } +- +- return result; +-} +- +-/* Close a connection to a device */ +-int io_dev_close(uintptr_t dev_handle) { +- int result = 0; +- assert(dev_handle != (uintptr_t)NULL); +- assert(is_valid_dev(dev_handle)); +- +- io_dev_info_t *dev = (io_dev_info_t *)dev_handle; +- +- /* Absence of registered function implies NOP here */ +- if (dev->funcs->dev_close != NULL) { +- result = dev->funcs->dev_close(dev); +- } +- +- return result; +-} +- +-/* Synchronous operations */ +- +-/* Open an IO entity */ +-int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle) { +- int result; +- assert((spec != (uintptr_t)NULL) && (handle != NULL)); +- assert(is_valid_dev(dev_handle)); +- +- io_dev_info_t *dev = (io_dev_info_t *)dev_handle; +- io_entity_t *entity; +- +- result = allocate_entity(&entity); +- +- if (result == 0) { +- assert(dev->funcs->open != NULL); +- result = dev->funcs->open(dev, spec, entity); +- +- if (result == 0) { +- entity->dev_handle = dev; +- set_handle(handle, entity); +- } else +- free_entity(entity); +- } +- return result; +-} +- +-/* Seek to a specific position in an IO entity */ +-int io_seek(uintptr_t handle, io_seek_mode_t mode, int32_t offset) { +- int result = -ENODEV; +- assert(is_valid_entity(handle) && is_valid_seek_mode(mode)); +- +- io_entity_t *entity = (io_entity_t *)handle; +- +- io_dev_info_t *dev = entity->dev_handle; +- +- if (dev->funcs->seek != NULL) +- result = dev->funcs->seek(entity, mode, offset); +- +- return result; +-} +- +-/* Determine the length of an IO entity */ +-int io_size(uintptr_t handle, size_t *length) { +- int result = -ENODEV; +- assert(is_valid_entity(handle) && (length != NULL)); +- +- io_entity_t *entity = (io_entity_t *)handle; +- +- io_dev_info_t *dev = entity->dev_handle; +- +- if (dev->funcs->size != NULL) result = dev->funcs->size(entity, length); +- +- return result; +-} +- +-/* Read data from an IO entity */ +-int io_read(uintptr_t handle, uintptr_t buffer, size_t length, +- size_t *length_read) { +- int result = -ENODEV; +- assert(is_valid_entity(handle)); +- +- io_entity_t *entity = (io_entity_t *)handle; +- +- io_dev_info_t *dev = entity->dev_handle; +- +- if (dev->funcs->read != NULL) +- result = dev->funcs->read(entity, buffer, length, length_read); +- +- return result; +-} +- +-/* Write data to an IO entity */ +-int io_write(uintptr_t handle, const uintptr_t buffer, size_t length, +- size_t *length_written) { +- int result = -ENODEV; +- assert(is_valid_entity(handle)); +- +- io_entity_t *entity = (io_entity_t *)handle; +- +- io_dev_info_t *dev = entity->dev_handle; +- +- if (dev->funcs->write != NULL) { +- result = dev->funcs->write(entity, buffer, length, length_written); +- } +- +- return result; +-} +- +-/* Close an IO entity */ +-int io_close(uintptr_t handle) { +- int result = 0; +- assert(is_valid_entity(handle)); +- +- io_entity_t *entity = (io_entity_t *)handle; +- +- io_dev_info_t *dev = entity->dev_handle; +- +- /* Absence of registered function implies NOP here */ +- if (dev->funcs->close != NULL) result = dev->funcs->close(entity); +- +- /* Ignore improbable free_entity failure */ +- (void)free_entity(entity); +- +- return result; +-} +diff --git a/platform/ext/target/arm/corstone1000/io/io_storage.h b/platform/ext/target/arm/corstone1000/io/io_storage.h +deleted file mode 100644 +index 0cdca5b26..000000000 +--- a/platform/ext/target/arm/corstone1000/io/io_storage.h ++++ /dev/null +@@ -1,92 +0,0 @@ +-/* +- * Copyright (c) 2022 Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: Apache-2.0 +- * +- * Licensed under the Apache License, Version 2.0 (the License); you may +- * not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an AS IS BASIS, WITHOUT +- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-#ifndef __IO_STORAGE_H__ +-#define __IO_STORAGE_H__ +- +-#include +-#include +- +-/* Access modes used when accessing data on a device */ +-#define IO_MODE_INVALID (0) +-#define IO_MODE_RO (1 << 0) +-#define IO_MODE_RW (1 << 1) +- +-/* Device type which can be used to enable policy decisions about which device +- * to access */ +-typedef enum { +- IO_TYPE_INVALID, +- IO_TYPE_SEMIHOSTING, +- IO_TYPE_MEMMAP, +- IO_TYPE_DUMMY, +- IO_TYPE_FIRMWARE_IMAGE_PACKAGE, +- IO_TYPE_BLOCK, +- IO_TYPE_MTD, +- IO_TYPE_MMC, +- IO_TYPE_STM32IMAGE, +- IO_TYPE_ENCRYPTED, +- IO_TYPE_MAX +-} io_type_t; +- +-/* Modes used when seeking data on a supported device */ +-typedef enum { +- IO_SEEK_INVALID, +- IO_SEEK_SET, +- IO_SEEK_END, +- IO_SEEK_CUR, +- IO_SEEK_MAX +-} io_seek_mode_t; +- +-/* Connector type, providing a means of identifying a device to open */ +-struct io_dev_connector; +- +-/* Block specification - used to refer to data on a device supporting +- * block-like entities */ +-typedef struct io_block_spec { +- size_t offset; +- size_t length; +-} io_block_spec_t; +- +- +-/* Open a connection to a device */ +-int io_dev_open(const struct io_dev_connector *dev_con, +- const uintptr_t dev_spec, uintptr_t *handle); +- +-/* Initialise a device explicitly - to permit lazy initialisation or +- * re-initialisation */ +-int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params); +- +-/* Close a connection to a device */ +-int io_dev_close(uintptr_t dev_handle); +- +-/* Synchronous operations */ +-int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle); +- +-int io_seek(uintptr_t handle, io_seek_mode_t mode, int32_t offset); +- +-int io_size(uintptr_t handle, size_t *length); +- +-int io_read(uintptr_t handle, uintptr_t buffer, size_t length, +- size_t *length_read); +- +-int io_write(uintptr_t handle, const uintptr_t buffer, size_t length, +- size_t *length_written); +- +-int io_close(uintptr_t handle); +- +-#endif /* __IO_STORAGE_H__ */ +diff --git a/platform/ext/target/arm/corstone1000/partition/efi.h b/platform/ext/target/arm/corstone1000/partition/efi.h +deleted file mode 100644 +index 7e6a4bc88..000000000 +--- a/platform/ext/target/arm/corstone1000/partition/efi.h ++++ /dev/null +@@ -1,37 +0,0 @@ +-/* +- * Copyright (c) 2021, Linaro Limited +- * +- * SPDX-License-Identifier: BSD-3-Clause +- * +- */ +- +-#ifndef DRIVERS_PARTITION_EFI_H +-#define DRIVERS_PARTITION_EFI_H +- +-#include +-#include +- +-#include "uuid.h" +- +-#define EFI_NAMELEN 36 +- +-static inline int guidcmp(const void *g1, const void *g2) { +- return memcmp(g1, g2, sizeof(struct efi_guid)); +-} +- +-static inline void *guidcpy(void *dst, const void *src) { +- return memcpy(dst, src, sizeof(struct efi_guid)); +-} +- +-#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ +- { \ +- (a) & 0xffffffff, (b)&0xffff, (c)&0xffff, { \ +- (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) \ +- } \ +- } +- +-#define NULL_GUID \ +- EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ +- 0x00, 0x00) +- +-#endif /* DRIVERS_PARTITION_EFI_H */ +diff --git a/platform/ext/target/arm/corstone1000/partition/gpt.c b/platform/ext/target/arm/corstone1000/partition/gpt.c +deleted file mode 100644 +index 8549785e3..000000000 +--- a/platform/ext/target/arm/corstone1000/partition/gpt.c ++++ /dev/null +@@ -1,58 +0,0 @@ +-/* +- * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#include "gpt.h" +- +-#include +-#include +-#include +- +-#include "efi.h" +- +-static int unicode_to_ascii(unsigned short *str_in, unsigned char *str_out) { +- uint8_t *name; +- int i; +- +- assert((str_in != NULL) && (str_out != NULL)); +- +- name = (uint8_t *)str_in; +- +- assert(name[0] != '\0'); +- +- /* check whether the unicode string is valid */ +- for (i = 1; i < (EFI_NAMELEN << 1); i += 2) { +- if (name[i] != '\0') return -EINVAL; +- } +- /* convert the unicode string to ascii string */ +- for (i = 0; i < (EFI_NAMELEN << 1); i += 2) { +- str_out[i >> 1] = name[i]; +- if (name[i] == '\0') break; +- } +- return 0; +-} +- +-int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry) { +- int result; +- +- assert((gpt_entry != NULL) && (entry != NULL)); +- +- if ((gpt_entry->first_lba == 0) && (gpt_entry->last_lba == 0)) { +- return -EINVAL; +- } +- +- memset(entry, 0, sizeof(partition_entry_t)); +- result = unicode_to_ascii(gpt_entry->name, (uint8_t *)entry->name); +- if (result != 0) { +- return result; +- } +- entry->start = (uint64_t)gpt_entry->first_lba * PLAT_PARTITION_BLOCK_SIZE; +- entry->length = (uint64_t)(gpt_entry->last_lba - gpt_entry->first_lba + 1) * +- PLAT_PARTITION_BLOCK_SIZE; +- guidcpy(&entry->part_guid, &gpt_entry->unique_uuid); +- guidcpy(&entry->type_guid, &gpt_entry->type_uuid); +- +- return 0; +-} +diff --git a/platform/ext/target/arm/corstone1000/partition/gpt.h b/platform/ext/target/arm/corstone1000/partition/gpt.h +deleted file mode 100644 +index b528fc05c..000000000 +--- a/platform/ext/target/arm/corstone1000/partition/gpt.h ++++ /dev/null +@@ -1,51 +0,0 @@ +-/* +- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#ifndef GPT_H +-#define GPT_H +- +-#include "efi.h" +-#include "partition.h" +-#include "uuid.h" +- +-#define PARTITION_TYPE_GPT 0xee +-#define GPT_HEADER_OFFSET PLAT_PARTITION_BLOCK_SIZE +-#define GPT_ENTRY_OFFSET (GPT_HEADER_OFFSET + PLAT_PARTITION_BLOCK_SIZE) +- +-#define GPT_SIGNATURE "EFI PART" +- +-typedef struct gpt_entry { +- struct efi_guid type_uuid; +- struct efi_guid unique_uuid; +- unsigned long long first_lba; +- unsigned long long last_lba; +- unsigned long long attr; +- unsigned short name[EFI_NAMELEN]; +-} gpt_entry_t; +- +-typedef struct gpt_header { +- unsigned char signature[8]; +- unsigned int revision; +- unsigned int size; +- unsigned int header_crc; +- unsigned int reserved; +- unsigned long long current_lba; +- unsigned long long backup_lba; +- unsigned long long first_lba; +- unsigned long long last_lba; +- struct efi_guid disk_uuid; +- /* starting LBA of array of partition entries */ +- unsigned long long part_lba; +- /* number of partition entries in array */ +- unsigned int list_num; +- /* size of a single partition entry (usually 128) */ +- unsigned int part_size; +- unsigned int part_crc; +-} gpt_header_t; +- +-int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry); +- +-#endif /* GPT_H */ +diff --git a/platform/ext/target/arm/corstone1000/partition/mbr.h b/platform/ext/target/arm/corstone1000/partition/mbr.h +deleted file mode 100644 +index e77f36701..000000000 +--- a/platform/ext/target/arm/corstone1000/partition/mbr.h ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* +- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#ifndef MBR_H +-#define MBR_H +- +-#define MBR_OFFSET 0 +- +-#define MBR_PRIMARY_ENTRY_OFFSET 0x1be +-#define MBR_PRIMARY_ENTRY_SIZE 0x10 +-#define MBR_PRIMARY_ENTRY_NUMBER 4 +-#define MBR_CHS_ADDRESS_LEN 3 +- +-#define MBR_SIGNATURE_FIRST 0x55 +-#define MBR_SIGNATURE_SECOND 0xAA +- +-typedef struct mbr_entry { +- unsigned char status; +- unsigned char first_sector[MBR_CHS_ADDRESS_LEN]; +- unsigned char type; +- unsigned char last_sector[MBR_CHS_ADDRESS_LEN]; +- unsigned int first_lba; +- unsigned int sector_nums; +-} mbr_entry_t; +- +-#endif /* MBR_H */ +diff --git a/platform/ext/target/arm/corstone1000/partition/partition.c b/platform/ext/target/arm/corstone1000/partition/partition.c +deleted file mode 100644 +index d76e123d7..000000000 +--- a/platform/ext/target/arm/corstone1000/partition/partition.c ++++ /dev/null +@@ -1,324 +0,0 @@ +-/* +- * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#include "partition.h" +- +-#include +-#include +-#include +-#include +-#include +- +-#include "efi.h" +-#include "gpt.h" +-#include "mbr.h" +- +-#include "io_storage.h" +-#include "platform.h" +-#include "soft_crc.h" +- +-#define PLAT_LOG_MODULE_NAME "partition" +-#include "platform_log.h" +- +-static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE]; +-static partition_entry_list_t list; +- +-#if LOG_LEVEL >= LOG_LEVEL_DEBUG +-static void dump_entries(int num) { +- char name[EFI_NAMELEN]; +- int i, j, len; +- +- VERBOSE("Partition table with %d entries:", num); +- for (i = 0; i < num; i++) { +- len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); +- for (j = 0; j < EFI_NAMELEN - len - 1; j++) { +- name[len + j] = ' '; +- } +- name[EFI_NAMELEN - 1] = '\0'; +- VERBOSE("%d: %s %x%x %d", i + 1, name, +- (uint32_t)(list.list[i].start >> 32), +- (uint32_t)list.list[i].start, +- (uint32_t)(list.list[i].start + list.list[i].length - 4)); +- } +-} +-#else +-#define dump_entries(num) ((void)num) +-#endif +- +-/* +- * Load the first sector that carries MBR header. +- * The MBR boot signature should be always valid whether it's MBR or GPT. +- */ +-static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) { +- size_t bytes_read; +- uintptr_t offset; +- int result; +- +- assert(mbr_entry != NULL); +- /* MBR partition table is in LBA0. */ +- result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); +- if (result != 0) { +- WARN("Failed to seek (%i)\n", result); +- return result; +- } +- result = io_read(image_handle, (uintptr_t)&mbr_sector, +- PLAT_PARTITION_BLOCK_SIZE, &bytes_read); +- if (result != 0) { +- WARN("Failed to read data (%i)\n", result); +- return result; +- } +- +- /* Check MBR boot signature. */ +- if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || +- (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { +- ERROR("MBR signature isn't correct"); +- return -ENOENT; +- } +- offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET; +- memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); +- return 0; +-} +- +-/* +- * Load GPT header and check the GPT signature and header CRC. +- * If partition numbers could be found, check & update it. +- */ +-static int load_gpt_header(uintptr_t image_handle) { +- gpt_header_t header; +- size_t bytes_read; +- int result; +- uint32_t header_crc, calc_crc; +- +- result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET); +- if (result != 0) { +- return result; +- } +- result = io_read(image_handle, (uintptr_t)&header, sizeof(gpt_header_t), +- &bytes_read); +- if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { +- return result; +- } +- if (memcmp(header.signature, GPT_SIGNATURE, sizeof(header.signature)) != +- 0) { +- return -EINVAL; +- } +- +- /* +- * UEFI Spec 2.8 March 2019 Page 119: HeaderCRC32 value is +- * computed by setting this field to 0, and computing the +- * 32-bit CRC for HeaderSize bytes. +- */ +- header_crc = header.header_crc; +- header.header_crc = 0U; +- +- calc_crc = crc32((uint8_t *)&header, DEFAULT_GPT_HEADER_SIZE); +- if (header_crc != calc_crc) { +- ERROR("Invalid GPT Header CRC: Expected 0x%x but got 0x%x.\n", +- header_crc, calc_crc); +- return -EINVAL; +- } +- +- header.header_crc = header_crc; +- +- /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ +- list.entry_count = header.list_num; +- if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { +- list.entry_count = PLAT_PARTITION_MAX_ENTRIES; +- } +- return 0; +-} +- +-static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry, +- int part_number) { +- size_t bytes_read; +- uintptr_t offset; +- int result; +- +- assert(mbr_entry != NULL); +- /* MBR partition table is in LBA0. */ +- result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); +- if (result != 0) { +- WARN("Failed to seek (%i)\n", result); +- return result; +- } +- result = io_read(image_handle, (uintptr_t)&mbr_sector, +- PLAT_PARTITION_BLOCK_SIZE, &bytes_read); +- if (result != 0) { +- WARN("Failed to read data (%i)\n", result); +- return result; +- } +- +- /* Check MBR boot signature. */ +- if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || +- (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { +- return -ENOENT; +- } +- offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET + +- MBR_PRIMARY_ENTRY_SIZE * part_number; +- memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); +- +- return 0; +-} +- +-static int load_mbr_entries(uintptr_t image_handle) { +- mbr_entry_t mbr_entry; +- int i; +- +- list.entry_count = MBR_PRIMARY_ENTRY_NUMBER; +- +- for (i = 0; i < list.entry_count; i++) { +- load_mbr_entry(image_handle, &mbr_entry, i); +- list.list[i].start = mbr_entry.first_lba * 512; +- list.list[i].length = mbr_entry.sector_nums * 512; +- list.list[i].name[0] = mbr_entry.type; +- } +- +- return 0; +-} +- +-static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) { +- size_t bytes_read; +- int result; +- +- assert(entry != NULL); +- result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), +- &bytes_read); +- if (sizeof(gpt_entry_t) != bytes_read) return -EINVAL; +- return result; +-} +- +-static int verify_partition_gpt(uintptr_t image_handle) { +- gpt_entry_t entry; +- int result, i; +- +- for (i = 0; i < list.entry_count; i++) { +- result = load_gpt_entry(image_handle, &entry); +- assert(result == 0); +- if (result != 0) { +- break; +- } +- result = parse_gpt_entry(&entry, &list.list[i]); +- if (result != 0) { +- break; +- } +- } +- if (i == 0) { +- return -EINVAL; +- } +- /* +- * Only records the valid partition number that is loaded from +- * partition table. +- */ +- list.entry_count = i; +- dump_entries(list.entry_count); +- +- return 0; +-} +- +-int load_partition_table(unsigned int image_id) { +- uintptr_t dev_handle, image_handle, image_spec = 0; +- mbr_entry_t mbr_entry; +- int result; +- +- result = plat_get_image_source(image_id, &dev_handle, &image_spec); +- if (result != 0) { +- WARN("Failed to obtain reference to image id=%u (%i)\n", image_id, +- result); +- return result; +- } +- +- result = io_open(dev_handle, image_spec, &image_handle); +- if (result != 0) { +- WARN("Failed to open image id=%u (%i)\n", image_id, result); +- return result; +- } +- +- result = load_mbr_header(image_handle, &mbr_entry); +- if (result != 0) { +- ERROR("Loading mbr header failed with image id=%u (%i)\n", image_id, +- result); +- return result; +- } +- if (mbr_entry.type == PARTITION_TYPE_GPT) { +- INFO("Loading gpt header"); +- result = load_gpt_header(image_handle); +- assert(result == 0); +- if (result != 0) { +- ERROR("Failed load gpt header! %i", result); +- goto load_partition_table_exit; +- } +- result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET); +- assert(result == 0); +- if (result != 0) { +- ERROR("Failed seek gpt header! %i", result); +- goto load_partition_table_exit; +- } +- result = verify_partition_gpt(image_handle); +- if (result != 0) { +- ERROR("Failed verify gpt partition %i", result); +- goto load_partition_table_exit; +- } +- } else { +- result = load_mbr_entries(image_handle); +- } +- +-load_partition_table_exit: +- io_close(image_handle); +- return result; +-} +- +-const partition_entry_t *get_partition_entry(const char *name) { +- int i; +- +- for (i = 0; i < list.entry_count; i++) { +- if (strcmp(name, list.list[i].name) == 0) { +- return &list.list[i]; +- } +- } +- return NULL; +-} +- +-const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_uuid) { +- int i; +- +- for (i = 0; i < list.entry_count; i++) { +- if (guidcmp(type_uuid, &list.list[i].type_guid) == 0) { +- return &list.list[i]; +- } +- } +- +- return NULL; +-} +- +-const partition_entry_t *get_partition_replica_by_type(const uuid_t *type_uuid) { +- int count = 0; +- int i; +- +- for (i = 0; i < list.entry_count; i++) { +- if (guidcmp(type_uuid, &list.list[i].type_guid) == 0) { +- if (++count == 2) +- return &list.list[i]; +- } +- } +- +- return NULL; +-} +- +-const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid) { +- int i; +- +- for (i = 0; i < list.entry_count; i++) { +- if (guidcmp(part_uuid, &list.list[i].part_guid) == 0) { +- return &list.list[i]; +- } +- } +- +- return NULL; +-} +- +-const partition_entry_list_t *get_partition_entry_list(void) { return &list; } +- +-void partition_init(unsigned int image_id) { load_partition_table(image_id); } +diff --git a/platform/ext/target/arm/corstone1000/partition/partition.h b/platform/ext/target/arm/corstone1000/partition/partition.h +deleted file mode 100644 +index 450cf20a0..000000000 +--- a/platform/ext/target/arm/corstone1000/partition/partition.h ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* +- * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- */ +- +-#ifndef PARTITION_H +-#define PARTITION_H +- +-#include +- +-#include "efi.h" +-#include "uuid.h" +- +-#if !PLAT_PARTITION_MAX_ENTRIES +-#define PLAT_PARTITION_MAX_ENTRIES 16 +-#endif /* PLAT_PARTITION_MAX_ENTRIES */ +- +-#if !PLAT_PARTITION_BLOCK_SIZE +-#define PLAT_PARTITION_BLOCK_SIZE 512 +-#endif /* PLAT_PARTITION_BLOCK_SIZE */ +- +-#define LEGACY_PARTITION_BLOCK_SIZE 512 +- +-#define DEFAULT_GPT_HEADER_SIZE 92 +- +-typedef struct partition_entry { +- uint64_t start; +- uint64_t length; +- char name[EFI_NAMELEN]; +- struct efi_guid part_guid; +- struct efi_guid type_guid; +-} partition_entry_t; +- +-typedef struct partition_entry_list { +- partition_entry_t list[PLAT_PARTITION_MAX_ENTRIES]; +- int entry_count; +-} partition_entry_list_t; +- +-int load_partition_table(unsigned int image_id); +-const partition_entry_t *get_partition_entry(const char *name); +-const partition_entry_t *get_partition_entry_by_type(const uuid_t *type_guid); +-const partition_entry_t *get_partition_replica_by_type(const uuid_t *type_uuid); +-const partition_entry_t *get_partition_entry_by_uuid(const uuid_t *part_uuid); +-const partition_entry_list_t *get_partition_entry_list(void); +-void partition_init(unsigned int image_id); +- +-#endif /* PARTITION_H */ +diff --git a/platform/ext/target/arm/corstone1000/partition/uuid.h b/platform/ext/target/arm/corstone1000/partition/uuid.h +deleted file mode 100644 +index 06fec5a3c..000000000 +--- a/platform/ext/target/arm/corstone1000/partition/uuid.h ++++ /dev/null +@@ -1,76 +0,0 @@ +-/*- +- * Copyright (c) 2002 Marcel Moolenaar +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * +- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- * +- * $FreeBSD$ +- */ +- +-/* +- * Portions copyright (c) 2014-2020, ARM Limited and Contributors. +- * All rights reserved. +- */ +- +-#ifndef UUID_H +-#define UUID_H +- +-#include +- +-/* Length of a node address (an IEEE 802 address). */ +-#define _UUID_NODE_LEN 6 +- +-/* Length of UUID string including dashes. */ +-#define _UUID_STR_LEN 36 +- +-/* +- * See also: +- * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt +- * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm +- * +- * A DCE 1.1 compatible source representation of UUIDs. +- */ +-struct uuid { +- uint8_t time_low[4]; +- uint8_t time_mid[2]; +- uint8_t time_hi_and_version[2]; +- uint8_t clock_seq_hi_and_reserved; +- uint8_t clock_seq_low; +- uint8_t node[_UUID_NODE_LEN]; +-}; +- +-struct efi_guid { +- uint32_t time_low; +- uint16_t time_mid; +- uint16_t time_hi_and_version; +- uint8_t clock_seq_and_node[8]; +-}; +- +-union uuid_helper_t { +- struct uuid uuid_struct; +- struct efi_guid efi_guid; +-}; +- +-/* XXX namespace pollution? */ +-typedef struct uuid uuid_t; +- +-#endif /* UUID_H */ +diff --git a/platform/ext/target/arm/corstone1000/platform.c b/platform/ext/target/arm/corstone1000/platform.c +index 32fdc55aa..c8157752a 100644 +--- a/platform/ext/target/arm/corstone1000/platform.c ++++ b/platform/ext/target/arm/corstone1000/platform.c +@@ -10,90 +10,25 @@ + #include "Driver_Flash.h" + #include "flash_layout.h" + +-#include "io_driver.h" +-#include "io_flash.h" +-#include "io_storage.h" ++#include "io_gpt.h" + + #include "platform.h" + + #define PLAT_LOG_MODULE_NAME "platform" + #include "platform_log.h" + +-typedef struct { +- uintptr_t dev_handle; +- uintptr_t image_spec; +-} platform_image_source_t; +- + 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 = (uintptr_t)local_block_flash, +- .bufferlen = FLASH_SECTOR_SIZE, +- .base_addr = FLASH_BASE_ADDRESS, +- .flash_driver = (uintptr_t)&FLASH_DEV_NAME, +-}; +-static io_block_spec_t flash_spec = { +- .offset = FLASH_BASE_ADDRESS, +- .length = FLASH_TOTAL_SIZE +-}; +- +-static platform_image_source_t platform_image_source[] = { +- [PLATFORM_GPT_IMAGE] = { +- .dev_handle = (uintptr_t)NULL, +- .image_spec = (uintptr_t)&flash_spec, +- } +-}; + + /* Initialize io storage of the platform */ + int32_t plat_io_storage_init(void) + { +- int rc = -1; +- uintptr_t flash_dev_handle = (uintptr_t)NULL; +- uintptr_t flash_handle = (uintptr_t)NULL; + +- rc = register_io_dev_flash((const io_dev_connector_t **) &flash_dev_con); ++ /* The GPT library requires a flash driver in order to do I/O */ ++ int rc = register_flash_io_gpt(&FLASH_DEV_NAME); + if (rc != 0) { + ERROR("Failed to register io flash rc: %d", rc); +- return rc; + } + +- rc = io_dev_open(flash_dev_con, (const uintptr_t)&flash_dev_spec, &flash_dev_handle); +- if (rc != 0) { +- ERROR("Failed to open io flash dev rc: %d", rc); +- return rc; +- } +- +- VERBOSE("Flash_dev_handle = %p",flash_dev_handle); +- +- rc = io_open(flash_dev_handle, (const uintptr_t)&flash_spec, &flash_handle); +- if (rc != 0) { +- ERROR("Failed to open io flash rc: %d", rc); +- return rc; +- } +- +- VERBOSE("Flash_handle = %p",flash_handle); +- +- rc = io_close(flash_handle); +- if (rc != 0) { +- ERROR("Failed to close io flash rc: %d", rc); +- return rc; +- } +- /* Update the platform image source that uses the flash with dev handles */ +- platform_image_source[PLATFORM_GPT_IMAGE].dev_handle = flash_dev_handle; +- + return rc; + } +- +-/* Return an IO device handle and specification which can be used to access +- * an image. This has to be implemented for the GPT parser. */ +-int32_t plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, +- uintptr_t *image_spec) { +- if (image_id >= PLATFORM_IMAGE_COUNT) { +- return -1; +- } +- *dev_handle = platform_image_source[image_id].dev_handle; +- *image_spec = platform_image_source[image_id].image_spec; +- return 0; +-} +diff --git a/platform/ext/target/arm/corstone1000/platform.h b/platform/ext/target/arm/corstone1000/platform.h +index 906a8f9ae..96bee50dc 100644 +--- a/platform/ext/target/arm/corstone1000/platform.h ++++ b/platform/ext/target/arm/corstone1000/platform.h +@@ -8,22 +8,28 @@ + #ifndef __PLATFORM_H__ + #define __PLATFORM_H__ + +-typedef enum { +- PLATFORM_GPT_IMAGE = 0, +- PLATFORM_IMAGE_COUNT, +-}platform_image_id_t; ++#include "efi_guid_structs.h" + +-#define FWU_METADATA_TYPE_UUID \ +- ((uuid_t){{0xa0, 0x84, 0x7a, 0x8a}, {0x87, 0x83}, {0xf6, 0x40}, 0xab, 0x41, {0xa8, 0xb9, 0xa5, 0xa6, 0x0d, 0x23}}) +-#define PRIVATE_METADATA_TYPE_UUID \ +- ((uuid_t){{0xc3, 0x5d, 0xb5, 0xec}, {0xb7, 0x8a}, {0x84, 0x4a}, 0xab, 0x56, {0xeb, 0x0a, 0x99, 0x74, 0xdb, 0x42}}) ++#if !PLAT_GPT_MAX_PARTITIONS ++#define PLAT_GPT_MAX_PARTITIONS 16 ++#endif /* PLAT_GPT_MAX_PARTITIONS */ ++ ++#define FWU_METADATA_TYPE_UUID \ ++ MAKE_EFI_GUID( \ ++ 0x8A7A84A0, \ ++ 0x8387, \ ++ 0x40F6, \ ++ 0xAB, 0x41, \ ++ 0xA8, 0xB9, 0xA5, 0xA6, 0x0D, 0x23) ++#define PRIVATE_METADATA_TYPE_UUID \ ++ MAKE_EFI_GUID( \ ++ 0xECB55DC3, \ ++ 0x8AB7, \ ++ 0x4A84, \ ++ 0xAB, 0x56, \ ++ 0xEB, 0x0A, 0x99, 0x74, 0xDB, 0x42) + + /* Initialize io storage of the platform */ + int32_t plat_io_storage_init(void); + +-/* Return an IO device handle and specification which can be used to access +- * an image. This has to be implemented for the GPT parser. */ +-int32_t plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, +- uintptr_t *image_spec); +- + #endif /*__PLATFORM_H__*/ +diff --git a/platform/ext/target/arm/corstone1000/soft_crc/soft_crc.c b/platform/ext/target/arm/corstone1000/soft_crc/soft_crc.c +deleted file mode 100644 +index 85f1e30d9..000000000 +--- a/platform/ext/target/arm/corstone1000/soft_crc/soft_crc.c ++++ /dev/null +@@ -1,121 +0,0 @@ +-/* Copyright (C) 1986 Gary S. Brown. You may use this program, or +- code or tables extracted from it, as desired without restriction.*/ +- +-/* First, the polynomial itself and its table of feedback terms. The */ +-/* polynomial is */ +-/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +-/* Note that we take it "backwards" and put the highest-order term in */ +-/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +-/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +-/* the MSB being 1. */ +- +-/* Note that the usual hardware shift register implementation, which */ +-/* is what we're using (we're merely optimizing it by doing eight-bit */ +-/* chunks at a time) shifts bits into the lowest-order term. In our */ +-/* implementation, that means shifting towards the right. Why do we */ +-/* do it this way? Because the calculated CRC must be transmitted in */ +-/* order from highest-order term to lowest-order term. UARTs transmit */ +-/* characters in order from LSB to MSB. By storing the CRC this way, */ +-/* we hand it to the UART in the order low-byte to high-byte; the UART */ +-/* sends each low-bit to hight-bit; and the result is transmission bit */ +-/* by bit from highest- to lowest-order term without requiring any bit */ +-/* shuffling on our part. Reception works similarly. */ +- +-/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +-/* */ +-/* 1. The table can be generated at runtime if desired; code to do so */ +-/* is shown later. It might not be obvious, but the feedback */ +-/* terms simply represent the results of eight shift/xor opera- */ +-/* tions for all combinations of data and CRC register values. */ +-/* */ +-/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ +-/* be they sixteen or thirty-two bits wide. You simply choose the */ +-/* appropriate table. Alternatively, because the table can be */ +-/* generated at runtime, you can start by generating the table for */ +-/* the polynomial in question and use exactly the same "updcrc", */ +-/* if your application needn't simultaneously handle two CRC */ +-/* polynomials. (Note, however, that XMODEM is strange.) */ +-/* */ +-/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ +-/* of course, 32-bit entries work OK if the high 16 bits are zero. */ +-/* */ +-/* 4. The values must be right-shifted by eight bits by the "updcrc" */ +-/* logic; the shift must be unsigned (bring in zeroes). On some */ +-/* hardware you could probably optimize the shift in assembler by */ +-/* using byte-swap instructions. */ +- +-/** +- * The code derived from work by Gary S. Brown. +-*/ +- +-#include "soft_crc.h" +- +- +-const static uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ +-0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, +-0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, +-0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, +-0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +-0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, +-0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, +-0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, +-0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +-0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, +-0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, +-0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, +-0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +-0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, +-0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, +-0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, +-0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +-0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, +-0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, +-0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, +-0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +-0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, +-0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, +-0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, +-0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +-0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, +-0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, +-0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, +-0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +-0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, +-0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, +-0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, +-0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +-0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, +-0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, +-0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, +-0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +-0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, +-0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, +-0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, +-0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +-0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, +-0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, +-0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +-}; +- +-#define UPDC32(octet,crc) (crc_32_tab[((crc)\ +- ^ ((uint8_t)octet)) & 0xff] ^ ((crc) >> 8)) +- +-static inline uint32_t crc32buf(char *buf, size_t len) +-{ +- register uint32_t oldcrc32; +- +- oldcrc32 = 0xFFFFFFFF; +- +- for ( ; len; --len, ++buf) +- { +- oldcrc32 = UPDC32(*buf, oldcrc32); +- } +- +- return ~oldcrc32; +-} +- +-/* Calculate crc32 */ +-uint32_t crc32(const void *buf, size_t len) { +- return crc32buf(buf, len); +-} +- +diff --git a/platform/ext/target/arm/corstone1000/soft_crc/soft_crc.h b/platform/ext/target/arm/corstone1000/soft_crc/soft_crc.h +deleted file mode 100644 +index e5b06075c..000000000 +--- a/platform/ext/target/arm/corstone1000/soft_crc/soft_crc.h ++++ /dev/null +@@ -1,18 +0,0 @@ +-/* +- * Copyright (c) 2023, Arm Limited. All rights reserved. +- * +- * SPDX-License-Identifier: BSD-3-Clause +- * +- */ +- +-#ifndef __SOFT_CRC_H__ +-#define __SOFT_CRC_H__ +- +-#include +-#include +- +-/* Calculate crc32 */ +-uint32_t crc32(const void *buf, size_t len); +- +-#endif /* __SOFT_CRC_H__ */ +- diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0042-plat-cs1k-Move-variable-from-stack-to-data.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0042-plat-cs1k-Move-variable-from-stack-to-data.patch new file mode 100644 index 00000000..d5921afa --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0042-plat-cs1k-Move-variable-from-stack-to-data.patch @@ -0,0 +1,55 @@ +From 201166be49ca4c0079cf804f208534f201cb4b65 Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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; diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0043-plat-cs1k-Create-and-remove-FWU-image-partitions.patch b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0043-plat-cs1k-Create-and-remove-FWU-image-partitions.patch new file mode 100644 index 00000000..513765e9 --- /dev/null +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/files/corstone1000/0043-plat-cs1k-Create-and-remove-FWU-image-partitions.patch @@ -0,0 +1,521 @@ +From 93101e6de045c0c4d633c502616ccf184c07e70a Mon Sep 17 00:00:00 2001 +From: Frazer Carsley +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 +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; + } + diff --git a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m-corstone1000.inc b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m-corstone1000.inc index b55a61ac..ff3a87a9 100644 --- a/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m-corstone1000.inc +++ b/meta-arm-bsp/recipes-bsp/trusted-firmware-m/trusted-firmware-m-corstone1000.inc @@ -65,6 +65,16 @@ SRC_URI:append:corstone1000 = " \ 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 \ " SRCREV_tfm-psa-adac:corstone1000 = "f2809ae231be33a1afcd7714f40756c67d846c88" @@ -78,7 +88,7 @@ SRC_URI:append:corstone1000-mps3 = " \ create_bl1_image(){ dd conv=notrunc bs=1 if=${D}${FIRMWARE_DIR}/bl1_1.bin of=${D}${FIRMWARE_DIR}/bl1.bin seek=0 - # Size of bl1_1.bin is 58KB (59392 bytes) - dd conv=notrunc bs=1 if=${D}${FIRMWARE_DIR}/bl1_provisioning_bundle.bin of=${D}${FIRMWARE_DIR}/bl1.bin seek=59392 + # Size of bl1_1.bin is 58KB (59208 bytes) + dd conv=notrunc bs=1 if=${D}${FIRMWARE_DIR}/bl1_provisioning_bundle.bin of=${D}${FIRMWARE_DIR}/bl1.bin seek=59208 } do_install[postfuncs] += "create_bl1_image" diff --git a/meta-arm-bsp/wic/corstone1000-flash-firmware.wks.in b/meta-arm-bsp/wic/corstone1000-flash-firmware-fvp.wks.in similarity index 65% rename from meta-arm-bsp/wic/corstone1000-flash-firmware.wks.in rename to meta-arm-bsp/wic/corstone1000-flash-firmware-fvp.wks.in index 78109aff..33699512 100644 --- a/meta-arm-bsp/wic/corstone1000-flash-firmware.wks.in +++ b/meta-arm-bsp/wic/corstone1000-flash-firmware-fvp.wks.in @@ -11,30 +11,24 @@ part --source empty --size 3k --offset 17k --part-name="reserved_1" --uuid B1F2F part --source empty --size 4k --align 4 --offset 20k --part-name="FWU-Metadata" --uuid 3FDFFEE1-3223-4C6B-80F9-B0E7D780C21D --part-type 8A7A84A0-8387-40F6-AB41-A8B9A5A60D23 part --source empty --size 4k --align 4 --offset 24k --part-name="Bkup-FWU-Metadata" --uuid B3068316-5351-4998-823A-3A7B09133EC1 --part-type 8A7A84A0-8387-40F6-AB41-A8B9A5A60D23 - -part --source empty --size 4k --align 4 --offset 28k --part-name="private_metadata_replica_2" --uuid 3CC3B456-DEC8-4CE3-BC5C-965483CE4828 --part-type ECB55DC3-8AB7-4A84-AB56-EB0A9974DB42 +part --source empty --size 4k --align 4 --offset 28k --part-name="private_metadata_replica_1" --uuid 3CC3B456-DEC8-4CE3-BC5C-965483CE4828 --part-type ECB55DC3-8AB7-4A84-AB56-EB0A9974DB42 part --source empty --size 4k --align 4 --offset 32k --part-name="private_metadata_replica_2" --uuid DCE9C503-8DFD-4DCB-8889-647E49641552 --part-type ECB55DC3-8AB7-4A84-AB56-EB0A9974DB42 +# The partition type of each of these four partitions should match the type of the images +# in a fiwmare update capsule # The size has to be aligned to TF-M's SE_BL2_PARTITION_SIZE (tfm/platform/ext/target/arm/corstone1000/partition/flash_layout.h) -part --source rawcopy --size 144k --sourceparams="file=trusted-firmware-m/bl2_signed.bin" --offset 36k --align 4 --part-name="bl2_primary" --uuid 9A3A8FBF-55EF-439C-80C9-A3F728033929 --part-type 64BD8ADB-02C0-4819-8688-03AB4CAB0ED9 +part --source rawcopy --size 144k --sourceparams="file=trusted-firmware-m/bl2_signed.bin" --offset 36k --align 4 --part-name="bl2_primary" --uuid 9A3A8FBF-55EF-439C-80C9-A3F728033929 --part-type F1D883F9-DFEB-5363-98D8-686EE3B69F4F # The size has to be aligned to TF-M's TFM_PARTITION_SIZE (tfm/platform/ext/target/arm/corstone1000/partition/flash_layout.h) -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 D763C27F-07F6-4FF0-B2F3-060CB465CD4E +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 2 --sourceparams="file=signed_fip.bin" --align 4 --part-name="FIP_A" --uuid B9C7AC9D-40FF-4675-956B-EEF4DE9DF1C5 --part-type B5EB19BD-CF56-45E8-ABA7-7ADB228FFEA7 +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 8197561D-6124-46FC-921E-141CC5745B05 - - -# The offset has to be aligned to TF-M's SE_BL2_BANK_1_OFFSET define (tfm/platform/ext/target/arm/corstone1000/partition/flash_layout.h) -part --source empty --size 144k --offset 16392k --align 4 --part-name="bl2_secondary" --uuid 3F0C49A4-48B7-4D1E-AF59-3E4A3CE1BA9F --part-type 64BD8ADB-02C0-4819-8688-03AB4CAB0ED9 -part --source empty --size 320k --align 4 --part-name="tfm_secondary" --uuid 009A6A12-64A6-4F0F-9882-57CD79A34A3D --part-type D763C27F-07F6-4FF0-B2F3-060CB465CD4E -part --source empty --size 2 --align 4 --part-name="FIP_B" --uuid 9424E370-7BC9-43BB-8C23-71EE645E1273 --part-type B5EB19BD-CF56-45E8-ABA7-7ADB228FFEA7 -part --source empty --size 12 --align 4 --part-name="kernel_secondary" --uuid A2698A91-F9B1-4629-9188-94E4520808F8 --part-type 8197561D-6124-46FC-921E-141CC5745B05 - +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 +# This ensures wic sets the size of the flash as 64MiB in the GPT header, despite only half being filled part --source empty --size 3k --offset 32748k --part-name="reserved_2" --uuid CCB18569-C0BA-42E0-A429-FE1DC862D660 bootloader --ptable gpt diff --git a/meta-arm-bsp/wic/corstone1000-flash-firmware-mps3.wks.in b/meta-arm-bsp/wic/corstone1000-flash-firmware-mps3.wks.in new file mode 100644 index 00000000..6487b927 --- /dev/null +++ b/meta-arm-bsp/wic/corstone1000-flash-firmware-mps3.wks.in @@ -0,0 +1,34 @@ +# WIC partitioning for corstone1000 internal flash +# Layout and maximum sizes (to be defined): +# + +# The entries with --offset parameter should not be relocated +# because BL1 code is statically configured for the given positions +# Partition sizes are fixed since corstone1000 does not support partial update +# and has a limit for each partition to grow. + +part --source empty --size 3k --offset 17k --part-name="reserved_1" --uuid B1F2FC8C-A7A3-4485-87CB-16961B8847D7 + +part --source empty --size 4k --align 4 --offset 20k --part-name="FWU-Metadata" --uuid 3FDFFEE1-3223-4C6B-80F9-B0E7D780C21D --part-type 8A7A84A0-8387-40F6-AB41-A8B9A5A60D23 +part --source empty --size 4k --align 4 --offset 24k --part-name="Bkup-FWU-Metadata" --uuid B3068316-5351-4998-823A-3A7B09133EC1 --part-type 8A7A84A0-8387-40F6-AB41-A8B9A5A60D23 +part --source empty --size 4k --align 4 --offset 28k --part-name="private_metadata_replica_1" --uuid 3CC3B456-DEC8-4CE3-BC5C-965483CE4828 --part-type ECB55DC3-8AB7-4A84-AB56-EB0A9974DB42 +part --source empty --size 4k --align 4 --offset 32k --part-name="private_metadata_replica_2" --uuid DCE9C503-8DFD-4DCB-8889-647E49641552 --part-type ECB55DC3-8AB7-4A84-AB56-EB0A9974DB42 + +# The partition type of each of these four partitions should match the type of the images +# in a fiwmare update capsule +# The size has to be aligned to TF-M's SE_BL2_PARTITION_SIZE (tfm/platform/ext/target/arm/corstone1000/partition/flash_layout.h) +part --source rawcopy --size 144k --sourceparams="file=trusted-firmware-m/bl2_signed.bin" --offset 36k --align 4 --part-name="bl2_primary" --uuid 9A3A8FBF-55EF-439C-80C9-A3F728033929 --part-type FBFBEFAA-0A56-50D5-B651-74091D3D62CF + +# The size has to be aligned to TF-M's TFM_PARTITION_SIZE (tfm/platform/ext/target/arm/corstone1000/partition/flash_layout.h) +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 AF4CC7AD-EE2E-5A39-AAD5-FAC8A1E6173C + +# Rawcopy of the FIP binary +part --source rawcopy --size 2 --sourceparams="file=signed_fip.bin" --align 4 --part-name="FIP_A" --uuid B9C7AC9D-40FF-4675-956B-EEF4DE9DF1C5 --part-type 55302F96-C4F0-5CF9-8624-E7CC388F2B68 + +# 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 3E8AC972-C33C-5CC9-90A0-CDD3159683EA + +# This ensures wic sets the size of the flash as 64MiB in the GPT header, despite only half being filled +part --source empty --size 3k --offset 32748k --part-name="reserved_2" --uuid CCB18569-C0BA-42E0-A429-FE1DC862D660 + +bootloader --ptable gpt