summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/user/optee.rst29
-rw-r--r--Documentation/user/user-manual.rst1
-rw-r--r--arch/arm/include/asm/barebox-arm.h2
-rw-r--r--arch/arm/include/asm/setjmp.h29
-rw-r--r--arch/arm/lib32/Makefile4
-rw-r--r--arch/arm/lib32/bootm.c12
-rw-r--r--arch/arm/lib32/optee-early.c38
-rw-r--r--arch/arm/lib32/setjmp.S36
-rw-r--r--arch/arm/lib64/Makefile1
-rw-r--r--arch/arm/lib64/setjmp.S40
-rw-r--r--arch/arm/mach-imx/imx6.c20
-rw-r--r--common/Kconfig54
-rw-r--r--common/Makefile2
-rw-r--r--common/optee.c23
-rw-r--r--include/asm-generic/memory_layout.h4
-rw-r--r--include/tee/optee.h11
16 files changed, 273 insertions, 33 deletions
diff --git a/Documentation/user/optee.rst b/Documentation/user/optee.rst
new file mode 100644
index 0000000000..950917b446
--- /dev/null
+++ b/Documentation/user/optee.rst
@@ -0,0 +1,29 @@
+
+.. _optee:
+
+OP-TEE
+======
+
+Barebox is able to start the Open Portable Trusted Execution Environment
+(OP-TEE) either before starting the linux kernel or during lowlevel board
+initialization in the Pre Bootloader ``PBL``.
+
+Before Linux start
+------------------
+Enable the `CONFIG_BOOTM_OPTEE` configuration variable and configure the
+`CONFIG_OPTEE_SIZE` variable. This will reserve a memory area at the end
+of memory for OP-TEE to run, usually Barebox would relocate itself there. To
+load OP-TEE before the kernel is started, configure the global ``bootm.tee``
+variable to point to a valid OPTEE v1 binary.
+
+During the PBL
+--------------
+To start OP-TEE during the lowlevel initialization of your board in the ``PBL``,
+enable the ``CONFIG_PBL_OPTEE`` configuration variable. your board should then
+call the function ``start_optee_early(void* tee, void* fdt)`` with a valid tee
+and FDT. Ensure that your OP-TEE is compiled with ``CFG_NS_ENTRY_ADDR`` unset,
+otherwise OP-TEE will not correctly return to barebox after startup.
+Since OP-TEE in the default configuration also modifies the device tree, don't
+pass the barebox internal device tree, instead copy it into a different memory
+location and pass it to OP-TEE afterwards.
+The modified device tree can then be passed to the main barebox start function.
diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst
index 41fdb8805c..827683eaa0 100644
--- a/Documentation/user/user-manual.rst
+++ b/Documentation/user/user-manual.rst
@@ -33,6 +33,7 @@ Contents:
system-reset
state
random
+ optee
debugging
watchdog
diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h
index 8b2ecd9ab2..599852d644 100644
--- a/arch/arm/include/asm/barebox-arm.h
+++ b/arch/arm/include/asm/barebox-arm.h
@@ -119,7 +119,7 @@ void *barebox_arm_boot_dtb(void);
static inline unsigned long arm_mem_stack_top(unsigned long membase,
unsigned long endmem)
{
- if (IS_ENABLED(CONFIG_BOOTM_OPTEE))
+ if (IS_ENABLED(CONFIG_BOOTM_OPTEE) || IS_ENABLED(CONFIG_PBL_OPTEE))
endmem -= OPTEE_SIZE;
return endmem - SZ_64K;
diff --git a/arch/arm/include/asm/setjmp.h b/arch/arm/include/asm/setjmp.h
new file mode 100644
index 0000000000..62bac613d6
--- /dev/null
+++ b/arch/arm/include/asm/setjmp.h
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH
+ * (C) Copyright 2016 Alexander Graf <agraf@suse.de>
+ */
+
+#ifndef _SETJMP_H_
+#define _SETJMP_H_ 1
+
+#include <asm/types.h>
+
+/*
+ * This really should be opaque, but the EFI implementation wrongly
+ * assumes that a 'struct jmp_buf_data' is defined.
+ */
+struct jmp_buf_data {
+#if defined(__aarch64__)
+ u64 regs[13];
+#else
+ u32 regs[10]; /* r4-r9, sl, fp, sp, lr */
+#endif
+};
+
+typedef struct jmp_buf_data jmp_buf[1];
+
+int setjmp(jmp_buf jmp);
+void longjmp(jmp_buf jmp, int ret);
+
+#endif /* _SETJMP_H_ */
diff --git a/arch/arm/lib32/Makefile b/arch/arm/lib32/Makefile
index cd43147e66..597bc07905 100644
--- a/arch/arm/lib32/Makefile
+++ b/arch/arm/lib32/Makefile
@@ -28,3 +28,7 @@ extra-y += barebox.lds
pbl-y += lib1funcs.o
pbl-y += ashldi3.o
pbl-y += div0.o
+
+obj-pbl-y += setjmp.o
+
+pbl-$(CONFIG_PBL_OPTEE) += optee-early.o
diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c
index 180624445d..d64e705c40 100644
--- a/arch/arm/lib32/bootm.c
+++ b/arch/arm/lib32/bootm.c
@@ -137,16 +137,10 @@ static int get_kernel_addresses(size_t image_size,
static int optee_verify_header_request_region(struct image_data *data, struct optee_header *hdr)
{
int ret = 0;
- if (hdr->magic != OPTEE_MAGIC) {
- pr_err("Invalid header magic 0x%08x, expected 0x%08x\n",
- hdr->magic, OPTEE_MAGIC);
- return -EINVAL;
- }
- if (hdr->arch != OPTEE_ARCH_ARM32 || hdr->init_load_addr_hi) {
- pr_err("Only 32bit supported\n");
- return -EINVAL;
- }
+ ret = optee_verify_header(hdr);
+ if (ret < 0)
+ return ret;
data->tee_res = request_sdram_region("TEE", hdr->init_load_addr_lo, hdr->init_size);
if (!data->tee_res) {
diff --git a/arch/arm/lib32/optee-early.c b/arch/arm/lib32/optee-early.c
new file mode 100644
index 0000000000..197325b8a0
--- /dev/null
+++ b/arch/arm/lib32/optee-early.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * optee-early.c - start OP-TEE during PBL
+ *
+ * Copyright (c) 2019 Rouven Czerwinski <r.czerwinski@pengutronix.de>, Pengutronix
+ *
+ */
+#include <asm/cache.h>
+#include <asm/setjmp.h>
+#include <tee/optee.h>
+#include <debug_ll.h>
+
+static jmp_buf tee_buf;
+
+int start_optee_early(void *fdt, void *tee)
+{
+ void (*tee_start)(void *r0, void *r1, void *r2);
+ struct optee_header *hdr;
+ int ret;
+
+ hdr = tee;
+ ret = optee_verify_header(hdr);
+ if (ret < 0)
+ return ret;
+
+ memcpy((void *)hdr->init_load_addr_lo, tee + sizeof(*hdr), hdr->init_size);
+ tee_start = (void *) hdr->init_load_addr_lo;
+
+ /* We use setjmp/longjmp here because OP-TEE clobbers most registers */
+ ret = setjmp(tee_buf);
+ if (ret == 0) {
+ sync_caches_for_execution();
+ tee_start(0, 0, fdt);
+ longjmp(tee_buf, 1);
+ }
+
+ return 0;
+}
diff --git a/arch/arm/lib32/setjmp.S b/arch/arm/lib32/setjmp.S
new file mode 100644
index 0000000000..f0606a7f66
--- /dev/null
+++ b/arch/arm/lib32/setjmp.S
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) 2017 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <config.h>
+#include <asm/assembler.h>
+#include <linux/linkage.h>
+
+.pushsection .text.setjmp, "ax"
+ENTRY(setjmp)
+ /*
+ * A subroutine must preserve the contents of the registers
+ * r4-r8, r10, r11 (v1-v5, v7 and v8) and SP (and r9 in PCS
+ * variants that designate r9 as v6).
+ */
+ mov ip, sp
+ stm a1, {v1-v8, ip, lr}
+ mov a1, #0
+ bx lr
+ENDPROC(setjmp)
+.popsection
+
+.pushsection .text.longjmp, "ax"
+ENTRY(longjmp)
+ ldm a1, {v1-v8, ip, lr}
+ mov sp, ip
+ mov a1, a2
+ /* If we were passed a return value of zero, return one instead */
+ cmp a1, #0
+ bne 1f
+ mov a1, #1
+1:
+ bx lr
+ENDPROC(longjmp)
+.popsection
diff --git a/arch/arm/lib64/Makefile b/arch/arm/lib64/Makefile
index 5068431342..69cb3d8ea1 100644
--- a/arch/arm/lib64/Makefile
+++ b/arch/arm/lib64/Makefile
@@ -5,5 +5,6 @@ obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memcpy.o
obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memset.o string.o
extra-y += barebox.lds
obj-pbl-y += runtime-offset.o
+obj-pbl-y += setjmp.o
pbl-y += div0.o pbl.o
diff --git a/arch/arm/lib64/setjmp.S b/arch/arm/lib64/setjmp.S
new file mode 100644
index 0000000000..a7f6d05417
--- /dev/null
+++ b/arch/arm/lib64/setjmp.S
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) 2017 Theobroma Systems Design und Consulting GmbH
+ */
+
+#include <config.h>
+#include <linux/linkage.h>
+
+.pushsection .text.setjmp, "ax"
+ENTRY(setjmp)
+ /* Preserve all callee-saved registers and the SP */
+ stp x19, x20, [x0,#0]
+ stp x21, x22, [x0,#16]
+ stp x23, x24, [x0,#32]
+ stp x25, x26, [x0,#48]
+ stp x27, x28, [x0,#64]
+ stp x29, x30, [x0,#80]
+ mov x2, sp
+ str x2, [x0, #96]
+ mov x0, #0
+ ret
+ENDPROC(setjmp)
+.popsection
+
+.pushsection .text.longjmp, "ax"
+ENTRY(longjmp)
+ ldp x19, x20, [x0,#0]
+ ldp x21, x22, [x0,#16]
+ ldp x23, x24, [x0,#32]
+ ldp x25, x26, [x0,#48]
+ ldp x27, x28, [x0,#64]
+ ldp x29, x30, [x0,#80]
+ ldr x2, [x0,#96]
+ mov sp, x2
+ /* Move the return value in place, but return 1 if passed 0. */
+ adds x0, xzr, x1
+ csinc x0, x0, xzr, ne
+ ret
+ENDPROC(longjmp)
+.popsection
diff --git a/arch/arm/mach-imx/imx6.c b/arch/arm/mach-imx/imx6.c
index 8f949534b8..6a9ea23c71 100644
--- a/arch/arm/mach-imx/imx6.c
+++ b/arch/arm/mach-imx/imx6.c
@@ -11,6 +11,7 @@
*
*/
+#include <abort.h>
#include <init.h>
#include <common.h>
#include <io.h>
@@ -288,6 +289,22 @@ int imx6_devices_init(void)
return 0;
}
+static bool imx6_cannot_write_l2x0(void)
+{
+ void __iomem *l2x0_base = IOMEM(0x00a02000);
+ u32 val;
+ /*
+ * Mask data aborts and try to access the PL210. If OP-TEE is running we
+ * will receive a data-abort and assume barebox is running in the normal
+ * world.
+ */
+ val = readl(l2x0_base + L2X0_PREFETCH_CTRL);
+
+ data_abort_mask();
+ writel(val, l2x0_base + L2X0_PREFETCH_CTRL);
+ return data_abort_unmask();
+}
+
static int imx6_mmu_init(void)
{
void __iomem *l2x0_base = IOMEM(0x00a02000);
@@ -296,6 +313,9 @@ static int imx6_mmu_init(void)
if (!cpu_is_mx6())
return 0;
+ if (imx6_cannot_write_l2x0())
+ return 0;
+
val = readl(l2x0_base + L2X0_CACHE_ID);
cache_part = val & L2X0_CACHE_ID_PART_MASK;
cache_rtl = val & L2X0_CACHE_ID_RTL_MASK;
diff --git a/common/Kconfig b/common/Kconfig
index 82bbdb3145..02ef3631e0 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -640,27 +640,6 @@ config BOOTM_FORCE_SIGNED_IMAGES
are refused to boot. Effectively this means only FIT images can be booted
since they are the only supported image type that support signing.
-config BOOTM_OPTEE
- bool
- prompt "support booting OP-TEE"
- depends on BOOTM && ARM
- help
- OP-TEE is a trusted execution environment (TEE). With this option
- enabled barebox supports starting optee_os as part of the bootm command.
- Instead of the kernel bootm starts the optee_os binary which then starts
- the kernel in nonsecure mode. Pass the optee_os binary with the -t option
- or in the global.bootm.tee variable.
-
-config BOOTM_OPTEE_SIZE
- hex
- default 0x02000000
- prompt "OP-TEE Memory Size"
- depends on BOOTM_OPTEE
- help
- Size to reserve in main memory for OP-TEE.
- Can be smaller than the actual size used by OP-TEE, this is used to prevent
- barebox from allocating memory in this area.
-
config BLSPEC
depends on FLEXIBLE_BOOTARGS
depends on !SHELL_NONE
@@ -1001,6 +980,39 @@ config MACHINE_ID
Note: if no hashable information is available no machine id will be passed
to the kernel.
+menu "OP-TEE loading"
+
+config OPTEE_SIZE
+ hex
+ default 0x02000000
+ prompt "OP-TEE Memory Size"
+ depends on BOOTM_OPTEE || PBL_OPTEE
+ help
+ Size to reserve in main memory for OP-TEE.
+ Can be smaller than the actual size used by OP-TEE, this is used to prevent
+ barebox from allocating memory in this area.
+
+config BOOTM_OPTEE
+ bool
+ prompt "support booting OP-TEE"
+ depends on BOOTM && ARM
+ help
+ OP-TEE is a trusted execution environment (TEE). With this option
+ enabled barebox supports starting optee_os as part of the bootm command.
+ Instead of the kernel bootm starts the optee_os binary which then starts
+ the kernel in nonsecure mode. Pass the optee_os binary with the -t option
+ or in the global.bootm.tee variable.
+
+config PBL_OPTEE
+ bool "Enable OP-TEE early start"
+ depends on ARM
+ depends on !THUMB2_BAREBOX
+ help
+ Allows starting OP-TEE during lowlevel initialization of the PBL.
+ Requires explicit support in the boards lowlevel file.
+
+endmenu
+
endmenu
menu "Debugging"
diff --git a/common/Makefile b/common/Makefile
index 11c91dd016..84463b4d48 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -67,6 +67,8 @@ obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o
obj-$(CONFIG_BOOT) += boot.o
obj-$(CONFIG_SERIAL_DEV_BUS) += serdev.o
obj-$(CONFIG_USBGADGET_START) += usbgadget.o
+pbl-$(CONFIG_PBL_OPTEE) += optee.o
+obj-$(CONFIG_BOOTM_OPTEE) += optee.o
ifdef CONFIG_PASSWORD
diff --git a/common/optee.c b/common/optee.c
new file mode 100644
index 0000000000..d542dde118
--- /dev/null
+++ b/common/optee.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define pr_fmt(fmt) "optee: " fmt
+
+#include <tee/optee.h>
+#include <printk.h>
+#include <asm-generic/errno.h>
+
+int optee_verify_header(struct optee_header *hdr)
+{
+ if (hdr->magic != OPTEE_MAGIC) {
+ pr_err("Invalid header magic 0x%08x, expected 0x%08x\n",
+ hdr->magic, OPTEE_MAGIC);
+ return -EINVAL;
+ }
+
+ if (hdr->arch != OPTEE_ARCH_ARM32 || hdr->init_load_addr_hi) {
+ pr_err("Only 32bit supported\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/include/asm-generic/memory_layout.h b/include/asm-generic/memory_layout.h
index 3f69664aa0..0d7ce3fe02 100644
--- a/include/asm-generic/memory_layout.h
+++ b/include/asm-generic/memory_layout.h
@@ -11,8 +11,8 @@
#define MALLOC_BASE CONFIG_MALLOC_BASE
#endif
-#ifdef CONFIG_BOOTM_OPTEE_SIZE
-#define OPTEE_SIZE CONFIG_BOOTM_OPTEE_SIZE
+#ifdef CONFIG_OPTEE_SIZE
+#define OPTEE_SIZE CONFIG_OPTEE_SIZE
#else
#define OPTEE_SIZE 0
#endif
diff --git a/include/tee/optee.h b/include/tee/optee.h
index 8cfe06d889..fa124236ba 100644
--- a/include/tee/optee.h
+++ b/include/tee/optee.h
@@ -10,6 +10,9 @@
#ifndef _OPTEE_H
#define _OPTEE_H
+#include <types.h>
+#include <asm-generic/errno.h>
+
#define OPTEE_MAGIC 0x4554504f
#define OPTEE_VERSION 1
#define OPTEE_ARCH_ARM32 0
@@ -27,4 +30,12 @@ struct optee_header {
uint32_t paged_size;
};
+int optee_verify_header (struct optee_header *hdr);
+
+#ifdef __PBL__
+
+int start_optee_early(void* fdt, void* tee);
+
+#endif /* __PBL__ */
+
#endif /* _OPTEE_H */