All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode
@ 2021-02-04 19:55 Alexandru Gagniuc
  2021-02-04 19:55 ` [PATCH 2/5] spl: Introduce spl_board_prepare_for_optee() hook Alexandru Gagniuc
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Alexandru Gagniuc @ 2021-02-04 19:55 UTC (permalink / raw)
  To: u-boot

In general, Falcon mode means we're booting a linux kernel directly.
With FIT images, however, an OP-TEE secure kernel can be booted before
linux. Thus, if the next stage is an IH_OS_TEE, this isn't necessarily
a problem.

Of course, a general solution would involve mmc_load_image_raw_os()
only loading the binary, and leaving the decision of suitability to
someone else. However, a rework of the boot flow is beyond the scope
of this patch. Accept IH_OS_TEE as a valid OS value.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
---
 common/spl/spl_mmc.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index add2785b4e..bab558d055 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -230,8 +230,10 @@ static int mmc_load_image_raw_os(struct spl_image_info *spl_image,
 	if (ret)
 		return ret;
 
-	if (spl_image->os != IH_OS_LINUX) {
-		puts("Expected Linux image is not found. Trying to start U-boot\n");
+	if (spl_image->os != IH_OS_LINUX && spl_image->os != IH_OS_TEE) {
+		puts("Expected OS image is not found. Instead found ");
+		puts(genimg_get_os_name(spl_image->os));
+		puts(". Trying to start U-boot\n");
 		return -ENOENT;
 	}
 
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/5] spl: Introduce spl_board_prepare_for_optee() hook
  2021-02-04 19:55 [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alexandru Gagniuc
@ 2021-02-04 19:55 ` Alexandru Gagniuc
  2021-02-07 14:37   ` Simon Glass
  2021-02-04 19:55 ` [PATCH 3/5] arm: stm32mp: Implement support for TZC 400 controller Alexandru Gagniuc
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Alexandru Gagniuc @ 2021-02-04 19:55 UTC (permalink / raw)
  To: u-boot

OP-TEE requires some particular setup, which is not needed for linux
or other payloads. Add a hook for platform-specific code to perform
any OP-TEE related configuration and initialization.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
---
 common/spl/spl.c |  6 ++++++
 include/spl.h    | 14 ++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/common/spl/spl.c b/common/spl/spl.c
index cdd7b05f27..f3aaa67572 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -160,6 +160,11 @@ __weak void spl_board_prepare_for_linux(void)
 	/* Nothing to do! */
 }
 
+__weak void spl_board_prepare_for_optee(void *fdt)
+{
+	/* Weak functions are stupid. Get rid of them! */
+}
+
 __weak void spl_board_prepare_for_boot(void)
 {
 	/* Nothing to do! */
@@ -705,6 +710,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
 #if CONFIG_IS_ENABLED(OPTEE)
 	case IH_OS_TEE:
 		debug("Jumping to U-Boot via OP-TEE\n");
+		spl_board_prepare_for_optee(spl_image.fdt_addr);
 		spl_optee_entry(NULL, NULL, spl_image.fdt_addr,
 				(void *)spl_image.entry_point);
 		break;
diff --git a/include/spl.h b/include/spl.h
index e172500b5f..f94e74e217 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -387,6 +387,20 @@ int spl_parse_image_header(struct spl_image_info *spl_image,
 			   const struct image_header *header);
 
 void spl_board_prepare_for_linux(void);
+
+/**
+ * spl_board_prepare_for_optee() - Prepare board for an OPTEE payload
+ *
+ * Prepares the board for booting an OP-TEE payload. Initialization is platform
+ * specific, and may include configuring the TrustZone memory, and other
+ * initialization steps required by OP-TEE.
+ * Note that @fdt is not used directly by OP-TEE. OP-TEE passes this @fdt to
+ * its normal world target. This target is not guaranteed to be u-boot, so @fdt
+ * changes that would normally be done by u-boot should be done in this step.
+ *
+ * @fdt: Devicetree that will be passed on, or NULL
+ */
+void spl_board_prepare_for_optee(void *fdt);
 void spl_board_prepare_for_boot(void);
 int spl_board_ubi_load_image(u32 boot_device);
 int spl_board_boot_device(u32 boot_device);
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/5] arm: stm32mp: Implement support for TZC 400 controller
  2021-02-04 19:55 [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alexandru Gagniuc
  2021-02-04 19:55 ` [PATCH 2/5] spl: Introduce spl_board_prepare_for_optee() hook Alexandru Gagniuc
@ 2021-02-04 19:55 ` Alexandru Gagniuc
  2021-02-07 14:37   ` Simon Glass
  2021-02-04 19:55 ` [PATCH 4/5] stm32mp1: spl: Configure TrustZone controller for OP-TEE Alexandru Gagniuc
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Alexandru Gagniuc @ 2021-02-04 19:55 UTC (permalink / raw)
  To: u-boot

The purpose of this change is to allow configuring TrustZone (TZC)
memory permissions. For example, OP-TEE expects TZC regions to be
configured in a very particular way. The API presented here is
intended to allow exactly that.

UCLASS support is not implemented, because it would not be too useful.
Changing TZC permissions needs to be done with care, so as not to cut
off access to memory we are currently using. One place where we can
use this is at the end of SPL, right before jumping to OP-TEE.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
---
 arch/arm/mach-stm32mp/Makefile           |   1 +
 arch/arm/mach-stm32mp/include/mach/tzc.h |  33 ++++++
 arch/arm/mach-stm32mp/tzc400.c           | 135 +++++++++++++++++++++++
 3 files changed, 169 insertions(+)
 create mode 100644 arch/arm/mach-stm32mp/include/mach/tzc.h
 create mode 100644 arch/arm/mach-stm32mp/tzc400.c

diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile
index c8aa24d489..1b878c5a85 100644
--- a/arch/arm/mach-stm32mp/Makefile
+++ b/arch/arm/mach-stm32mp/Makefile
@@ -10,6 +10,7 @@ obj-y += bsec.o
 
 ifdef CONFIG_SPL_BUILD
 obj-y += spl.o
+obj-y += tzc400.o
 else
 obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/
 obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o
diff --git a/arch/arm/mach-stm32mp/include/mach/tzc.h b/arch/arm/mach-stm32mp/include/mach/tzc.h
new file mode 100644
index 0000000000..16db55c464
--- /dev/null
+++ b/arch/arm/mach-stm32mp/include/mach/tzc.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Simple API for configuring TrustZone memory regions
+ *
+ * The premise is that the desired TZC layout is known beforehand, and it can
+ * be configured in one step. tzc_configure() provides this functionality.
+ */
+#ifndef MACH_TZC_H
+#define MACH_TZC_H
+
+#include <linux/types.h>
+
+enum tzc_sec_mode {
+	TZC_ATTR_SEC_NONE = 0,
+	TZC_ATTR_SEC_R = 1,
+	TZC_ATTR_SEC_W = 2,
+	TZC_ATTR_SEC_RW	 = 3
+};
+
+struct tzc_region {
+	uintptr_t base;
+	uintptr_t top;
+	enum tzc_sec_mode sec_mode;
+	uint16_t nsec_id;
+	uint16_t filters_mask;
+};
+
+int tzc_configure(uintptr_t tzc, const struct tzc_region *cfg);
+int tzc_disable_filters(uintptr_t tzc, uint16_t filters_mask);
+int tzc_enable_filters(uintptr_t tzc, uint16_t filters_mask);
+void tzc_dump_config(uintptr_t tzc);
+
+#endif /* MACH_TZC_H */
diff --git a/arch/arm/mach-stm32mp/tzc400.c b/arch/arm/mach-stm32mp/tzc400.c
new file mode 100644
index 0000000000..8d20b4382d
--- /dev/null
+++ b/arch/arm/mach-stm32mp/tzc400.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Simple API for configuring TrustZone memory restrictions for TZC400
+ */
+#include <linux/iopoll.h>
+#include <mach/tzc.h>
+
+#define TZC_TIMEOUT_US		100
+
+#define TZC_BUILD_CONFIG	0x00
+#define TZC_ACTION		0x04
+#define TZC_ACTION_NONE		0
+#define TZC_ACTION_ERR		1
+#define TZC_ACTION_INT		2
+#define TZC_ACTION_INT_ERR	3
+#define TZC_GATE_KEEPER		0x08
+
+#define TZC_REGION0_OFFSET	0x100
+#define TZC_REGION_CFG_SIZE	0x20
+#define TZC_REGION1_OFFSET	0x120
+#define TZC_REGION_BASE		0x00
+#define TZC_REGION_TOP		0x08
+#define TZC_REGION_ATTRIBUTE	0x10
+#define TZC_REGION_ACCESS	0x14
+
+static uint32_t tzc_read(uintptr_t tzc, size_t reg)
+{
+	return readl(tzc + reg);
+}
+
+static void tzc_write(uintptr_t tzc, size_t reg, uint32_t val)
+{
+	writel(val, tzc + reg);
+}
+
+static uint16_t tzc_config_get_active_filters(const struct tzc_region *cfg)
+{
+	uint16_t active_filters = 0;
+
+	for ( ; cfg->top != 0; cfg++)
+		active_filters |= cfg->filters_mask;
+
+	return active_filters;
+}
+
+int tzc_configure(uintptr_t tzc, const struct tzc_region *cfg)
+{
+	uintptr_t region = tzc + TZC_REGION1_OFFSET;
+	uint32_t nsid, attr_reg, active_filters;
+	int ret;
+
+	active_filters = tzc_config_get_active_filters(cfg);
+	if (active_filters == 0)
+		return -EINVAL;
+
+	ret = tzc_disable_filters(tzc, active_filters);
+	if (ret < 0)
+		return ret;
+
+	for ( ; cfg->top != 0; cfg++, region += TZC_REGION_CFG_SIZE) {
+
+		attr_reg = (cfg->sec_mode & 0x03) << 30;
+		attr_reg |= (cfg->filters_mask & 0x03) << 0;
+		nsid = cfg->nsec_id & 0xffff;
+		nsid |= nsid << 16;
+
+		tzc_write(region, TZC_REGION_BASE, cfg->base);
+		tzc_write(region, TZC_REGION_TOP, cfg->top);
+		tzc_write(region, TZC_REGION_ACCESS, nsid);
+		tzc_write(region, TZC_REGION_ATTRIBUTE, attr_reg);
+	}
+
+	tzc_write(tzc, TZC_ACTION, TZC_ACTION_ERR);
+	return tzc_enable_filters(tzc, active_filters);
+}
+
+int tzc_disable_filters(uintptr_t tzc, uint16_t filters_mask)
+{
+	uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
+	uint32_t filter_status = filters_mask << 16;
+
+	gate &= ~filters_mask;
+	tzc_write(tzc, TZC_GATE_KEEPER, gate);
+
+	return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
+				 (gate & filter_status) == 0, TZC_TIMEOUT_US);
+}
+
+int tzc_enable_filters(uintptr_t tzc, uint16_t filters_mask)
+{
+	uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
+	uint32_t filter_status = filters_mask << 16;
+
+	gate |= filters_mask;
+	tzc_write(tzc, TZC_GATE_KEEPER, gate);
+
+
+	return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
+				 (gate & filter_status) == filter_status,
+				 TZC_TIMEOUT_US);
+}
+
+static const char *sec_access_str_from_attr(uint32_t attr)
+{
+	const char *const sec_mode[] = { "none", "RO  ", "WO  ", "RW  " };
+
+	return sec_mode[(attr >> 30) & 0x03];
+}
+
+void tzc_dump_config(uintptr_t tzc)
+{
+	uint32_t build_config, base, top, attr, nsaid;
+	int num_regions, i;
+	uintptr_t region;
+
+	build_config = tzc_read(tzc, TZC_BUILD_CONFIG);
+	num_regions = ((build_config >> 0) & 0x1f) + 1;
+
+	for (i = 0; i < num_regions; i++) {
+		region = tzc + TZC_REGION0_OFFSET + i * TZC_REGION_CFG_SIZE;
+
+		base = tzc_read(region, TZC_REGION_BASE);
+		top = tzc_read(region, TZC_REGION_TOP);
+		attr = tzc_read(region, TZC_REGION_ATTRIBUTE);
+		nsaid = tzc_read(region, TZC_REGION_ACCESS);
+
+		if (attr == 0 && nsaid == 0)
+			continue;
+
+		pr_info("TZC region %u: %08x->%08x - filters 0x%x\n",
+		       i, base, top, (attr >> 0) & 0xf);
+		pr_info("\t Secure access %s NSAID %08x\n",
+		       sec_access_str_from_attr(attr), nsaid);
+	}
+}
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/5] stm32mp1: spl: Configure TrustZone controller for OP-TEE
  2021-02-04 19:55 [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alexandru Gagniuc
  2021-02-04 19:55 ` [PATCH 2/5] spl: Introduce spl_board_prepare_for_optee() hook Alexandru Gagniuc
  2021-02-04 19:55 ` [PATCH 3/5] arm: stm32mp: Implement support for TZC 400 controller Alexandru Gagniuc
@ 2021-02-04 19:55 ` Alexandru Gagniuc
  2021-02-04 19:55 ` [PATCH 5/5] ARM: dts: stm32mp: Add OP-TEE reserved memory to SPL dtb Alexandru Gagniuc
  2021-02-04 19:56 ` [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alex G.
  4 siblings, 0 replies; 11+ messages in thread
From: Alexandru Gagniuc @ 2021-02-04 19:55 UTC (permalink / raw)
  To: u-boot

OP-TEE is very particular about how the TZC should be configured.
When booting an OP-TEE payload, an incorrect TZC configuration will
result in a panic.

Most information can be derived from the SPL devicetree. The only
information we don't have is the split between TZDRAM and shared
memory. This has to be hardcoded. The rest of the configuration is
fairly easy, and only requires 3 TZC regions. Configure them.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
---
 arch/arm/mach-stm32mp/spl.c | 84 +++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/arch/arm/mach-stm32mp/spl.c b/arch/arm/mach-stm32mp/spl.c
index 0c50ad54df..bdef7edcb9 100644
--- a/arch/arm/mach-stm32mp/spl.c
+++ b/arch/arm/mach-stm32mp/spl.c
@@ -15,6 +15,7 @@
 #include <asm/cache.h>
 #include <asm/io.h>
 #include <asm/arch/sys_proto.h>
+#include <mach/tzc.h>
 #include <linux/libfdt.h>
 
 u32 spl_boot_device(void)
@@ -91,6 +92,89 @@ __weak int board_early_init_f(void)
 	return 0;
 }
 
+uint32_t stm32mp_get_dram_size(void)
+{
+	uint32_t ram_size = 0;
+	struct udevice *dev;
+	ofnode node;
+
+	if (uclass_get_device(UCLASS_RAM, 0, &dev))
+		return 0;
+
+	dev_for_each_subnode(node, dev) {
+		ram_size = ofnode_read_u32_default(node, "st,mem-size", 0);
+		if (ram_size)
+			break;
+	}
+
+	return ram_size;
+}
+
+uint32_t optee_get_reserved_memory_base(void)
+{
+	ofnode node;
+	fdt_addr_t start;
+
+	node = ofnode_path("/reserved-memory/optee");
+	if (!ofnode_valid(node))
+		return 0;
+
+	start = ofnode_get_addr(node);
+	return (start < 0) ? 0 : (uintptr_t)start;
+}
+
+#define CFG_TZDRAM_SIZE		0x01e00000
+#define STM32_TZC_NSID_ALL		0xffff
+#define STM32_TZC_FILTER_ALL		3
+
+void stm32_init_tzc_for_optee(void)
+{
+	const uint32_t dram_size = stm32mp_get_dram_size();
+	const uintptr_t dram_top = STM32_DDR_BASE + (dram_size - 1);
+	uint32_t optee_base = optee_get_reserved_memory_base();
+	uint32_t tee_shmem_base = optee_base + CFG_TZDRAM_SIZE;
+	const uintptr_t tzc = STM32_TZC_BASE;
+
+	if (dram_size == 0)
+		panic("Cannot determine DRAM size from devicetree\n");
+
+	const struct tzc_region optee_config[] = {
+		{
+			.base = STM32_DDR_BASE,
+			.top = optee_base - 1,
+			.sec_mode = TZC_ATTR_SEC_NONE,
+			.nsec_id = STM32_TZC_NSID_ALL,
+			.filters_mask = STM32_TZC_FILTER_ALL,
+		}, {
+			.base = optee_base,
+			.top = tee_shmem_base - 1,
+			.sec_mode = TZC_ATTR_SEC_RW,
+			.nsec_id = 0,
+			.filters_mask = STM32_TZC_FILTER_ALL,
+		}, {
+			.base = tee_shmem_base,
+			.top = dram_top,
+			.sec_mode = TZC_ATTR_SEC_NONE,
+			.nsec_id = STM32_TZC_NSID_ALL,
+			.filters_mask = STM32_TZC_FILTER_ALL,
+		}, {
+			.top = 0,
+		}
+	};
+
+	flush_dcache_all();
+
+	tzc_configure(tzc, optee_config);
+	tzc_dump_config(tzc);
+
+	dcache_disable();
+}
+
+void spl_board_prepare_for_optee(void *fdt)
+{
+	stm32_init_tzc_for_optee();
+}
+
 void board_init_f(ulong dummy)
 {
 	struct udevice *dev;
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/5] ARM: dts: stm32mp: Add OP-TEE reserved memory to SPL dtb
  2021-02-04 19:55 [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alexandru Gagniuc
                   ` (2 preceding siblings ...)
  2021-02-04 19:55 ` [PATCH 4/5] stm32mp1: spl: Configure TrustZone controller for OP-TEE Alexandru Gagniuc
@ 2021-02-04 19:55 ` Alexandru Gagniuc
  2021-02-04 19:56 ` [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alex G.
  4 siblings, 0 replies; 11+ messages in thread
From: Alexandru Gagniuc @ 2021-02-04 19:55 UTC (permalink / raw)
  To: u-boot

Add the "/reserved-memory/optee" node to the SPL devicetree. The
purpose is to allow configuring TZC regions when booting OP-TEE.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
---
 arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi
index 6787619290..9c4100c39c 100644
--- a/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi
+++ b/arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi
@@ -30,9 +30,12 @@
 	};
 
 	reserved-memory {
+		u-boot,dm-pre-reloc;
+
 		optee at de000000 {
 			reg = <0xde000000 0x02000000>;
 			no-map;
+			u-boot,dm-pre-reloc;
 		};
 	};
 
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode
  2021-02-04 19:55 [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alexandru Gagniuc
                   ` (3 preceding siblings ...)
  2021-02-04 19:55 ` [PATCH 5/5] ARM: dts: stm32mp: Add OP-TEE reserved memory to SPL dtb Alexandru Gagniuc
@ 2021-02-04 19:56 ` Alex G.
  2021-02-07 14:37   ` Simon Glass
  4 siblings, 1 reply; 11+ messages in thread
From: Alex G. @ 2021-02-04 19:56 UTC (permalink / raw)
  To: u-boot

This series was re-sent in error. Please ignore.

On 2/4/21 1:55 PM, Alexandru Gagniuc wrote:
> In general, Falcon mode means we're booting a linux kernel directly.
> With FIT images, however, an OP-TEE secure kernel can be booted before
> linux. Thus, if the next stage is an IH_OS_TEE, this isn't necessarily
> a problem.
> 
> Of course, a general solution would involve mmc_load_image_raw_os()
> only loading the binary, and leaving the decision of suitability to
> someone else. However, a rework of the boot flow is beyond the scope
> of this patch. Accept IH_OS_TEE as a valid OS value.
> 
> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
> ---
>   common/spl/spl_mmc.c | 6 ++++--
>   1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
> index add2785b4e..bab558d055 100644
> --- a/common/spl/spl_mmc.c
> +++ b/common/spl/spl_mmc.c
> @@ -230,8 +230,10 @@ static int mmc_load_image_raw_os(struct spl_image_info *spl_image,
>   	if (ret)
>   		return ret;
>   
> -	if (spl_image->os != IH_OS_LINUX) {
> -		puts("Expected Linux image is not found. Trying to start U-boot\n");
> +	if (spl_image->os != IH_OS_LINUX && spl_image->os != IH_OS_TEE) {
> +		puts("Expected OS image is not found. Instead found ");
> +		puts(genimg_get_os_name(spl_image->os));
> +		puts(". Trying to start U-boot\n");
>   		return -ENOENT;
>   	}
>   
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/5] arm: stm32mp: Implement support for TZC 400 controller
  2021-02-04 19:55 ` [PATCH 3/5] arm: stm32mp: Implement support for TZC 400 controller Alexandru Gagniuc
@ 2021-02-07 14:37   ` Simon Glass
  2021-02-08 21:23     ` Alex G.
  0 siblings, 1 reply; 11+ messages in thread
From: Simon Glass @ 2021-02-07 14:37 UTC (permalink / raw)
  To: u-boot

Hi Alexandru,

On Thu, 4 Feb 2021 at 12:56, Alexandru Gagniuc <mr.nuke.me@gmail.com> wrote:
>
> The purpose of this change is to allow configuring TrustZone (TZC)
> memory permissions. For example, OP-TEE expects TZC regions to be
> configured in a very particular way. The API presented here is
> intended to allow exactly that.
>
> UCLASS support is not implemented, because it would not be too useful.
> Changing TZC permissions needs to be done with care, so as not to cut
> off access to memory we are currently using. One place where we can
> use this is at the end of SPL, right before jumping to OP-TEE.
>
> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
> ---
>  arch/arm/mach-stm32mp/Makefile           |   1 +
>  arch/arm/mach-stm32mp/include/mach/tzc.h |  33 ++++++
>  arch/arm/mach-stm32mp/tzc400.c           | 135 +++++++++++++++++++++++
>  3 files changed, 169 insertions(+)
>  create mode 100644 arch/arm/mach-stm32mp/include/mach/tzc.h
>  create mode 100644 arch/arm/mach-stm32mp/tzc400.c

If this is an API you should add comments to the header file structs
and functions.

Is this API specific to just this chip?

Regards,
Simon

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/5] spl: Introduce spl_board_prepare_for_optee() hook
  2021-02-04 19:55 ` [PATCH 2/5] spl: Introduce spl_board_prepare_for_optee() hook Alexandru Gagniuc
@ 2021-02-07 14:37   ` Simon Glass
  0 siblings, 0 replies; 11+ messages in thread
From: Simon Glass @ 2021-02-07 14:37 UTC (permalink / raw)
  To: u-boot

Hi Alexandru,

On Thu, 4 Feb 2021 at 12:56, Alexandru Gagniuc <mr.nuke.me@gmail.com> wrote:
>
> OP-TEE requires some particular setup, which is not needed for linux
> or other payloads. Add a hook for platform-specific code to perform
> any OP-TEE related configuration and initialization.
>
> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
> ---
>  common/spl/spl.c |  6 ++++++
>  include/spl.h    | 14 ++++++++++++++
>  2 files changed, 20 insertions(+)
>
> diff --git a/common/spl/spl.c b/common/spl/spl.c
> index cdd7b05f27..f3aaa67572 100644
> --- a/common/spl/spl.c
> +++ b/common/spl/spl.c
> @@ -160,6 +160,11 @@ __weak void spl_board_prepare_for_linux(void)
>         /* Nothing to do! */
>  }
>
> +__weak void spl_board_prepare_for_optee(void *fdt)
> +{
> +       /* Weak functions are stupid. Get rid of them! */
> +}
> +
>  __weak void spl_board_prepare_for_boot(void)
>  {
>         /* Nothing to do! */
> @@ -705,6 +710,7 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
>  #if CONFIG_IS_ENABLED(OPTEE)
>         case IH_OS_TEE:
>                 debug("Jumping to U-Boot via OP-TEE\n");
> +               spl_board_prepare_for_optee(spl_image.fdt_addr);
>                 spl_optee_entry(NULL, NULL, spl_image.fdt_addr,
>                                 (void *)spl_image.entry_point);
>                 break;
> diff --git a/include/spl.h b/include/spl.h
> index e172500b5f..f94e74e217 100644
> --- a/include/spl.h
> +++ b/include/spl.h
> @@ -387,6 +387,20 @@ int spl_parse_image_header(struct spl_image_info *spl_image,
>                            const struct image_header *header);
>
>  void spl_board_prepare_for_linux(void);
> +
> +/**
> + * spl_board_prepare_for_optee() - Prepare board for an OPTEE payload
> + *
> + * Prepares the board for booting an OP-TEE payload. Initialization is platform
> + * specific, and may include configuring the TrustZone memory, and other
> + * initialization steps required by OP-TEE.
> + * Note that @fdt is not used directly by OP-TEE. OP-TEE passes this @fdt to
> + * its normal world target. This target is not guaranteed to be u-boot, so @fdt
> + * changes that would normally be done by u-boot should be done in this step.
> + *
> + * @fdt: Devicetree that will be passed on, or NULL
> + */
> +void spl_board_prepare_for_optee(void *fdt);
>  void spl_board_prepare_for_boot(void);
>  int spl_board_ubi_load_image(u32 boot_device);
>  int spl_board_boot_device(u32 boot_device);
> --
> 2.26.2
>

Reviewed-by: Simon Glass <sjg@chromium.org>

One way to get rid of the weak function would be to introduce some
sort of event handler / runner or hook system. We could have an enum
of available events and allow handlers to register themselves. Then we
could do something like:

struct event ev;

ev.type = EVT_SPL_OS_PREPARE;
ev.data.spl_os_prepare = IG_OS_TEE;
ret = event_post(&ev);
(return code -ENOSYS if nothing handled the event)

Could use a ilnker_list to set up the handlers at build time. Perhaps
could allow runtime registration if useful.

Regards,
Simon

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode
  2021-02-04 19:56 ` [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alex G.
@ 2021-02-07 14:37   ` Simon Glass
  0 siblings, 0 replies; 11+ messages in thread
From: Simon Glass @ 2021-02-07 14:37 UTC (permalink / raw)
  To: u-boot

On Thu, 4 Feb 2021 at 12:56, Alex G. <mr.nuke.me@gmail.com> wrote:
>
> This series was re-sent in error. Please ignore.
>
> On 2/4/21 1:55 PM, Alexandru Gagniuc wrote:
> > In general, Falcon mode means we're booting a linux kernel directly.
> > With FIT images, however, an OP-TEE secure kernel can be booted before
> > linux. Thus, if the next stage is an IH_OS_TEE, this isn't necessarily
> > a problem.
> >
> > Of course, a general solution would involve mmc_load_image_raw_os()
> > only loading the binary, and leaving the decision of suitability to
> > someone else. However, a rework of the boot flow is beyond the scope
> > of this patch. Accept IH_OS_TEE as a valid OS value.
> >
> > Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
> > ---
> >   common/spl/spl_mmc.c | 6 ++++--
> >   1 file changed, 4 insertions(+), 2 deletions(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/5] arm: stm32mp: Implement support for TZC 400 controller
  2021-02-07 14:37   ` Simon Glass
@ 2021-02-08 21:23     ` Alex G.
  0 siblings, 0 replies; 11+ messages in thread
From: Alex G. @ 2021-02-08 21:23 UTC (permalink / raw)
  To: u-boot

On 2/7/21 8:37 AM, Simon Glass wrote:
> Hi Alexandru,
> 
> On Thu, 4 Feb 2021 at 12:56, Alexandru Gagniuc <mr.nuke.me@gmail.com> wrote:
>>
>> The purpose of this change is to allow configuring TrustZone (TZC)
>> memory permissions. For example, OP-TEE expects TZC regions to be
>> configured in a very particular way. The API presented here is
>> intended to allow exactly that.
>>
>> UCLASS support is not implemented, because it would not be too useful.
>> Changing TZC permissions needs to be done with care, so as not to cut
>> off access to memory we are currently using. One place where we can
>> use this is at the end of SPL, right before jumping to OP-TEE.
>>
>> Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
>> ---
>>   arch/arm/mach-stm32mp/Makefile           |   1 +
>>   arch/arm/mach-stm32mp/include/mach/tzc.h |  33 ++++++
>>   arch/arm/mach-stm32mp/tzc400.c           | 135 +++++++++++++++++++++++
>>   3 files changed, 169 insertions(+)
>>   create mode 100644 arch/arm/mach-stm32mp/include/mach/tzc.h
>>   create mode 100644 arch/arm/mach-stm32mp/tzc400.c
> 
> If this is an API you should add comments to the header file structs
> and functions.
> 
> Is this API specific to just this chip?

I've designed and validated this to set up stm32mp for starting up 
OP-TEE. It's a narrow use case. I can't speak for other chips.

Alex

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/5] arm: stm32mp: Implement support for TZC 400 controller
  2021-02-03 15:21 Alexandru Gagniuc
@ 2021-02-03 15:21 ` Alexandru Gagniuc
  0 siblings, 0 replies; 11+ messages in thread
From: Alexandru Gagniuc @ 2021-02-03 15:21 UTC (permalink / raw)
  To: u-boot

The purpose of this change is to allow configuring TrustZone (TZC)
memory permissions. For example, OP-TEE expects TZC regions to be
configured in a very particular way. The API presented here is
intended to allow exactly that.

UCLASS support is not implemented, because it would not be too useful.
Changing TZC permissions needs to be done with care, so as not to cut
off access to memory we are currently using. One place where we can
use this is at the end of SPL, right before jumping to OP-TEE.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
---
 arch/arm/mach-stm32mp/Makefile           |   1 +
 arch/arm/mach-stm32mp/include/mach/tzc.h |  33 ++++++
 arch/arm/mach-stm32mp/tzc400.c           | 135 +++++++++++++++++++++++
 3 files changed, 169 insertions(+)
 create mode 100644 arch/arm/mach-stm32mp/include/mach/tzc.h
 create mode 100644 arch/arm/mach-stm32mp/tzc400.c

diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile
index c8aa24d489..1b878c5a85 100644
--- a/arch/arm/mach-stm32mp/Makefile
+++ b/arch/arm/mach-stm32mp/Makefile
@@ -10,6 +10,7 @@ obj-y += bsec.o
 
 ifdef CONFIG_SPL_BUILD
 obj-y += spl.o
+obj-y += tzc400.o
 else
 obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/
 obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o
diff --git a/arch/arm/mach-stm32mp/include/mach/tzc.h b/arch/arm/mach-stm32mp/include/mach/tzc.h
new file mode 100644
index 0000000000..16db55c464
--- /dev/null
+++ b/arch/arm/mach-stm32mp/include/mach/tzc.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Simple API for configuring TrustZone memory regions
+ *
+ * The premise is that the desired TZC layout is known beforehand, and it can
+ * be configured in one step. tzc_configure() provides this functionality.
+ */
+#ifndef MACH_TZC_H
+#define MACH_TZC_H
+
+#include <linux/types.h>
+
+enum tzc_sec_mode {
+	TZC_ATTR_SEC_NONE = 0,
+	TZC_ATTR_SEC_R = 1,
+	TZC_ATTR_SEC_W = 2,
+	TZC_ATTR_SEC_RW	 = 3
+};
+
+struct tzc_region {
+	uintptr_t base;
+	uintptr_t top;
+	enum tzc_sec_mode sec_mode;
+	uint16_t nsec_id;
+	uint16_t filters_mask;
+};
+
+int tzc_configure(uintptr_t tzc, const struct tzc_region *cfg);
+int tzc_disable_filters(uintptr_t tzc, uint16_t filters_mask);
+int tzc_enable_filters(uintptr_t tzc, uint16_t filters_mask);
+void tzc_dump_config(uintptr_t tzc);
+
+#endif /* MACH_TZC_H */
diff --git a/arch/arm/mach-stm32mp/tzc400.c b/arch/arm/mach-stm32mp/tzc400.c
new file mode 100644
index 0000000000..8d20b4382d
--- /dev/null
+++ b/arch/arm/mach-stm32mp/tzc400.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Simple API for configuring TrustZone memory restrictions for TZC400
+ */
+#include <linux/iopoll.h>
+#include <mach/tzc.h>
+
+#define TZC_TIMEOUT_US		100
+
+#define TZC_BUILD_CONFIG	0x00
+#define TZC_ACTION		0x04
+#define TZC_ACTION_NONE		0
+#define TZC_ACTION_ERR		1
+#define TZC_ACTION_INT		2
+#define TZC_ACTION_INT_ERR	3
+#define TZC_GATE_KEEPER		0x08
+
+#define TZC_REGION0_OFFSET	0x100
+#define TZC_REGION_CFG_SIZE	0x20
+#define TZC_REGION1_OFFSET	0x120
+#define TZC_REGION_BASE		0x00
+#define TZC_REGION_TOP		0x08
+#define TZC_REGION_ATTRIBUTE	0x10
+#define TZC_REGION_ACCESS	0x14
+
+static uint32_t tzc_read(uintptr_t tzc, size_t reg)
+{
+	return readl(tzc + reg);
+}
+
+static void tzc_write(uintptr_t tzc, size_t reg, uint32_t val)
+{
+	writel(val, tzc + reg);
+}
+
+static uint16_t tzc_config_get_active_filters(const struct tzc_region *cfg)
+{
+	uint16_t active_filters = 0;
+
+	for ( ; cfg->top != 0; cfg++)
+		active_filters |= cfg->filters_mask;
+
+	return active_filters;
+}
+
+int tzc_configure(uintptr_t tzc, const struct tzc_region *cfg)
+{
+	uintptr_t region = tzc + TZC_REGION1_OFFSET;
+	uint32_t nsid, attr_reg, active_filters;
+	int ret;
+
+	active_filters = tzc_config_get_active_filters(cfg);
+	if (active_filters == 0)
+		return -EINVAL;
+
+	ret = tzc_disable_filters(tzc, active_filters);
+	if (ret < 0)
+		return ret;
+
+	for ( ; cfg->top != 0; cfg++, region += TZC_REGION_CFG_SIZE) {
+
+		attr_reg = (cfg->sec_mode & 0x03) << 30;
+		attr_reg |= (cfg->filters_mask & 0x03) << 0;
+		nsid = cfg->nsec_id & 0xffff;
+		nsid |= nsid << 16;
+
+		tzc_write(region, TZC_REGION_BASE, cfg->base);
+		tzc_write(region, TZC_REGION_TOP, cfg->top);
+		tzc_write(region, TZC_REGION_ACCESS, nsid);
+		tzc_write(region, TZC_REGION_ATTRIBUTE, attr_reg);
+	}
+
+	tzc_write(tzc, TZC_ACTION, TZC_ACTION_ERR);
+	return tzc_enable_filters(tzc, active_filters);
+}
+
+int tzc_disable_filters(uintptr_t tzc, uint16_t filters_mask)
+{
+	uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
+	uint32_t filter_status = filters_mask << 16;
+
+	gate &= ~filters_mask;
+	tzc_write(tzc, TZC_GATE_KEEPER, gate);
+
+	return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
+				 (gate & filter_status) == 0, TZC_TIMEOUT_US);
+}
+
+int tzc_enable_filters(uintptr_t tzc, uint16_t filters_mask)
+{
+	uint32_t gate = tzc_read(tzc, TZC_GATE_KEEPER);
+	uint32_t filter_status = filters_mask << 16;
+
+	gate |= filters_mask;
+	tzc_write(tzc, TZC_GATE_KEEPER, gate);
+
+
+	return readl_poll_timeout(tzc + TZC_GATE_KEEPER, gate,
+				 (gate & filter_status) == filter_status,
+				 TZC_TIMEOUT_US);
+}
+
+static const char *sec_access_str_from_attr(uint32_t attr)
+{
+	const char *const sec_mode[] = { "none", "RO  ", "WO  ", "RW  " };
+
+	return sec_mode[(attr >> 30) & 0x03];
+}
+
+void tzc_dump_config(uintptr_t tzc)
+{
+	uint32_t build_config, base, top, attr, nsaid;
+	int num_regions, i;
+	uintptr_t region;
+
+	build_config = tzc_read(tzc, TZC_BUILD_CONFIG);
+	num_regions = ((build_config >> 0) & 0x1f) + 1;
+
+	for (i = 0; i < num_regions; i++) {
+		region = tzc + TZC_REGION0_OFFSET + i * TZC_REGION_CFG_SIZE;
+
+		base = tzc_read(region, TZC_REGION_BASE);
+		top = tzc_read(region, TZC_REGION_TOP);
+		attr = tzc_read(region, TZC_REGION_ATTRIBUTE);
+		nsaid = tzc_read(region, TZC_REGION_ACCESS);
+
+		if (attr == 0 && nsaid == 0)
+			continue;
+
+		pr_info("TZC region %u: %08x->%08x - filters 0x%x\n",
+		       i, base, top, (attr >> 0) & 0xf);
+		pr_info("\t Secure access %s NSAID %08x\n",
+		       sec_access_str_from_attr(attr), nsaid);
+	}
+}
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2021-02-08 21:23 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-04 19:55 [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alexandru Gagniuc
2021-02-04 19:55 ` [PATCH 2/5] spl: Introduce spl_board_prepare_for_optee() hook Alexandru Gagniuc
2021-02-07 14:37   ` Simon Glass
2021-02-04 19:55 ` [PATCH 3/5] arm: stm32mp: Implement support for TZC 400 controller Alexandru Gagniuc
2021-02-07 14:37   ` Simon Glass
2021-02-08 21:23     ` Alex G.
2021-02-04 19:55 ` [PATCH 4/5] stm32mp1: spl: Configure TrustZone controller for OP-TEE Alexandru Gagniuc
2021-02-04 19:55 ` [PATCH 5/5] ARM: dts: stm32mp: Add OP-TEE reserved memory to SPL dtb Alexandru Gagniuc
2021-02-04 19:56 ` [PATCH 1/5] spl: mmc: Support OP-TEE payloads in Falcon mode Alex G.
2021-02-07 14:37   ` Simon Glass
  -- strict thread matches above, loose matches on Subject: below --
2021-02-03 15:21 Alexandru Gagniuc
2021-02-03 15:21 ` [PATCH 3/5] arm: stm32mp: Implement support for TZC 400 controller Alexandru Gagniuc

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.