From eb096e4c03b80f9f31e5d15ca06e5a38e4112664 Mon Sep 17 00:00:00 2001
From: Bence Balogh <bence.balogh@arm.com>
Date: Tue, 7 Nov 2023 20:25:49 +0100
Subject: [PATCH 1/2] platform: corstone1000: Update MPU configuration

In Armv6-M the MPU requires the regions to be aligned with
region sizes.
The commit aligns the different code/data sections using the
alignment macros. The code/data sections can be covered by
multiple MPU regions in order to save memory.

Small adjustments had to be made in the memory layout in order to
not overflow the flash:
- Decreased TFM_PARTITION_SIZE
- Increased S_UNPRIV_DATA_SIZE

Added checks to the MPU configuration function for checking the
MPU constraints:
- Base address has to be aligned to the size
- The minimum MPU region size is 0x100
- The MPU can have 8 regions at most

Change-Id: I059468e8aba0822bb354fd1cd4987ac2bb1f34d1
Signed-off-by: Bence Balogh <bence.balogh@arm.com>
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/25393]

---
 .../target/arm/corstone1000/CMakeLists.txt    | 19 +++++
 .../arm/corstone1000/create-flash-image.sh    |  8 +-
 .../arm/corstone1000/partition/flash_layout.h |  2 +-
 .../arm/corstone1000/partition/region_defs.h  |  6 +-
 .../arm/corstone1000/tfm_hal_isolation.c      | 83 +++++++++++++++----
 5 files changed, 93 insertions(+), 25 deletions(-)

diff --git a/platform/ext/target/arm/corstone1000/CMakeLists.txt b/platform/ext/target/arm/corstone1000/CMakeLists.txt
index e6cf15b11..8817f514c 100644
--- a/platform/ext/target/arm/corstone1000/CMakeLists.txt
+++ b/platform/ext/target/arm/corstone1000/CMakeLists.txt
@@ -22,6 +22,25 @@ target_compile_definitions(platform_region_defs
     INTERFACE
         $<$<BOOL:${TFM_S_REG_TEST}>:TFM_S_REG_TEST>
 )
+
+# The Armv6-M MPU requires that the MPU regions be aligned to the region sizes.
+# The minimal region size is 0x100 bytes.
+#
+# The alignments have to be a power of two and ideally bigger than the section size (which
+# can be checked in the map file).
+# In some cases the alignment value is smaller than the actual section
+# size to save memory. In that case, multiple MPU region has to be configured to cover it.
+#
+# To save memory, the attributes are set to XN_EXEC_OK and AP_RO_PRIV_UNPRIV for
+# the SRAM so the PSA_ROT_LINKER_CODE, TFM_UNPRIV_CODE and APP_ROT_LINKER_CODE don't have to
+# be aligned. The higher-priority regions will overwrite these attributes if needed.
+# The RAM is also located in the SRAM so it has to be configured to overwrite these default
+# attributes.
+target_compile_definitions(platform_region_defs
+    INTERFACE
+        TFM_LINKER_APP_ROT_LINKER_DATA_ALIGNMENT=0x2000
+        TFM_LINKER_SP_META_PTR_ALIGNMENT=0x100
+)
 #========================= Platform common defs ===============================#
 
 # Specify the location of platform specific build dependencies.
diff --git a/platform/ext/target/arm/corstone1000/create-flash-image.sh b/platform/ext/target/arm/corstone1000/create-flash-image.sh
index 2522d3674..a6be61384 100755
--- a/platform/ext/target/arm/corstone1000/create-flash-image.sh
+++ b/platform/ext/target/arm/corstone1000/create-flash-image.sh
@@ -8,7 +8,7 @@
 
 ######################################################################
 # This script is to create a flash gpt image for corstone platform
-# 
+#
 #  Flash image layout:
 #       |------------------------------|
 #       |        Protective MBR        |
@@ -82,15 +82,15 @@ sgdisk  --mbrtogpt \
         --new=4:56:+4K --typecode=4:$PRIVATE_METADATA_TYPE_UUID --partition-guid=4:$(uuidgen) --change-name=4:'private_metadata_replica_1' \
         --new=5:64:+4k --typecode=5:$PRIVATE_METADATA_TYPE_UUID --partition-guid=5:$(uuidgen) --change-name=5:'private_metadata_replica_2' \
         --new=6:72:+100k --typecode=6:$SE_BL2_TYPE_UUID --partition-guid=6:$(uuidgen) --change-name=6:'bl2_primary' \
-        --new=7:272:+376K --typecode=7:$TFM_TYPE_UUID --partition-guid=7:$(uuidgen) --change-name=7:'tfm_primary' \
+        --new=7:272:+368K --typecode=7:$TFM_TYPE_UUID --partition-guid=7:$(uuidgen) --change-name=7:'tfm_primary' \
         --new=8:32784:+100k --typecode=8:$SE_BL2_TYPE_UUID --partition-guid=8:$(uuidgen) --change-name=8:'bl2_secondary' \
-        --new=9:32984:+376K --typecode=9:$TFM_TYPE_UUID --partition-guid=9:$(uuidgen) --change-name=9:'tfm_secondary' \
+        --new=9:32984:+368K --typecode=9:$TFM_TYPE_UUID --partition-guid=9:$(uuidgen) --change-name=9:'tfm_secondary' \
         --new=10:65496:65501  --partition-guid=10:$(uuidgen) --change-name=10:'reserved_2' \
         $IMAGE
 
 [ $? -ne 0 ] && echo "Error occurs while writing the GPT layout" && exit 1
 
-# Write partitions 
+# Write partitions
 # conv=notrunc avoids truncation to keep the geometry of the image.
 dd if=$BIN_DIR/bl2_signed.bin of=${IMAGE}  seek=72 conv=notrunc
 dd if=$BIN_DIR/tfm_s_signed.bin of=${IMAGE} seek=272 conv=notrunc
diff --git a/platform/ext/target/arm/corstone1000/partition/flash_layout.h b/platform/ext/target/arm/corstone1000/partition/flash_layout.h
index 568c8de28..7fffd94c6 100644
--- a/platform/ext/target/arm/corstone1000/partition/flash_layout.h
+++ b/platform/ext/target/arm/corstone1000/partition/flash_layout.h
@@ -134,7 +134,7 @@
 
 /* Bank configurations */
 #define BANK_PARTITION_SIZE             (0xFE0000)   /* 15.875 MB */
-#define TFM_PARTITION_SIZE              (0x5E000)    /* 376 KB */
+#define TFM_PARTITION_SIZE              (0x5C000)    /* 368 KB */
 
 /************************************************************/
 /* Bank : Images flash offsets are with respect to the bank */
diff --git a/platform/ext/target/arm/corstone1000/partition/region_defs.h b/platform/ext/target/arm/corstone1000/partition/region_defs.h
index 99e822f51..64ab786e5 100644
--- a/platform/ext/target/arm/corstone1000/partition/region_defs.h
+++ b/platform/ext/target/arm/corstone1000/partition/region_defs.h
@@ -1,8 +1,10 @@
 /*
- * Copyright (c) 2017-2022 Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2023 Arm Limited. All rights reserved.
  * Copyright (c) 2021-2023 Cypress Semiconductor Corporation (an Infineon company)
  * or an affiliate of Cypress Semiconductor Corporation. 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
@@ -53,7 +55,7 @@
 
 #define S_DATA_START            (SRAM_BASE + TFM_PARTITION_SIZE)
 #define S_DATA_SIZE             (SRAM_SIZE - TFM_PARTITION_SIZE)
-#define S_UNPRIV_DATA_SIZE      (0x2160)
+#define S_UNPRIV_DATA_SIZE      (0x4000)
 #define S_DATA_LIMIT            (S_DATA_START + S_DATA_SIZE - 1)
 #define S_DATA_PRIV_START       (S_DATA_START + S_UNPRIV_DATA_SIZE)
 
diff --git a/platform/ext/target/arm/corstone1000/tfm_hal_isolation.c b/platform/ext/target/arm/corstone1000/tfm_hal_isolation.c
index 01f7687bc..98e795dde 100644
--- a/platform/ext/target/arm/corstone1000/tfm_hal_isolation.c
+++ b/platform/ext/target/arm/corstone1000/tfm_hal_isolation.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
  * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon
  * company) or an affiliate of Cypress Semiconductor Corporation. All rights
  * reserved.
@@ -14,9 +14,11 @@
 #include "tfm_hal_isolation.h"
 #include "mpu_config.h"
 #include "mmio_defs.h"
+#include "flash_layout.h"
 
 #define PROT_BOUNDARY_VAL \
     ((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK)
+#define MPU_REGION_MIN_SIZE (0x100)
 
 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
 
@@ -31,20 +33,38 @@ REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
 REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Limit);
 #endif /* CONFIG_TFM_PARTITION_META */
 
-static void configure_mpu(uint32_t rnr, uint32_t base, uint32_t limit,
-                          uint32_t is_xn_exec, uint32_t ap_permissions)
+static enum tfm_hal_status_t configure_mpu(uint32_t rnr, uint32_t base,
+                          uint32_t limit, uint32_t is_xn_exec, uint32_t ap_permissions)
 {
-    uint32_t size; /* region size */
+    uint32_t rbar_size_field; /* region size as it is used in the RBAR */
     uint32_t rasr; /* region attribute and size register */
     uint32_t rbar; /* region base address register */
 
-    size = get_rbar_size_field(limit - base);
+    rbar_size_field = get_rbar_size_field(limit - base);
+
+    /* The MPU region's base address has to be aligned to the region
+     * size for a valid MPU configuration */
+    if ((base % (1 << (rbar_size_field + 1))) != 0) {
+        return TFM_HAL_ERROR_INVALID_INPUT;
+    }
+
+    /* The MPU supports only 8 memory regions */
+    if (rnr > 7) {
+        return TFM_HAL_ERROR_INVALID_INPUT;
+    }
+
+    /* The minimum size for a region is 0x100 bytes */
+    if((limit - base) < MPU_REGION_MIN_SIZE) {
+        return TFM_HAL_ERROR_INVALID_INPUT;
+    }
 
     rasr = ARM_MPU_RASR(is_xn_exec, ap_permissions, TEX, NOT_SHAREABLE,
-            NOT_CACHEABLE, NOT_BUFFERABLE, SUB_REGION_DISABLE, size);
+            NOT_CACHEABLE, NOT_BUFFERABLE, SUB_REGION_DISABLE, rbar_size_field);
     rbar = base & MPU_RBAR_ADDR_Msk;
 
     ARM_MPU_SetRegionEx(rnr, rbar, rasr);
+
+    return TFM_HAL_SUCCESS;
 }
 
 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
@@ -56,33 +76,60 @@ enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(
     uint32_t rnr = TFM_ISOLATION_REGION_START_NUMBER; /* current region number */
     uint32_t base; /* start address */
     uint32_t limit; /* end address */
+    enum tfm_hal_status_t ret;
 
     ARM_MPU_Disable();
 
-    /* TFM Core unprivileged code region */
-    base = (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
-    limit = (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
-
-    configure_mpu(rnr++, base, limit, XN_EXEC_OK, AP_RO_PRIV_UNPRIV);
-
-    /* RO region */
-    base = (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base);
-    limit = (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base);
+    /* Armv6-M MPU allows region overlapping. The region with the higher RNR
+     * will decide the attributes.
+     *
+     * The default attributes are set to XN_EXEC_OK and AP_RO_PRIV_UNPRIV for the
+     * whole SRAM so the PSA_ROT_LINKER_CODE, TFM_UNPRIV_CODE and APP_ROT_LINKER_CODE
+     * don't have to be aligned and memory space can be saved.
+     * This region has the lowest RNR so the next regions can overwrite these
+     * attributes if it's needed.
+     */
+    base = SRAM_BASE;
+    limit = SRAM_BASE + SRAM_SIZE;
+
+    ret = configure_mpu(rnr++, base, limit,
+                            XN_EXEC_OK, AP_RW_PRIV_UNPRIV);
+    if (ret != TFM_HAL_SUCCESS) {
+        return ret;
+    }
 
-    configure_mpu(rnr++, base, limit, XN_EXEC_OK, AP_RO_PRIV_UNPRIV);
 
     /* RW, ZI and stack as one region */
     base = (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base);
     limit = (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base);
 
-    configure_mpu(rnr++, base, limit, XN_EXEC_NOT_OK, AP_RW_PRIV_UNPRIV);
+    /* The section size can be bigger than the alignment size, else the code would
+     * not fit into the memory. Because of this, the sections can use multiple MPU
+     * regions. */
+    do {
+        ret = configure_mpu(rnr++, base, base + TFM_LINKER_APP_ROT_LINKER_DATA_ALIGNMENT,
+                                XN_EXEC_NOT_OK, AP_RW_PRIV_UNPRIV);
+        if (ret != TFM_HAL_SUCCESS) {
+            return ret;
+        }
+        base += TFM_LINKER_APP_ROT_LINKER_DATA_ALIGNMENT;
+    } while (base < limit);
+
 
 #ifdef CONFIG_TFM_PARTITION_META
     /* TFM partition metadata pointer region */
     base = (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
     limit = (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Limit);
 
-    configure_mpu(rnr++, base, limit, XN_EXEC_NOT_OK, AP_RW_PRIV_UNPRIV);
+    do {
+        ret = configure_mpu(rnr++, base, base + TFM_LINKER_SP_META_PTR_ALIGNMENT,
+                                XN_EXEC_NOT_OK, AP_RW_PRIV_UNPRIV);
+        if (ret != TFM_HAL_SUCCESS) {
+            return ret;
+        }
+        base += TFM_LINKER_SP_META_PTR_ALIGNMENT;
+    } while (base < limit);
+
 #endif
 
     arm_mpu_enable();
