1From eb096e4c03b80f9f31e5d15ca06e5a38e4112664 Mon Sep 17 00:00:00 2001
2From: Bence Balogh <bence.balogh@arm.com>
3Date: Tue, 7 Nov 2023 20:25:49 +0100
4Subject: [PATCH 1/2] platform: corstone1000: Update MPU configuration
5
6In Armv6-M the MPU requires the regions to be aligned with
7region sizes.
8The commit aligns the different code/data sections using the
9alignment macros. The code/data sections can be covered by
10multiple MPU regions in order to save memory.
11
12Small adjustments had to be made in the memory layout in order to
13not overflow the flash:
14- Decreased TFM_PARTITION_SIZE
15- Increased S_UNPRIV_DATA_SIZE
16
17Added checks to the MPU configuration function for checking the
18MPU constraints:
19- Base address has to be aligned to the size
20- The minimum MPU region size is 0x100
21- The MPU can have 8 regions at most
22
23Change-Id: I059468e8aba0822bb354fd1cd4987ac2bb1f34d1
24Signed-off-by: Bence Balogh <bence.balogh@arm.com>
25Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/25393]
26
27---
28 .../target/arm/corstone1000/CMakeLists.txt    | 19 +++++
29 .../arm/corstone1000/create-flash-image.sh    |  8 +-
30 .../arm/corstone1000/partition/flash_layout.h |  2 +-
31 .../arm/corstone1000/partition/region_defs.h  |  6 +-
32 .../arm/corstone1000/tfm_hal_isolation.c      | 83 +++++++++++++++----
33 5 files changed, 93 insertions(+), 25 deletions(-)
34
35diff --git a/platform/ext/target/arm/corstone1000/CMakeLists.txt b/platform/ext/target/arm/corstone1000/CMakeLists.txt
36index e6cf15b11..8817f514c 100644
37--- a/platform/ext/target/arm/corstone1000/CMakeLists.txt
38+++ b/platform/ext/target/arm/corstone1000/CMakeLists.txt
39@@ -22,6 +22,25 @@ target_compile_definitions(platform_region_defs
40     INTERFACE
41         $<$<BOOL:${TFM_S_REG_TEST}>:TFM_S_REG_TEST>
42 )
43+
44+# The Armv6-M MPU requires that the MPU regions be aligned to the region sizes.
45+# The minimal region size is 0x100 bytes.
46+#
47+# The alignments have to be a power of two and ideally bigger than the section size (which
48+# can be checked in the map file).
49+# In some cases the alignment value is smaller than the actual section
50+# size to save memory. In that case, multiple MPU region has to be configured to cover it.
51+#
52+# To save memory, the attributes are set to XN_EXEC_OK and AP_RO_PRIV_UNPRIV for
53+# the SRAM so the PSA_ROT_LINKER_CODE, TFM_UNPRIV_CODE and APP_ROT_LINKER_CODE don't have to
54+# be aligned. The higher-priority regions will overwrite these attributes if needed.
55+# The RAM is also located in the SRAM so it has to be configured to overwrite these default
56+# attributes.
57+target_compile_definitions(platform_region_defs
58+    INTERFACE
59+        TFM_LINKER_APP_ROT_LINKER_DATA_ALIGNMENT=0x2000
60+        TFM_LINKER_SP_META_PTR_ALIGNMENT=0x100
61+)
62 #========================= Platform common defs ===============================#
63
64 # Specify the location of platform specific build dependencies.
65diff --git a/platform/ext/target/arm/corstone1000/create-flash-image.sh b/platform/ext/target/arm/corstone1000/create-flash-image.sh
66index 2522d3674..a6be61384 100755
67--- a/platform/ext/target/arm/corstone1000/create-flash-image.sh
68+++ b/platform/ext/target/arm/corstone1000/create-flash-image.sh
69@@ -8,7 +8,7 @@
70
71 ######################################################################
72 # This script is to create a flash gpt image for corstone platform
73-#
74+#
75 #  Flash image layout:
76 #       |------------------------------|
77 #       |        Protective MBR        |
78@@ -82,15 +82,15 @@ sgdisk  --mbrtogpt \
79         --new=4:56:+4K --typecode=4:$PRIVATE_METADATA_TYPE_UUID --partition-guid=4:$(uuidgen) --change-name=4:'private_metadata_replica_1' \
80         --new=5:64:+4k --typecode=5:$PRIVATE_METADATA_TYPE_UUID --partition-guid=5:$(uuidgen) --change-name=5:'private_metadata_replica_2' \
81         --new=6:72:+100k --typecode=6:$SE_BL2_TYPE_UUID --partition-guid=6:$(uuidgen) --change-name=6:'bl2_primary' \
82-        --new=7:272:+376K --typecode=7:$TFM_TYPE_UUID --partition-guid=7:$(uuidgen) --change-name=7:'tfm_primary' \
83+        --new=7:272:+368K --typecode=7:$TFM_TYPE_UUID --partition-guid=7:$(uuidgen) --change-name=7:'tfm_primary' \
84         --new=8:32784:+100k --typecode=8:$SE_BL2_TYPE_UUID --partition-guid=8:$(uuidgen) --change-name=8:'bl2_secondary' \
85-        --new=9:32984:+376K --typecode=9:$TFM_TYPE_UUID --partition-guid=9:$(uuidgen) --change-name=9:'tfm_secondary' \
86+        --new=9:32984:+368K --typecode=9:$TFM_TYPE_UUID --partition-guid=9:$(uuidgen) --change-name=9:'tfm_secondary' \
87         --new=10:65496:65501  --partition-guid=10:$(uuidgen) --change-name=10:'reserved_2' \
88         $IMAGE
89
90 [ $? -ne 0 ] && echo "Error occurs while writing the GPT layout" && exit 1
91
92-# Write partitions
93+# Write partitions
94 # conv=notrunc avoids truncation to keep the geometry of the image.
95 dd if=$BIN_DIR/bl2_signed.bin of=${IMAGE}  seek=72 conv=notrunc
96 dd if=$BIN_DIR/tfm_s_signed.bin of=${IMAGE} seek=272 conv=notrunc
97diff --git a/platform/ext/target/arm/corstone1000/partition/flash_layout.h b/platform/ext/target/arm/corstone1000/partition/flash_layout.h
98index 568c8de28..7fffd94c6 100644
99--- a/platform/ext/target/arm/corstone1000/partition/flash_layout.h
100+++ b/platform/ext/target/arm/corstone1000/partition/flash_layout.h
101@@ -134,7 +134,7 @@
102
103 /* Bank configurations */
104 #define BANK_PARTITION_SIZE             (0xFE0000)   /* 15.875 MB */
105-#define TFM_PARTITION_SIZE              (0x5E000)    /* 376 KB */
106+#define TFM_PARTITION_SIZE              (0x5C000)    /* 368 KB */
107
108 /************************************************************/
109 /* Bank : Images flash offsets are with respect to the bank */
110diff --git a/platform/ext/target/arm/corstone1000/partition/region_defs.h b/platform/ext/target/arm/corstone1000/partition/region_defs.h
111index 99e822f51..64ab786e5 100644
112--- a/platform/ext/target/arm/corstone1000/partition/region_defs.h
113+++ b/platform/ext/target/arm/corstone1000/partition/region_defs.h
114@@ -1,8 +1,10 @@
115 /*
116- * Copyright (c) 2017-2022 Arm Limited. All rights reserved.
117+ * Copyright (c) 2017-2023 Arm Limited. All rights reserved.
118  * Copyright (c) 2021-2023 Cypress Semiconductor Corporation (an Infineon company)
119  * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
120  *
121+ * SPDX-License-Identifier: Apache-2.0
122+ *
123  * Licensed under the Apache License, Version 2.0 (the "License");
124  * you may not use this file except in compliance with the License.
125  * You may obtain a copy of the License at
126@@ -53,7 +55,7 @@
127
128 #define S_DATA_START            (SRAM_BASE + TFM_PARTITION_SIZE)
129 #define S_DATA_SIZE             (SRAM_SIZE - TFM_PARTITION_SIZE)
130-#define S_UNPRIV_DATA_SIZE      (0x2160)
131+#define S_UNPRIV_DATA_SIZE      (0x4000)
132 #define S_DATA_LIMIT            (S_DATA_START + S_DATA_SIZE - 1)
133 #define S_DATA_PRIV_START       (S_DATA_START + S_UNPRIV_DATA_SIZE)
134
135diff --git a/platform/ext/target/arm/corstone1000/tfm_hal_isolation.c b/platform/ext/target/arm/corstone1000/tfm_hal_isolation.c
136index 01f7687bc..98e795dde 100644
137--- a/platform/ext/target/arm/corstone1000/tfm_hal_isolation.c
138+++ b/platform/ext/target/arm/corstone1000/tfm_hal_isolation.c
139@@ -1,5 +1,5 @@
140 /*
141- * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
142+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
143  * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon
144  * company) or an affiliate of Cypress Semiconductor Corporation. All rights
145  * reserved.
146@@ -14,9 +14,11 @@
147 #include "tfm_hal_isolation.h"
148 #include "mpu_config.h"
149 #include "mmio_defs.h"
150+#include "flash_layout.h"
151
152 #define PROT_BOUNDARY_VAL \
153     ((1U << HANDLE_ATTR_PRIV_POS) & HANDLE_ATTR_PRIV_MASK)
154+#define MPU_REGION_MIN_SIZE (0x100)
155
156 #ifdef CONFIG_TFM_ENABLE_MEMORY_PROTECT
157
158@@ -31,20 +33,38 @@ REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
159 REGION_DECLARE(Image$$, TFM_SP_META_PTR, $$ZI$$Limit);
160 #endif /* CONFIG_TFM_PARTITION_META */
161
162-static void configure_mpu(uint32_t rnr, uint32_t base, uint32_t limit,
163-                          uint32_t is_xn_exec, uint32_t ap_permissions)
164+static enum tfm_hal_status_t configure_mpu(uint32_t rnr, uint32_t base,
165+                          uint32_t limit, uint32_t is_xn_exec, uint32_t ap_permissions)
166 {
167-    uint32_t size; /* region size */
168+    uint32_t rbar_size_field; /* region size as it is used in the RBAR */
169     uint32_t rasr; /* region attribute and size register */
170     uint32_t rbar; /* region base address register */
171
172-    size = get_rbar_size_field(limit - base);
173+    rbar_size_field = get_rbar_size_field(limit - base);
174+
175+    /* The MPU region's base address has to be aligned to the region
176+     * size for a valid MPU configuration */
177+    if ((base % (1 << (rbar_size_field + 1))) != 0) {
178+        return TFM_HAL_ERROR_INVALID_INPUT;
179+    }
180+
181+    /* The MPU supports only 8 memory regions */
182+    if (rnr > 7) {
183+        return TFM_HAL_ERROR_INVALID_INPUT;
184+    }
185+
186+    /* The minimum size for a region is 0x100 bytes */
187+    if((limit - base) < MPU_REGION_MIN_SIZE) {
188+        return TFM_HAL_ERROR_INVALID_INPUT;
189+    }
190
191     rasr = ARM_MPU_RASR(is_xn_exec, ap_permissions, TEX, NOT_SHAREABLE,
192-            NOT_CACHEABLE, NOT_BUFFERABLE, SUB_REGION_DISABLE, size);
193+            NOT_CACHEABLE, NOT_BUFFERABLE, SUB_REGION_DISABLE, rbar_size_field);
194     rbar = base & MPU_RBAR_ADDR_Msk;
195
196     ARM_MPU_SetRegionEx(rnr, rbar, rasr);
197+
198+    return TFM_HAL_SUCCESS;
199 }
200
201 #endif /* CONFIG_TFM_ENABLE_MEMORY_PROTECT */
202@@ -56,33 +76,60 @@ enum tfm_hal_status_t tfm_hal_set_up_static_boundaries(
203     uint32_t rnr = TFM_ISOLATION_REGION_START_NUMBER; /* current region number */
204     uint32_t base; /* start address */
205     uint32_t limit; /* end address */
206+    enum tfm_hal_status_t ret;
207
208     ARM_MPU_Disable();
209
210-    /* TFM Core unprivileged code region */
211-    base = (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_START, $$RO$$Base);
212-    limit = (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_CODE_END, $$RO$$Limit);
213-
214-    configure_mpu(rnr++, base, limit, XN_EXEC_OK, AP_RO_PRIV_UNPRIV);
215-
216-    /* RO region */
217-    base = (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_START, $$Base);
218-    limit = (uint32_t)&REGION_NAME(Image$$, TFM_APP_CODE_END, $$Base);
219+    /* Armv6-M MPU allows region overlapping. The region with the higher RNR
220+     * will decide the attributes.
221+     *
222+     * The default attributes are set to XN_EXEC_OK and AP_RO_PRIV_UNPRIV for the
223+     * whole SRAM so the PSA_ROT_LINKER_CODE, TFM_UNPRIV_CODE and APP_ROT_LINKER_CODE
224+     * don't have to be aligned and memory space can be saved.
225+     * This region has the lowest RNR so the next regions can overwrite these
226+     * attributes if it's needed.
227+     */
228+    base = SRAM_BASE;
229+    limit = SRAM_BASE + SRAM_SIZE;
230+
231+    ret = configure_mpu(rnr++, base, limit,
232+                            XN_EXEC_OK, AP_RW_PRIV_UNPRIV);
233+    if (ret != TFM_HAL_SUCCESS) {
234+        return ret;
235+    }
236
237-    configure_mpu(rnr++, base, limit, XN_EXEC_OK, AP_RO_PRIV_UNPRIV);
238
239     /* RW, ZI and stack as one region */
240     base = (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_START, $$Base);
241     limit = (uint32_t)&REGION_NAME(Image$$, TFM_APP_RW_STACK_END, $$Base);
242
243-    configure_mpu(rnr++, base, limit, XN_EXEC_NOT_OK, AP_RW_PRIV_UNPRIV);
244+    /* The section size can be bigger than the alignment size, else the code would
245+     * not fit into the memory. Because of this, the sections can use multiple MPU
246+     * regions. */
247+    do {
248+        ret = configure_mpu(rnr++, base, base + TFM_LINKER_APP_ROT_LINKER_DATA_ALIGNMENT,
249+                                XN_EXEC_NOT_OK, AP_RW_PRIV_UNPRIV);
250+        if (ret != TFM_HAL_SUCCESS) {
251+            return ret;
252+        }
253+        base += TFM_LINKER_APP_ROT_LINKER_DATA_ALIGNMENT;
254+    } while (base < limit);
255+
256
257 #ifdef CONFIG_TFM_PARTITION_META
258     /* TFM partition metadata pointer region */
259     base = (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Base);
260     limit = (uint32_t)&REGION_NAME(Image$$, TFM_SP_META_PTR, $$ZI$$Limit);
261
262-    configure_mpu(rnr++, base, limit, XN_EXEC_NOT_OK, AP_RW_PRIV_UNPRIV);
263+    do {
264+        ret = configure_mpu(rnr++, base, base + TFM_LINKER_SP_META_PTR_ALIGNMENT,
265+                                XN_EXEC_NOT_OK, AP_RW_PRIV_UNPRIV);
266+        if (ret != TFM_HAL_SUCCESS) {
267+            return ret;
268+        }
269+        base += TFM_LINKER_SP_META_PTR_ALIGNMENT;
270+    } while (base < limit);
271+
272 #endif
273
274     arm_mpu_enable();
275