path: root/documentation
diff options
Diffstat (limited to 'documentation')
-rw-r--r--documentation/images/secure_storage/block_data_encryption.odgbin14086 -> 14066 bytes
-rw-r--r--documentation/images/secure_storage/block_data_encryption.pngbin40890 -> 38881 bytes
-rw-r--r--documentation/images/secure_storage/meta_data_encryption.odgbin14232 -> 14494 bytes
-rw-r--r--documentation/images/secure_storage/meta_data_encryption.pngbin44106 -> 40220 bytes
9 files changed, 487 insertions, 75 deletions
diff --git a/documentation/images/secure_storage/block_data_encryption.odg b/documentation/images/secure_storage/block_data_encryption.odg
index 655c81d..53a3b6f 100644
--- a/documentation/images/secure_storage/block_data_encryption.odg
+++ b/documentation/images/secure_storage/block_data_encryption.odg
Binary files differ
diff --git a/documentation/images/secure_storage/block_data_encryption.png b/documentation/images/secure_storage/block_data_encryption.png
index b05f2c0..b2ce849 100644
--- a/documentation/images/secure_storage/block_data_encryption.png
+++ b/documentation/images/secure_storage/block_data_encryption.png
Binary files differ
diff --git a/documentation/images/secure_storage/meta_data_encryption.odg b/documentation/images/secure_storage/meta_data_encryption.odg
index f6785d4..5ccb9b3 100644
--- a/documentation/images/secure_storage/meta_data_encryption.odg
+++ b/documentation/images/secure_storage/meta_data_encryption.odg
Binary files differ
diff --git a/documentation/images/secure_storage/meta_data_encryption.png b/documentation/images/secure_storage/meta_data_encryption.png
index 9c7f8c4..5a50d73 100644
--- a/documentation/images/secure_storage/meta_data_encryption.png
+++ b/documentation/images/secure_storage/meta_data_encryption.png
Binary files differ
diff --git a/documentation/ b/documentation/
index 7ca8121..8063357 100644
--- a/documentation/
+++ b/documentation/
@@ -19,8 +19,18 @@ The processor is configured to use:
* Monitor vector for SMC exceptions
* State vector for IRQ exceptions
-Interrupts handled by secure world are sent as FIQs and interrupts handled
-by normal world are sent as IRQs.
+Two types of interrupt are defined in optee_os:
+* Native interrupt - The interrupt handled by optee_os
+ (for example: secure interrupt)
+* Foreign interrupt - The interrupt not handled by optee_os
+ (for example: non-secure interrupt which is handled by normal world)
+For ARM GICv2 mode, native interrupt is sent as FIQ and foreign interrupt is
+sent as IRQ.
+For ARM GICv3 mode, foreign interrupt is sent as FIQ which could be handled
+by either secure world (EL3 in AArch64) or normal world. This mode is not
+supported yet.
Since IRQs are received using the state vector the actual vector used
depends on the current state of the CPU. If the NS (non-secure) bit in SCR
diff --git a/documentation/ b/documentation/
index 073b46b..cb0a5af 100644
--- a/documentation/
+++ b/documentation/
@@ -151,12 +151,13 @@ table when the TA context is activated.
![Select xlation table](images/xlat_table.png "Select xlation table")
## Translation tables and switching to normal world
-When switching to normal world either via an IRQ or RPC there is a chance
-that secure world will resume execution on a different CPU. This means that
-the new CPU need to be configured with the context of the currently active
-TA. This is solved by always setting the TA context in the CPU when
-resuming execution. Here is room for improvements since it is more likely
-than not that it is the same CPU that resumes execution in secure world.
+When switching to normal world either via a foreign interrupt or RPC there
+is a chance that secure world will resume execution on a different CPU.
+This means that the new CPU need to be configured with the context of the
+currently active TA. This is solved by always setting the TA context in
+the CPU when resuming execution. Here is room for improvements since it is
+more likely than not that it is the same CPU that resumes execution in
+secure world.
# 6. Stacks
Different stacks are used during different stages. The stacks are:
@@ -216,11 +217,16 @@ is restored it will continue at the next instruction as if this function did a
normal return. CPU switches to use the temp stack before returning to normal
-## IRQ exit
-IRQ exit occurs when OP-TEE receives an IRQ, which is always handled in normal
-world. IRQ exit is similar to RPC exit but it is `thread_irq_handler()` and
-`elx_irq()` (respectively for ARMv7-A/Aarch32 and for Aarch64) that saves the
-thread state instead. The thread is resumed in the same way though.
+## Foreign interrupt exit
+Foreign interrupt exit occurs when OP-TEE receives a foreign interrupt. For ARM
+GICv2 mode, foreign interrupt is sent as IRQ which is always handled in normal
+world. Foreign interrupt exit is similar to RPC exit but it is
+`thread_irq_handler()` and `elx_irq()` (respectively for ARMv7-A/Aarch32 and
+for Aarch64) that saves the thread state instead. The thread is resumed in the
+same way though.
+For ARM GICv3 mode, foreign interrupt is sent as FIQ which could be handled by
+either secure world (EL3 in AArch64) or normal world. This mode is not supported
*Notes for ARMv7/AArch32:*
SP_IRQ is initialized to temp stack instead of a separate stack. Prior to
@@ -233,7 +239,8 @@ original `SP_EL0` is saved in the thread context to be restored when resuming.
## Resume entry
OP-TEE is entered using the temp stack in the same way as for normal entry. The
thread to resume is looked up and the state is restored to resume execution. The
-procedure to resume from an RPC exit or an IRQ exit is exactly the same.
+procedure to resume from an RPC exit or an foreign interrupt exit is exactly
+the same.
## Syscall
Syscalls are executed using the thread stack.
diff --git a/documentation/ b/documentation/
new file mode 100644
index 0000000..3ec197e
--- /dev/null
+++ b/documentation/
@@ -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:
+$ ls kern.ld.S main.c platform_config.h
+So for the gendev platform it means that the files should be placed in this
+This is the device specific makefile where you define configurations unique to
+your platform. Add good start for a new platform would be:
+PLATFORM_FLAVOR ?= gendev-flav
+# 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
+# What kind of UART should be used?
+CFG_8250_UART ?= y
+#CFG_PL011 ?= y
+# Enable power management stubs
+# Use the generic boot
+# Enable internal tests by default
+# User software random number generator
+# Does the device support crypto extensions?
+There are probably quite a few other flags that could be useful or even
+necessary. Please refer to the other `` file in the already existing
+##### 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"
+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:
+include core/arch/arm/kernel/
+##### 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):
+#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.
+ */
+static struct serial8250_uart_data console_data __early_bss;
+void console_init(void)
+ serial8250_uart_init(&console_data, CONSOLE_UART_BASE,
+ 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:
+/* Make stacks aligned to data cache line length */
+#ifdef ARM64
+#error "Pager not supported for ARM64"
+#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_RAM_VA_SIZE (4 * 1024 * 1024)
+#define CFG_TEE_LOAD_ADDR (TZDRAM_BASE + 0x20000)
+#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
+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
+[] 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
+#### 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
+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 []). We have successfully
+verified OP-TEE by using the authentication framework from ARM Trusted Firmware
+(see [] 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 []
+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]: ../
+[]: ../
+[travis]: ../.travis.yml
diff --git a/documentation/ b/documentation/
index 9202325..9aa370c 100644
--- a/documentation/
+++ b/documentation/
@@ -19,7 +19,7 @@ by CFG_REE_FS=y.
of an eMMC device, and is enabled by setting `CFG_RPMB_FS=y`. It is described
in [](
- The third one stores objects in a SQLite database in normal world. It is
-enabled by `CFG_SQL_FS=y`. See [](secure_storage_sql.db).
+enabled by `CFG_SQL_FS=y`. See [](
It is possible to use the normal world filesystems and the RPMB implementations
simultaneously. For this, three OP-TEE specific storage identifiers have been
@@ -42,6 +42,7 @@ The rest of this document describes the REE FS only.
storage service calls
- **[core/tee/tee_ree_fs.c](../core/tee/tee_ree_fs):** TEE file system & REE
file operation interface
+- **[core/tee/fs_htree.c](../core/tee/fs_htree.c):** Hash tree
- **[core/tee/tee_fs_key_manager.c](../core/tee/tee_fs_key_manager.c):** Key
- **[lib/libutee/](../lib/libutee/):** GlobalPlatform Internal API library
@@ -72,7 +73,7 @@ Below is an excerpt from the specification listing the most vital requirements:
instances of that TA but separated from the other TAs.
5. The Trusted Storage must provide a minimum level of protection against
rollback attacks. It is accepted that the actually physical storage may be in
- an unsecure areas and so is vulnerable to actions from outside of the TEE.
+ an insecure area and so is vulnerable to actions from outside of the TEE.
Typically, an implementation may rely on the REE for that purpose (protection
level 100) or on hardware assets controlled by the TEE (protection level
@@ -87,45 +88,6 @@ file system. For each TA, OP-TEE use the TA's UUID to create a standalone folder
for it under the secure storage space folder. For a persistent object belonging
to a specific TA, OP-TEE creates a TEE file is object-id under the TA folder.
-All fields in the REE file are duplicated with two versions 0 and 1. The
-active meta-data block is selected by the lowest bit in the
-meta-counter. The active file block is selected by corresponding bit
-number instruct tee_fs_file_info.backup_version_table.
-The atomicity of each operation is ensured by updating meta-counter when
-everything in the secondary blocks (both meta-data and file-data blocks)
-are successfully written. The main purpose of the code is to perform block
-encryption and authentication of the file data, and properly handle seeking
-through the file. One file (in the sense of struct tee_file_operations)
-maps to one file in the REE filesystem, and has the following structure:
-[ 4 bytes meta-counter]
-[ meta-data version 0][ meta-data version 1 ]
-[ Block 0 version 0 ][ Block 0 version 1 ]
-[ Block 1 version 0 ][ Block 1 version 1 ]
-[ Block n version 0 ][ Block n version 1 ]
-One meta-data block is built up as:
-[ struct meta_header | struct tee_fs_get_header_size ]
-One data block is built up as:
-[ struct block_header | BLOCK_FILE_SIZE bytes ]
-The reason why we store the TEE file content in many small blocks is to
-accelerate the file update speed when handling a large file. The block size
-(FILE_BLOCK_SIZE) and the maximum number of blocks of a TEE file
-(NUM_BLOCKS_PER_FILE) are defined in
-For now, the default block size is 4KB and the maximum number of blocks of a
-TEE file is 1024.
## Key Manager
Key manager is an component in TEE file system, and is responsible for handling
@@ -177,22 +139,57 @@ PRNG (pesudo random number generator) for the TEE file and store the encrypted
FEK in meta file. FEK is used for encrypting/decrypting the TEE file information
stored in meta file or the data stored in block file.
+## Hash Tree
+The hash tree is responsible for handling data encryption and decryption of
+a secure storage file.
+The hash tree is implemented as a binary tree where
+each node (`struct tee_fs_htree_node_image` below) in the tree protects its
+two child nodes and a data block.
+The meta data is stored in a header (`struct tee_fs_htree_image` below)
+which also protects the top node.
+All fields (header, nodes, and blocks) are duplicated with two versions, 0
+and 1, to ensure atomic updates. See
+[core/tee/fs_htree.c](../core/tee/fs_htree.c) for details.
### Meta Data Encryption Flow
![Meta Data Encryption](images/secure_storage/meta_data_encryption.png
"Meta data encryption")
A new meta IV will be generated by PRNG when a meta data needs to be updated.
-The default size of meta IV is defined in
+The size of meta IV is defined in
-The data structure of meta data is defined in
-[core/tee/tee_fs_private.h](../core/tee/tee_fs_private.h) as follows:
+The data structures of meta data and node data are defined in
+[core/include/tee/fs_htree.h](../core/include/tee/fs_htree.h) as follows:
-struct tee_fs_file_info {
- size_t length;
- uint32_t backup_version_table[NUM_BLOCKS_PER_FILE / 32];
+struct tee_fs_htree_node_image {
+ uint8_t hash[TEE_FS_HTREE_HASH_SIZE];
+ uint8_t iv[TEE_FS_HTREE_IV_SIZE];
+ uint8_t tag[TEE_FS_HTREE_TAG_SIZE];
+ uint16_t flags;
+struct tee_fs_htree_meta {
+ uint64_t length;
+struct tee_fs_htree_imeta {
+ struct tee_fs_htree_meta meta;
+ uint32_t max_node_id;
+struct tee_fs_htree_image {
+ uint8_t iv[TEE_FS_HTREE_IV_SIZE];
+ uint8_t tag[TEE_FS_HTREE_TAG_SIZE];
+ uint8_t enc_fek[TEE_FS_HTREE_FEK_SIZE];
+ uint8_t imeta[sizeof(struct tee_fs_htree_imeta)];
+ uint32_t counter;
@@ -202,8 +199,8 @@ struct tee_fs_file_info {
"Block data encryption")
A new block IV will be generated by PRNG when a block data needs to be updated.
-The default size of block IV is defined in
+The size of block IV is defined in
## Atomic Operation
diff --git a/documentation/ b/documentation/
index 675c794..620e477 100644
--- a/documentation/
+++ b/documentation/
@@ -45,21 +45,18 @@ the SQL filesystem is the **tee_file_operations** structure `sql_fs_ops`.
## The SQL filesystem
The secure side of the SQL FS implementation is mostly in
-[core/tee/tee_sql_fs.c](../core/tee/tee_sql_fs.c). This file maps the operations
-in `sql_fs_ops` such as `open`, `truncate`, `read`, `write`, `seek`
-and so on, to similar operations on a file that is a container for the encrypted
-data and associated meta-data. This container is created and manipulated by
-`tee-supplicant` on request from the secure OS. Its layout is like this:
- [ File meta-data ] [ Block #0 ] [Block #1]...
- [meta_header|sql_fs_file_meta] [block_header|user data] [ ]...
+[core/tee/tee_sql_fs.c](../core/tee/tee_sql_fs.c). This file maps the
+operations in `sql_fs_ops` such as `open`, `truncate`, `read`, `write`
+and so on, to similar operations on a file that is a container for
+the encrypted data and associated meta-data. This container is created and
+manipulated by `tee-supplicant` on request from the secure OS. Its logical
+layout is similar to REE FS except that there's only a single version of
+each field as atomic updates are ensured by **libsqlfs** instead.
How this file is stored in the SQLite database is private to **libsqlfs**. From
the point of view of OP-TEE, it is a byte-addressable linear file on which
atomic updates can be performed through a standard interface (`open`,
-`truncate`, `seek`, `read`, `write`...) with the addition of `begin_transaction`
+`truncate`, `read`, `write`...) with the addition of `begin_transaction`
and `end_transaction`.
## Encryption