summaryrefslogtreecommitdiff
path: root/documentation/porting_guidelines.md
diff options
context:
space:
mode:
Diffstat (limited to 'documentation/porting_guidelines.md')
-rw-r--r--documentation/porting_guidelines.md401
1 files changed, 401 insertions, 0 deletions
diff --git a/documentation/porting_guidelines.md b/documentation/porting_guidelines.md
new file mode 100644
index 0000000..3ec197e
--- /dev/null
+++ b/documentation/porting_guidelines.md
@@ -0,0 +1,401 @@
+Porting guidelines for OP-TEE
+=============================
+
+1. [Introduction](#1-introduction)
+2. [Add a new platform](#2-add-a-new-platform)
+3. [Hardware Unique Key](#3-hardware-unique-key)
+4. [Secure Clock](#4-secure-clock)
+5. [Root and Chain of Trust](#5-root-and-chain-of-trust)
+6. [Hardware Crypto IP](#6-hardware-crypto-ip)
+7. [Power Management / PSCI](#7-power-management--psci)
+8. [Memory firewalls / TZASC](#8-memory-firewalls--tzasc)
+9. [Trusted Application private/public keypair](#9-trusted-application-privatepublic-keypair)
+
+## 1. Introduction
+---------------
+This document serves a dual purpose:
+* Serve as a base for getting OP-TEE up and running on a new device with initial
+ xtest validation passing. This is the first part of this document (section 2).
+* Highlight the missing pieces if you intend to make intend to make a real
+ secure product, that is what the second part of this document is about.
+
+We are trying our best to implement full end to end security in OP-TEE in a
+generic way, but due to the nature of devices being different, NDA etc, it is
+not always possible for us to do so and in those cases, we most often try to
+write a generic API, but we will just stub the code. This porting guideline
+highlights the missing pieces that must be addressed in a real secure consumer
+device. Hopefully we will sooner or later get access to devices where we at
+least can make reference implementations publicly available to everyone for the
+missing pieces we are talking about here.
+
+## 2. Add a new platform
+The first thing you need to do after you have decided to port OP-TEE to another
+device is to add a new platform device. That can either be adding a new platform
+variant (`PLATFORM_FLAVOR`) if it is a device from a family already supported,
+or it can be a brand new platform family (`PLATFORM`). Typically this initial
+setup involve configuring UART, memory addresses etc. For simplicity let us call
+our fictive platform for "gendev" just so we have something to refer to when
+writing examples further down.
+
+### 2.1 core/arch/arm
+In `core/arch/arm` you will find all the currently supported devices. That is
+where you are supposed to add a new platform or modify an existing one.
+Typically you will find this set of files in a specific platform folder:
+```bash
+$ ls
+conf.mk kern.ld.S link.mk main.c platform_config.h sub.mk
+```
+
+So for the gendev platform it means that the files should be placed in this
+folder:
+```bash
+core/arch/arm/plat-gendev
+```
+
+##### conf.mk
+This is the device specific makefile where you define configurations unique to
+your platform. Add good start for a new platform would be:
+```Makefile
+PLATFORM_FLAVOR ?= gendev-flav
+PLATFORM_FLAVOR_$(PLATFORM_FLAVOR) := y
+
+# 32-bit flags
+arm32-platform-cpuarch := cortex-a15
+arm32-platform-cflags += -mcpu=$(arm32-platform-cpuarch)
+arm32-platform-aflags += -mcpu=$(arm32-platform-cpuarch)
+arm32-platform-aflags += -mfpu=neon
+
+# Running 32-bit core?
+CFG_ARM32_core ?= y
+ta-targets = ta_arm32
+
+# How many threads are enabled in TEE core
+CFG_NUM_THREADS ?= 4
+
+# What kind of UART should be used?
+CFG_8250_UART ?= y
+#CFG_PL011 ?= y
+
+# Enable power management stubs
+CFG_PM_STUBS := y
+
+# Use the generic boot
+CFG_GENERIC_BOOT := y
+
+# Enable internal tests by default
+CFG_TEE_CORE_EMBED_INTERNAL_TESTS ?= y
+
+# User software random number generator
+CFG_WITH_SOFTWARE_PRNG ?= y
+
+# Does the device support crypto extensions?
+CFG_CRYPTO_WITH_CE ?= n
+```
+There are probably quite a few other flags that could be useful or even
+necessary. Please refer to the other `conf.mk` file in the already existing
+platforms.
+
+##### kern.ld.S
+This is your linker script. As it turns out, most of the existing platforms use
+the same linker script and therefore most likely you will only need to add this
+single line to the file:
+```
+#include "../kernel/kern.ld.S"
+```
+
+##### link.mk
+This is the makefile for the linker, just as for the linker script, most
+platforms use the same and generic makefile for the linker, so adding only this
+should probably be sufficient:
+```Makefile
+include core/arch/arm/kernel/link.mk
+```
+
+##### main.c
+This platform specific file will contain power management handlers and code
+related to the UART. We will talk more about the information related to the
+handlers further down in this document. For our gendev device it could look like
+this (here we are excluding the necessary license header to save some space):
+
+```c
+#include <console.h>
+#include <drivers/serial8250_uart.h>
+#include <kernel/generic_boot.h>
+#include <kernel/panic.h>
+#include <kernel/pm_stubs.h>
+#include <mm/core_memprot.h>
+#include <mm/tee_pager.h>
+#include <platform_config.h>
+#include <stdint.h>
+#include <tee/entry_fast.h>
+#include <tee/entry_std.h>
+
+static void main_fiq(void)
+{
+ panic();
+}
+
+static const struct thread_handlers handlers = {
+ .std_smc = tee_entry_std,
+ .fast_smc = tee_entry_fast,
+ .nintr = main_fiq,
+ .cpu_on = cpu_on_handler,
+ .cpu_off = pm_do_nothing,
+ .cpu_suspend = pm_do_nothing,
+ .cpu_resume = pm_do_nothing,
+ .system_off = pm_do_nothing,
+ .system_reset = pm_do_nothing,
+};
+
+const struct thread_handlers *generic_boot_get_handlers(void)
+{
+ return &handlers;
+}
+
+/*
+ * Register the physical memory area for peripherals etc. Here we are
+ * registering the UART console.
+ */
+register_phys_mem(MEM_AREA_IO_NSEC, CONSOLE_UART_BASE, SERIAL8250_UART_REG_SIZE);
+
+static struct serial8250_uart_data console_data __early_bss;
+
+void console_init(void)
+{
+ serial8250_uart_init(&console_data, CONSOLE_UART_BASE,
+ CONSOLE_UART_CLK_IN_HZ, CONSOLE_BAUDRATE);
+ register_serial_console(&console_data.chip);
+}
+```
+
+##### platform_config.h
+This is a mandatory header file for every platform, since there are several
+files relaying upon the existence of this particular file. This file is where
+you will find the major differences between different platforms, since this is
+where you do the memory configuration, define base addresses etc. we are going to
+list a few here, but it probably makes more sense to have a look at the already
+existing `platform_config.h` files for the other platforms. Our fictive gendev
+could look like this:
+
+```c
+#ifndef PLATFORM_CONFIG_H
+#define PLATFORM_CONFIG_H
+
+/* Make stacks aligned to data cache line length */
+#define STACK_ALIGNMENT 64
+
+#ifdef ARM64
+#ifdef CFG_WITH_PAGER
+#error "Pager not supported for ARM64"
+#endif
+#endif /* ARM64 */
+
+/* 8250 UART */
+#define CONSOLE_UART_BASE 0xcafebabe /* UART0 */
+#define CONSOLE_BAUDRATE 115200
+#define CONSOLE_UART_CLK_IN_HZ 19200000
+
+#define DRAM0_BASE 0x00000000
+#define DRAM0_SIZE 0x40000000
+
+/* Below ARM-TF */
+#define CFG_SHMEM_START 0x08000000
+#define CFG_SHMEM_SIZE (4 * 1024 * 1024)
+
+/* If your device has SRAM */
+#define TZSRAM_BASE 0x3F000000
+#define TZSRAM_SIZE (200 * 1024)
+
+/* Otherwise or in addition, use DDR */
+#define TZDRAM_BASE 0x60000000
+#define TZDRAM_SIZE (32 * 1024 * 1024)
+
+#define CFG_TEE_CORE_NB_CORE 4
+
+#define CFG_TEE_RAM_VA_SIZE (4 * 1024 * 1024)
+
+#define CFG_TEE_LOAD_ADDR (TZDRAM_BASE + 0x20000)
+
+#define CFG_TEE_RAM_PH_SIZE CFG_TEE_RAM_VA_SIZE
+#define CFG_TEE_RAM_START TZDRAM_BASE
+
+#define CFG_TA_RAM_START ROUNDUP((TZDRAM_BASE + CFG_TEE_RAM_VA_SIZE), \
+ CORE_MMU_DEVICE_SIZE)
+#define CFG_TA_RAM_SIZE (16 * 1024 * 1024)
+#endif /* PLATFORM_CONFIG_H */
+```
+This is minimal amount of information in the `platform_config.h` file. I.e, the
+memory layout for on-chip and external RAM. Note that parts of the DDR typically
+will need to be shared with normal world, so there is need for some kind of
+memory firewall for this (more about that further down). As you can see we have
+also added the UART configuration here, i.e., the `DEVICE0_xyz` part.
+
+### 2.2 Devices officially in OP-TEE?
+We do encourage everyone to submit their board support to the OP-TEE project
+itself, so it becomes part of the official releases and will be maintained by
+the OP-TEE community itself. If you intend to do so, then there are a few more
+things that you are supposed to do.
+
+#### 2.2.1 Update README.md
+There is a section ([3. Platforms Supported]) that lists all devices officially
+supported in OP-TEE, that is where you also shall list your device. It should
+contain the name of the platform, then composite `PLATFORM` flag and whether the
+device is publicly available or not.
+
+#### 2.2.2 Update travis.xml
+Since we are using Travis to test pull request etc, we would like that you also
+all your device to the [travis] file, so that it will at least be built when
+someone is doing a pull request. Add a line saying:
+
+```
+- PLATFORM=gendev PLATFORM_FLAVOR=gendev-flav make -j8 all -s
+```
+#### 2.2.3 Maintainer
+If you are submitting the board support upstream and cannot give Linaro
+maintainers a device, then we are going to ask you to become the maintainer for
+the device you have added. This means that you should also update the
+[MAINTAINERS.md] file accordingly. By being a maintainer for a device you are
+responsible to keep it up to date and you will be asked every quarter as part of
+the OP-TEE release schedule to test your device running the latest OP-TEE
+software.
+
+#### 2.2.4 Update build.git
+This isn't strictly necessary, but we are trying to create repo setup(s) for the
+device(s) that we are in charge of. That makes it very easy for newcomers to get
+started with a certain platform. So please consider creating a new [manifest]
+for the device you have added to OP-TEE.
+
+## 3. Hardware Unique Key
+Most devices have some kind of Hardware Unique Key (HUK) that is mainly used to
+derive other keys. The HUK could for example be used when deriving keys used in
+secure storage etc. The important thing with the HUK is that it needs to be well
+protected and in the best case the HUK should never ever be readable directly
+from software, not even from the secure side. There are different solutions to
+this, crypto accelerator might have support for it or, it could involve another
+secure co-processor.
+
+In OP-TEE the HUK **is** just **stubbed** and you will see that in the function
+called `tee_otp_get_hw_unique_key()` in `core/include/kernel/tee_common_otp.h`.
+In a real secure product you **must** replace this with something else. If your
+device lacks the hardware support for a HUK, then you must at least change this
+to something else than just zeroes. But, remember it is not good secure practice
+to store a key in software, especially not the key that is the root for
+everything else, so this is not something we recommend that you should do.
+
+## 4. Secure Clock
+The Time API in GlobalPlatform Internal Core API specification defines three
+sources of time; system time, TA persistent time and REE time. The REE time
+is by nature considered as an unsecure source of time, but the other two should
+in a fully trustable hardware make use of trustable source of time, i.e., a
+secure clock. Note that from GlobalPlatform point of view it is not required to
+make use of a secure clock, i.e., it is OK to use time from REE, but the level
+of trust should be reflected by the `gpd.tee.systemTime.protectionLevel`
+property and the `gpd.tee.TAPersistentTime.protectionLevel` property (100=REE
+controlled clock, 1000=TEE controlled clock). So the functions that one needs to
+pay attention to are `tee_time_get_sys_time()` and `tee_time_get_ta_time()`. If
+your hardware has a secure clock, then you probably want to change the
+implementation there to instead use the secure clock (and then you would also
+need to update the property accordingly, i.e.,
+`tee_time_get_sys_time_protection_level()` and the variable `ta_time_prot_lvl`
+in `tee_svc.c`).
+
+## 5. Root and Chain of Trust
+To be able to assure that your devices are running the (untampered) binaries you
+intended to run you will need to establish some kind of trust anchor on the
+devices.
+
+The most common way of doing that is to put the root public key in some
+read only memory on the device. Quite often SoC's/OEM's stores public key(s)
+directly or the hash(es) of the public key(s) in [OTP]. When the boot ROM (which
+indeed needs to be ROM) is about to load the first stage bootloader it typically
+reads the public key from the software binary itself, hash the key and compare
+it to the key in OTP. If they are matching, then the boot ROM can be sure that
+the first stage bootloader was indeed signed with the corresponding private key.
+
+In OP-TEE you will not find any code at all related to this and this is a good
+example when it is hard for us to do this in a generic way since device
+manufacturers all tend to do this in their own unique way and they are not very
+keen on sharing their low level boot details and security implementation with
+the rest of the world. This is especially true on ARMv7-A. For ARMv8-A it looks
+bit better, since ARM in ARM Trusted Firmware have implemented and defined how a
+abstract the chain of trust (see [auth-framework.md]). We have successfully
+verified OP-TEE by using the authentication framework from ARM Trusted Firmware
+(see [optee_with_auth_framework.md] for the details).
+
+## 6. Hardware Crypto IP
+By default OP-TEE uses a software crypto library (currently LibTomCrypt) and you
+have the ability to enable Crypto Extensions that were introduced with ARMv8-A
+(if the device is capable of that). Some of the devices we have in our hands do
+have hardware crypto IP's, but due to NDA's etc it has not been possible to
+enable it. If you have a device capable of doing crypto operations on a
+dedicated crypto block and you prefer to use that in favor for the software
+implementation, then you will need to implement a new `crypto_ops` structure and
+write the low level driver that communicates with the device. Our [crypto.md]
+file describes how to add and implement a new `struct crypto_ops`. Since the
+communication with crypto blocks tends to be quite different depending on what
+kind of crypto block you have, we have not written how that should be done. It
+might be that we do that in the future when get hold of a device where we can
+use the crypto block.
+
+## 7. Power Management / PSCI
+In section 2 when we talked about the file `main.c`, we added a couple of
+handlers related to power management, we are talking about the following lines:
+```
+ .cpu_on = cpu_on_handler,
+ .cpu_off = pm_do_nothing,
+ .cpu_suspend = pm_do_nothing,
+ .cpu_resume = pm_do_nothing,
+ .system_off = pm_do_nothing,
+ .system_reset = pm_do_nothing,
+```
+The only function that actually does something there is the `cpu_on` function,
+the rest of them are stubbed. The main reason for that is because we think that
+how to suspend and resume is a device dependent thing. The code in OP-TEE is
+prepared so that callbacks etc from ARM Trusted Firmware will be routed to
+OP-TEE, but since the function(s) are just stubbed we will not do anything and
+just return. In a real production device, you would probably want to save and
+restore CPU states, secure hardware IPs' registers and TZASC and other memory
+firewall related setting when these callbacks are being called.
+
+## 8. Memory firewalls / TZASC
+ARM have defined a system IP / SoC peripheral called TrustZone Address Space
+Controller (TZASC, see [TZC-380] and [TZC-400]). TZASC can be used to configure
+DDR memory into separate regions in the physcial address space, where each
+region can have an individual security level setting. After enabling TZASC, it
+will perform security checks on transactions to memory or peripherals. It is not
+always the case that TZASC is on a device, in some cases the SoC has developed
+something equivalent. In OP-TEE this is very well reflected, i.e., different
+platforms have different ways of protecting their memory. On ARMv8-A platforms
+we are in most of the cases using ARM Trusted Firmware as the boot firmware and
+there the secure bootloader is the one that configures secure vs non-secure
+memory using TZASC (see [plat_arm_security_setup] in ARM-TF). The takeaway here
+is that you must make sure that you have configured whatever memory firewall your
+device has such that it has a secure and a non-secure memory area.
+
+## 9. Trusted Application private/public keypair
+By default all Trusted Applications (TA's) are signed with the pre-generated
+2048-bit RSA development key (private key). This key is located in the `keys`
+folder (in the root of optee_os.git) and is named `default_ta.pem`. This key
+**must** be replaced with your own key and you should **never ever** check-in
+this private key in the source code tree when in use in a real product. The
+recommended way to store private keys is to use some kind of [HSM] (Hardware
+Security Module), but an alternative would be temporary put the private key on a
+computer considered as secure when you are about to sign TA's intended to be
+used in real products. Typically it is only a few number of people having access
+to this type of key in company. The key handling in OP-TEE is currently a bit
+limited since we only support a single key which is used for all TA's. We have
+plans on extending this to make it a bit more flexible. Exactly when that will
+happen has not been decided yet.
+
+[3. Platforms Supported]: ../README.md#3-platforms-supported
+[auth-framework.md]: https://github.com/ARM-software/arm-trusted-firmware/blob/master/docs/auth-framework.md
+[crypto.md]: crypto.md
+[HSM]: https://en.wikipedia.org/wiki/Hardware_security_module
+[manifest]: https://github.com/OP-TEE/build#6-manifests
+[MAINTAINERS.md]: ../MAINTAINERS.md
+[optee_with_auth_framework.md]: optee_with_auth_framework.md
+[OTP]: https://en.wikipedia.org/wiki/Programmable_read-only_memory
+[plat_arm_security_setup]: https://github.com/ARM-software/arm-trusted-firmware/search?utf8=%E2%9C%93&q=plat_arm_security_setup&type=
+[TZC-380]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0431c/index.html
+[TZC-400]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.100325_0001_02_en/index.html
+[travis]: ../.travis.yml