summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHaoran.Wang <elven.wang@nxp.com>2017-08-28 15:21:44 +0800
committerYe Li <ye.li@nxp.com>2018-06-13 03:06:36 -0700
commit0ccdd527a794c2b450658980361a7857ce7495c9 (patch)
treeb04765783a5d5789bae9af434901268d6bc8d427 /lib
parent2c840c82b3558267650b98735790ac7151644ae1 (diff)
MLK-18591-4 android: iot: Import ql-tipc lib for Trusty OS
The lib provided ql-tipc communication channel with Trusty OS. Also the AVB, Keymaster and SecureStorage service tipc client implement in this lib. Change-Id: I0ab1ec9ee1b6f272b960c2e944008283c2c9249a Signed-off-by: Haoran.Wang <elven.wang@nxp.com> (cherry picked from commit 8fb370dd80fbb293b58115d2e7fc4970813773c7)
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile1
-rw-r--r--lib/trusty/ql-tipc/LICENSE20
-rw-r--r--lib/trusty/ql-tipc/README.md30
-rw-r--r--lib/trusty/ql-tipc/arch/arm/sm_err.h45
-rw-r--r--lib/trusty/ql-tipc/arch/arm/smcall.h143
-rw-r--r--lib/trusty/ql-tipc/arch/arm/trusty_dev.c257
-rw-r--r--lib/trusty/ql-tipc/arch/arm/trusty_mem.c259
-rw-r--r--lib/trusty/ql-tipc/avb.c250
-rw-r--r--lib/trusty/ql-tipc/ipc.c299
-rw-r--r--lib/trusty/ql-tipc/ipc_dev.c448
-rw-r--r--lib/trusty/ql-tipc/keymaster.c350
-rw-r--r--lib/trusty/ql-tipc/libtipc.c101
-rw-r--r--lib/trusty/ql-tipc/rpmb_proxy.c337
-rw-r--r--lib/trusty/ql-tipc/sysdeps/Makefile46
-rw-r--r--lib/trusty/ql-tipc/sysdeps/storage_ops_uboot.c122
-rw-r--r--lib/trusty/ql-tipc/sysdeps/sysdeps_uboot.c124
16 files changed, 2832 insertions, 0 deletions
diff --git a/lib/Makefile b/lib/Makefile
index cef1e3e903..8529d4f2e1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_FIT) += libfdt/
obj-$(CONFIG_OF_LIVE) += of_live.o
obj-$(CONFIG_CMD_DHRYSTONE) += dhry/
obj-$(CONFIG_ARCH_AT91) += at91/
+obj-$(CONFIG_IMX_TRUSTY_OS) += trusty/ql-tipc/sysdeps/
obj-$(CONFIG_AES) += aes.o
obj-$(CONFIG_AVB_SUPPORT) += avb/
diff --git a/lib/trusty/ql-tipc/LICENSE b/lib/trusty/ql-tipc/LICENSE
new file mode 100644
index 0000000000..d21621abc4
--- /dev/null
+++ b/lib/trusty/ql-tipc/LICENSE
@@ -0,0 +1,20 @@
+Copyright 2016, The Android Open Source Project
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/lib/trusty/ql-tipc/README.md b/lib/trusty/ql-tipc/README.md
new file mode 100644
index 0000000000..76e3781756
--- /dev/null
+++ b/lib/trusty/ql-tipc/README.md
@@ -0,0 +1,30 @@
+# Queueless Trusty IPC
+
+ql-tipc is a portable client library that implements Trusty queueless IPC.
+It is intended to enable Trusty IPC in bootloader environments.
+
+## Code organization
+
+### IPC components
+
+- libtipc - Functions to be called by library user
+- ipc - IPC library
+- ipc_dev - Helper functions for sending requests to the secure OS
+- rpmb_proxy - Handles RPMB requests from secure storage service
+- avb - Sends requests to the Android Verified Boot service
+
+### Misc
+
+- examples/ - Implementations of bootloader-specific code.
+- arch/$ARCH/ - Architecture dependent implementation of Trusty device
+ (see trusty_dev.h). Implements SMCs on ARM for example.
+
+## Portability Notes
+
+The suggested approach to porting ql-tipc is to copy all header and C files
+into the bootloader and integrate as needed. RPMB storage operations and
+functions defined in trusty/sysdeps.h require system dependent implementations.
+
+If the TIPC_ENABLE_DEBUG preprocessor symbol is set, the code will include
+debug information and run-time checks. Production builds should not use this.
+
diff --git a/lib/trusty/ql-tipc/arch/arm/sm_err.h b/lib/trusty/ql-tipc/arch/arm/sm_err.h
new file mode 100644
index 0000000000..940125611c
--- /dev/null
+++ b/lib/trusty/ql-tipc/arch/arm/sm_err.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef QL_TIPC_SM_ERR_H_
+#define QL_TIPC_SM_ERR_H_
+
+/* Errors from the secure monitor */
+#define SM_ERR_UNDEFINED_SMC 0xFFFFFFFF /* Unknown SMC (defined by ARM DEN 0028A(0.9.0) */
+#define SM_ERR_INVALID_PARAMETERS -2
+#define SM_ERR_INTERRUPTED -3 /* Got interrupted. Call back with restart SMC */
+#define SM_ERR_UNEXPECTED_RESTART -4 /* Got an restart SMC when we didn't expect it */
+#define SM_ERR_BUSY -5 /* Temporarily busy. Call back with original args */
+#define SM_ERR_INTERLEAVED_SMC -6 /* Got a trusted_service SMC when a restart SMC is required */
+#define SM_ERR_INTERNAL_FAILURE -7 /* Unknown error */
+#define SM_ERR_NOT_SUPPORTED -8
+#define SM_ERR_NOT_ALLOWED -9 /* SMC call not allowed */
+#define SM_ERR_END_OF_INPUT -10
+#define SM_ERR_PANIC -11 /* Secure OS crashed */
+#define SM_ERR_FIQ_INTERRUPTED -12 /* Got interrupted by FIQ. Call back with SMC_SC_RESTART_FIQ on same CPU */
+#define SM_ERR_CPU_IDLE -13 /* SMC call waiting for another CPU */
+#define SM_ERR_NOP_INTERRUPTED -14 /* Got interrupted. Call back with new SMC_SC_NOP */
+#define SM_ERR_NOP_DONE -15 /* Cpu idle after SMC_SC_NOP (not an error) */
+
+#endif /* QL_TIPC_SM_ERR_H_ */
diff --git a/lib/trusty/ql-tipc/arch/arm/smcall.h b/lib/trusty/ql-tipc/arch/arm/smcall.h
new file mode 100644
index 0000000000..695776c93e
--- /dev/null
+++ b/lib/trusty/ql-tipc/arch/arm/smcall.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef QL_TIPC_SMCALL_H_
+#define QL_TIPC_SMCALL_H_
+
+#define SMC_NUM_ENTITIES 64
+#define SMC_NUM_ARGS 4
+#define SMC_NUM_PARAMS (SMC_NUM_ARGS - 1)
+
+#define SMC_IS_FASTCALL(smc_nr) ((smc_nr) & 0x80000000)
+#define SMC_IS_SMC64(smc_nr) ((smc_nr) & 0x40000000)
+#define SMC_ENTITY(smc_nr) (((smc_nr) & 0x3F000000) >> 24)
+#define SMC_FUNCTION(smc_nr) ((smc_nr) & 0x0000FFFF)
+
+#define SMC_NR(entity, fn, fastcall, smc64) ((((fastcall) & 0x1) << 31) | \
+ (((smc64) & 0x1) << 30) | \
+ (((entity) & 0x3F) << 24) | \
+ ((fn) & 0xFFFF) \
+ )
+
+#define SMC_FASTCALL_NR(entity, fn) SMC_NR((entity), (fn), 1, 0)
+#define SMC_STDCALL_NR(entity, fn) SMC_NR((entity), (fn), 0, 0)
+#define SMC_FASTCALL64_NR(entity, fn) SMC_NR((entity), (fn), 1, 1)
+#define SMC_STDCALL64_NR(entity, fn) SMC_NR((entity), (fn), 0, 1)
+
+#define SMC_ENTITY_ARCH 0 /* ARM Architecture calls */
+#define SMC_ENTITY_CPU 1 /* CPU Service calls */
+#define SMC_ENTITY_SIP 2 /* SIP Service calls */
+#define SMC_ENTITY_OEM 3 /* OEM Service calls */
+#define SMC_ENTITY_STD 4 /* Standard Service calls */
+#define SMC_ENTITY_RESERVED 5 /* Reserved for future use */
+#define SMC_ENTITY_TRUSTED_APP 48 /* Trusted Application calls */
+#define SMC_ENTITY_TRUSTED_OS 50 /* Trusted OS calls */
+#define SMC_ENTITY_LOGGING 51 /* Used for secure -> nonsecure logging */
+#define SMC_ENTITY_SECURE_MONITOR 60 /* Trusted OS calls internal to secure monitor */
+
+/* FC = Fast call, SC = Standard call */
+#define SMC_SC_RESTART_LAST SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0)
+#define SMC_SC_LOCKED_NOP SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1)
+
+/**
+ * SMC_SC_RESTART_FIQ - Re-enter trusty after it was interrupted by an fiq
+ *
+ * No arguments, no return value.
+ *
+ * Re-enter trusty after returning to ns to process an fiq. Must be called iff
+ * trusty returns SM_ERR_FIQ_INTERRUPTED.
+ *
+ * Enable by selecting api version TRUSTY_API_VERSION_RESTART_FIQ (1) or later.
+ */
+#define SMC_SC_RESTART_FIQ SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 2)
+
+/**
+ * SMC_SC_NOP - Enter trusty to run pending work.
+ *
+ * No arguments.
+ *
+ * Returns SM_ERR_NOP_INTERRUPTED or SM_ERR_NOP_DONE.
+ * If SM_ERR_NOP_INTERRUPTED is returned, the call must be repeated.
+ *
+ * Enable by selecting api version TRUSTY_API_VERSION_SMP (2) or later.
+ */
+#define SMC_SC_NOP SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 3)
+
+/*
+ * Return from secure os to non-secure os with return value in r1
+ */
+#define SMC_SC_NS_RETURN SMC_STDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0)
+
+#define SMC_FC_RESERVED SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0)
+#define SMC_FC_FIQ_EXIT SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1)
+#define SMC_FC_REQUEST_FIQ SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 2)
+#define SMC_FC_GET_NEXT_IRQ SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 3)
+#define SMC_FC_FIQ_ENTER SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 4)
+
+#define SMC_FC64_SET_FIQ_HANDLER SMC_FASTCALL64_NR(SMC_ENTITY_SECURE_MONITOR, 5)
+#define SMC_FC64_GET_FIQ_REGS SMC_FASTCALL64_NR (SMC_ENTITY_SECURE_MONITOR, 6)
+
+#define SMC_FC_CPU_SUSPEND SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 7)
+#define SMC_FC_CPU_RESUME SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 8)
+
+#define SMC_FC_AARCH_SWITCH SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 9)
+#define SMC_FC_GET_VERSION_STR SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 10)
+
+/**
+ * SMC_FC_API_VERSION - Find and select supported API version.
+ *
+ * @r1: Version supported by client.
+ *
+ * Returns version supported by trusty.
+ *
+ * If multiple versions are supported, the client should start by calling
+ * SMC_FC_API_VERSION with the largest version it supports. Trusty will then
+ * return a version it supports. If the client does not support the version
+ * returned by trusty and the version returned is less than the version
+ * requested, repeat the call with the largest supported version less than the
+ * last returned version.
+ *
+ * This call must be made before any calls that are affected by the api version.
+ */
+#define TRUSTY_API_VERSION_RESTART_FIQ (1)
+#define TRUSTY_API_VERSION_SMP (2)
+#define TRUSTY_API_VERSION_SMP_NOP (3)
+#define TRUSTY_API_VERSION_CURRENT (3)
+#define SMC_FC_API_VERSION SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 11)
+
+/* TRUSTED_OS entity calls */
+#define SMC_SC_VIRTIO_GET_DESCR SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 20)
+#define SMC_SC_VIRTIO_START SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 21)
+#define SMC_SC_VIRTIO_STOP SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 22)
+
+#define SMC_SC_VDEV_RESET SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 23)
+#define SMC_SC_VDEV_KICK_VQ SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 24)
+#define SMC_NC_VDEV_KICK_VQ SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 25)
+
+/* Queueless Trusty IPC Interface */
+#define SMC_SC_TRUSTY_IPC_CREATE_QL_DEV SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 30)
+#define SMC_SC_TRUSTY_IPC_SHUTDOWN_QL_DEV SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 31)
+#define SMC_SC_TRUSTY_IPC_HANDLE_QL_DEV_CMD SMC_STDCALL_NR(SMC_ENTITY_TRUSTED_OS, 32)
+
+#endif /* QL_TIPC_SMCALL_H_ */
diff --git a/lib/trusty/ql-tipc/arch/arm/trusty_dev.c b/lib/trusty/ql-tipc/arch/arm/trusty_dev.c
new file mode 100644
index 0000000000..6407d738da
--- /dev/null
+++ b/lib/trusty/ql-tipc/arch/arm/trusty_dev.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/trusty_dev.h>
+#include <trusty/util.h>
+
+#include "sm_err.h"
+#include "smcall.h"
+
+struct trusty_dev;
+
+#define LOCAL_LOG 0
+
+#ifndef __asmeq
+#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
+#endif
+
+#ifdef NS_ARCH_ARM64
+#define SMC_ARG0 "x0"
+#define SMC_ARG1 "x1"
+#define SMC_ARG2 "x2"
+#define SMC_ARG3 "x3"
+#define SMC_ARCH_EXTENSION ""
+#define SMC_REGISTERS_TRASHED "x4","x5","x6","x7","x8","x9","x10","x11", \
+ "x12","x13","x14","x15","x16","x17"
+#else
+#define SMC_ARG0 "r0"
+#define SMC_ARG1 "r1"
+#define SMC_ARG2 "r2"
+#define SMC_ARG3 "r3"
+#define SMC_ARCH_EXTENSION ".arch_extension sec\n"
+#define SMC_REGISTERS_TRASHED "ip"
+#endif
+
+/*
+ * Execute SMC call into trusty
+ */
+static unsigned long smc(unsigned long r0,
+ unsigned long r1,
+ unsigned long r2,
+ unsigned long r3)
+{
+ register unsigned long _r0 asm(SMC_ARG0) = r0;
+ register unsigned long _r1 asm(SMC_ARG1) = r1;
+ register unsigned long _r2 asm(SMC_ARG2) = r2;
+ register unsigned long _r3 asm(SMC_ARG3) = r3;
+
+ asm volatile(
+ __asmeq("%0", SMC_ARG0)
+ __asmeq("%1", SMC_ARG1)
+ __asmeq("%2", SMC_ARG2)
+ __asmeq("%3", SMC_ARG3)
+ __asmeq("%4", SMC_ARG0)
+ __asmeq("%5", SMC_ARG1)
+ __asmeq("%6", SMC_ARG2)
+ __asmeq("%7", SMC_ARG3)
+ SMC_ARCH_EXTENSION
+ "smc #0" /* switch to secure world */
+ : "=r" (_r0), "=r" (_r1), "=r" (_r2), "=r" (_r3)
+ : "r" (_r0), "r" (_r1), "r" (_r2), "r" (_r3)
+ : SMC_REGISTERS_TRASHED);
+ return _r0;
+}
+
+static int32_t trusty_fast_call32(struct trusty_dev *dev, uint32_t smcnr,
+ uint32_t a0, uint32_t a1, uint32_t a2)
+{
+ trusty_assert(dev);
+ trusty_assert(SMC_IS_FASTCALL(smcnr));
+
+ return smc(smcnr, a0, a1, a2);
+}
+
+static unsigned long trusty_std_call_inner(struct trusty_dev *dev,
+ unsigned long smcnr,
+ unsigned long a0,
+ unsigned long a1,
+ unsigned long a2)
+{
+ unsigned long ret;
+ int retry = 5;
+
+ trusty_debug("%s(0x%lx 0x%lx 0x%lx 0x%lx)\n", __func__, smcnr, a0, a1, a2);
+
+ while (true) {
+ ret = smc(smcnr, a0, a1, a2);
+ while ((int32_t)ret == SM_ERR_FIQ_INTERRUPTED)
+ ret = smc(SMC_SC_RESTART_FIQ, 0, 0, 0);
+ if ((int)ret != SM_ERR_BUSY || !retry)
+ break;
+
+ trusty_debug("%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy, retry\n",
+ __func__, smcnr, a0, a1, a2);
+
+ retry--;
+ }
+
+ return ret;
+}
+
+static unsigned long trusty_std_call_helper(struct trusty_dev *dev,
+ unsigned long smcnr,
+ unsigned long a0,
+ unsigned long a1,
+ unsigned long a2)
+{
+ unsigned long ret;
+ unsigned long irq_state;
+
+ while (true) {
+ trusty_local_irq_disable(&irq_state);
+ ret = trusty_std_call_inner(dev, smcnr, a0, a1, a2);
+ trusty_local_irq_restore(&irq_state);
+
+ if ((int)ret != SM_ERR_BUSY)
+ break;
+
+ trusty_idle(dev);
+ }
+
+ return ret;
+}
+
+static int32_t trusty_std_call32(struct trusty_dev *dev, uint32_t smcnr,
+ uint32_t a0, uint32_t a1, uint32_t a2)
+{
+ int ret;
+
+ trusty_assert(dev);
+ trusty_assert(!SMC_IS_FASTCALL(smcnr));
+
+ if (smcnr != SMC_SC_NOP) {
+ trusty_lock(dev);
+ }
+
+ trusty_debug("%s(0x%x 0x%x 0x%x 0x%x) started\n", __func__,
+ smcnr, a0, a1, a2);
+
+ ret = trusty_std_call_helper(dev, smcnr, a0, a1, a2);
+ while (ret == SM_ERR_INTERRUPTED || ret == SM_ERR_CPU_IDLE) {
+ trusty_debug("%s(0x%x 0x%x 0x%x 0x%x) interrupted\n", __func__,
+ smcnr, a0, a1, a2);
+ if (ret == SM_ERR_CPU_IDLE) {
+ trusty_idle(dev);
+ }
+ ret = trusty_std_call_helper(dev, SMC_SC_RESTART_LAST, 0, 0, 0);
+ }
+
+ trusty_debug("%s(0x%x 0x%x 0x%x 0x%x) returned 0x%x\n",
+ __func__, smcnr, a0, a1, a2, ret);
+
+ if (smcnr != SMC_SC_NOP) {
+ trusty_unlock(dev);
+ }
+
+ return ret;
+}
+
+static int trusty_call32_mem_buf(struct trusty_dev *dev, uint32_t smcnr,
+ struct ns_mem_page_info *page, uint32_t size)
+{
+ trusty_assert(dev);
+ trusty_assert(page);
+
+ if (SMC_IS_FASTCALL(smcnr)) {
+ return trusty_fast_call32(dev, smcnr,
+ (uint32_t)page->attr,
+ (uint32_t)(page->attr >> 32), size);
+ } else {
+ return trusty_std_call32(dev, smcnr,
+ (uint32_t)page->attr,
+ (uint32_t)(page->attr >> 32), size);
+ }
+}
+
+int trusty_dev_init_ipc(struct trusty_dev *dev,
+ struct ns_mem_page_info *buf, uint32_t buf_size)
+{
+ return trusty_call32_mem_buf(dev, SMC_SC_TRUSTY_IPC_CREATE_QL_DEV,
+ buf, buf_size);
+}
+
+int trusty_dev_exec_ipc(struct trusty_dev *dev,
+ struct ns_mem_page_info *buf, uint32_t buf_size)
+{
+ return trusty_call32_mem_buf(dev, SMC_SC_TRUSTY_IPC_HANDLE_QL_DEV_CMD,
+ buf, buf_size);
+}
+
+int trusty_dev_shutdown_ipc(struct trusty_dev *dev,
+ struct ns_mem_page_info *buf, uint32_t buf_size)
+{
+ return trusty_call32_mem_buf(dev, SMC_SC_TRUSTY_IPC_SHUTDOWN_QL_DEV,
+ buf, buf_size);
+}
+
+
+static int trusty_init_api_version(struct trusty_dev *dev)
+{
+ uint32_t api_version;
+
+ api_version = trusty_fast_call32(dev, SMC_FC_API_VERSION,
+ TRUSTY_API_VERSION_CURRENT, 0, 0);
+ if (api_version == SM_ERR_UNDEFINED_SMC)
+ api_version = 0;
+
+ if (api_version > TRUSTY_API_VERSION_CURRENT) {
+ trusty_error("unsupported trusty api version %u > %u\n",
+ api_version, TRUSTY_API_VERSION_CURRENT);
+ return -1;
+ }
+
+ trusty_info("selected trusty api version: %u (requested %u)\n",
+ api_version, TRUSTY_API_VERSION_CURRENT);
+
+ dev->api_version = api_version;
+
+ return 0;
+}
+
+int trusty_dev_init(struct trusty_dev *dev, void *priv_data)
+{
+ trusty_assert(dev);
+
+ dev->priv_data = priv_data;
+ return trusty_init_api_version(dev);
+}
+
+int trusty_dev_shutdown(struct trusty_dev *dev)
+{
+ trusty_assert(dev);
+
+ dev->priv_data = NULL;
+ return 0;
+}
+
diff --git a/lib/trusty/ql-tipc/arch/arm/trusty_mem.c b/lib/trusty/ql-tipc/arch/arm/trusty_mem.c
new file mode 100644
index 0000000000..76abda2d5c
--- /dev/null
+++ b/lib/trusty/ql-tipc/arch/arm/trusty_mem.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/trusty_dev.h>
+#include <trusty/util.h>
+
+/* 48-bit physical address bits 47:12 */
+
+#define NS_PTE_PHYSADDR_SHIFT 12
+#define NS_PTE_PHYSADDR(pte) ((pte) & 0xFFFFFFFFF000ULL)
+
+/* Access permissions bits 7:6
+ * EL0 EL1
+ * 00 None RW
+ * 01 RW RW
+ * 10 None RO
+ * 11 RO RO
+ */
+#define NS_PTE_AP_SHIFT 6
+#define NS_PTE_AP_MASK (0x3 << NS_PTE_AP_SHIFT)
+
+/* Memory type and cache attributes bits 55:48 */
+#define NS_PTE_MAIR_SHIFT 48
+#define NS_PTE_MAIR_MASK (0x00FFULL << NS_PTE_MAIR_SHIFT)
+
+#define NS_PTE_MAIR_INNER_SHIFT 48
+#define NS_PTE_MAIR_INNER_MASK (0x000FULL << NS_PTE_MAIR_INNER_SHIFT)
+
+#define NS_PTE_MAIR_OUTER_SHIFT 52
+#define NS_PTE_MAIR_OUTER_MASK (0x000FULL << NS_PTE_MAIR_OUTER_SHIFT)
+
+/* Normal memory */
+#define NS_MAIR_NORMAL_CACHED_WB_RWA 0xFF /* inner and outer write back read/write allocate */
+#define NS_MAIR_NORMAL_CACHED_WT_RA 0xAA /* inner and outer write through read allocate */
+#define NS_MAIR_NORMAL_CACHED_WB_RA 0xEE /* inner and outer write back, read allocate */
+#define NS_MAIR_NORMAL_UNCACHED 0x44 /* uncached */
+
+/* Device memory */
+#define NS_MAIR_DEVICE_STRONGLY_ORDERED 0x00 /* nGnRnE (strongly ordered) */
+#define NS_MAIR_DEVICE 0x04 /* nGnRE (device) */
+#define NS_MAIR_DEVICE_GRE 0x0C /* GRE */
+
+/* shareable attributes bits 9:8 */
+#define NS_PTE_SHAREABLE_SHIFT 8
+
+#define NS_NON_SHAREABLE 0x0
+#define NS_OUTER_SHAREABLE 0x2
+#define NS_INNER_SHAREABLE 0x3
+
+typedef uintptr_t addr_t;
+typedef uintptr_t vaddr_t;
+typedef uintptr_t paddr_t;
+
+#if NS_ARCH_ARM64
+
+#define PAR_F (0x1 << 0)
+
+/*
+ * ARM64
+ */
+static void arm64_write_ATS1E1W(uint64_t vaddr)
+{
+ __asm__ volatile("at S1E1W, %0" :: "r" (vaddr));
+ __asm__ volatile("isb" ::: "memory");
+}
+
+static uint64_t arm64_read_par64(void)
+{
+ uint64_t _val;
+ __asm__ volatile("mrs %0, par_el1" : "=r" (_val));
+ return _val;
+}
+
+
+static uint64_t va2par(vaddr_t va)
+{
+ uint64_t par;
+ unsigned long irq_state;
+
+ trusty_local_irq_disable(&irq_state);
+ arm64_write_ATS1E1W(va);
+ par = arm64_read_par64();
+ trusty_local_irq_restore(&irq_state);
+
+ return par;
+}
+
+static uint64_t par2attr(uint64_t par)
+{
+ uint64_t attr;
+
+ /* set phys address */
+ attr = NS_PTE_PHYSADDR(par);
+
+ /* cache attributes */
+ attr |= ((par >> 56) & 0xFF) << NS_PTE_MAIR_SHIFT;
+
+ /* shareable attributes */
+ attr |= ((par >> 7) & 0x03) << NS_PTE_SHAREABLE_SHIFT;
+
+ /* the memory is writable and accessible so leave AP field 0 */
+ attr |= 0x0 << NS_PTE_AP_SHIFT;
+
+ return attr;
+}
+
+#else
+
+#define PAR_F (0x1 << 0)
+#define PAR_SS (0x1 << 1)
+#define PAR_SH (0x1 << 7)
+#define PAR_NOS (0x1 << 10)
+#define PAR_LPAE (0x1 << 11)
+
+/*
+ * ARM32
+ */
+static void arm_write_ATS1CPW(uint64_t vaddr)
+{
+ __asm__ volatile(
+ "mcr p15, 0, %0, c7, c8, 1 \n"
+ : : "r"(vaddr)
+ );
+}
+
+static uint64_t arm_read_par64(void)
+{
+ uint32_t lower, higher;
+
+ __asm__ volatile(
+ "mrc p15, 0, %0, c7, c4, 0 \n"
+ "tst %0, #(1 << 11) @ LPAE / long desc format\n"
+ "moveq %1, #0 \n"
+ "mrrcne p15, 0, %0, %1, c7 \n"
+ :"=r"(lower), "=r"(higher) : :
+ );
+
+ return ((uint64_t)higher << 32) | lower;
+}
+
+
+static uint8_t ish_to_mair[8] = {
+ 0x04, /* 0b000 Non cacheble */
+ 0x00, /* 0b001 Strongly ordered */
+ 0xF0, /* 0b010 reserved */
+ 0x04, /* 0b011 device */
+ 0xF0, /* 0b100 reserved */
+ 0x0F, /* 0b101 write back - write allocate */
+ 0x0A, /* 0b110 write through */
+ 0x0E, /* 0b111 write back - no write allocate */
+};
+
+static uint8_t osh_to_mair[4] = {
+ 0x00, /* 0b00 Non-cacheable */
+ 0x0F, /* 0b01 Write-back, Write-allocate */
+ 0x0A, /* 0b10 Write-through, no Write-allocate */
+ 0x0E, /* 0b11 Write-back, no Write-allocate */
+};
+
+static uint64_t par2attr(uint64_t par)
+{
+ uint64_t attr;
+
+ if (par & PAR_LPAE) {
+ /* set phys address */
+ attr = NS_PTE_PHYSADDR(par);
+
+ /* cache attributes */
+ attr |= ((par >> 56) & 0xFF) << NS_PTE_MAIR_SHIFT;
+
+ /* shareable attributes */
+ attr |= ((par >> 7) & 0x03) << NS_PTE_SHAREABLE_SHIFT;
+
+ } else {
+
+ /* set phys address */
+ trusty_assert((par & PAR_SS) == 0); /* super section not supported */
+ attr = NS_PTE_PHYSADDR(par);
+
+ /* cache attributes */
+ uint64_t inner = ((uint64_t)ish_to_mair[(par >> 4) & 0x7]) << NS_PTE_MAIR_INNER_SHIFT;
+ uint64_t outer = ((uint64_t)osh_to_mair[(par >> 2) & 0x3]) << NS_PTE_MAIR_OUTER_SHIFT;
+ uint64_t cache_attributes = (outer << 4) | inner;
+
+ /* Trusty does not support any kind of device memory, so we will force
+ * cache attributes to be NORMAL UNCACHED on the Trusty side.
+ */
+ if (cache_attributes == NS_MAIR_DEVICE_STRONGLY_ORDERED) {
+ attr |= ((uint64_t)NS_MAIR_NORMAL_UNCACHED << NS_PTE_MAIR_SHIFT);
+ } else {
+ attr |= inner;
+ attr |= outer;
+ }
+
+ /* shareable attributes */
+ if (par & PAR_SH) {
+ /* how to handle NOS bit ? */
+ attr |= ((uint64_t)NS_INNER_SHAREABLE) << NS_PTE_SHAREABLE_SHIFT;
+ } else {
+ attr |= ((uint64_t)NS_NON_SHAREABLE) << NS_PTE_SHAREABLE_SHIFT;
+ }
+ }
+
+ /* the memory is writable and accessible so leave AP field 0 */
+ attr |= 0x0 << NS_PTE_AP_SHIFT;
+
+ return attr;
+}
+
+static uint64_t va2par(vaddr_t va)
+{
+ uint64_t par;
+ unsigned long irq_state;
+
+ trusty_local_irq_disable(&irq_state);
+ arm_write_ATS1CPW(va); /* need to call the right one */
+ par = arm_read_par64();
+ trusty_local_irq_restore(&irq_state);
+
+ return par;
+}
+
+#endif /* ARM64 */
+
+
+int trusty_encode_page_info(struct ns_mem_page_info *inf, void *va)
+{
+ uint64_t par = va2par((vaddr_t)va);
+
+ if (par & PAR_F) {
+ return -1;
+ }
+
+ inf->attr = par2attr(par);
+
+ return 0;
+}
+
diff --git a/lib/trusty/ql-tipc/avb.c b/lib/trusty/ql-tipc/avb.c
new file mode 100644
index 0000000000..ebbb38ff20
--- /dev/null
+++ b/lib/trusty/ql-tipc/avb.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/avb.h>
+#include <trusty/rpmb.h>
+#include <trusty/trusty_ipc.h>
+#include <trusty/util.h>
+
+#define LOCAL_LOG 0
+
+static bool initialized;
+static int avb_tipc_version = 1;
+static struct trusty_ipc_chan avb_chan;
+
+static int avb_send_request(struct avb_message *msg, void *req, size_t req_len)
+{
+ struct trusty_ipc_iovec req_iovs[2] = {
+ { .base = msg, .len = sizeof(*msg) },
+ { .base = req, .len = req_len },
+ };
+
+ return trusty_ipc_send(&avb_chan, req_iovs, req ? 2 : 1, true);
+}
+
+static int avb_read_response(struct avb_message *msg, uint32_t cmd, void *resp,
+ size_t resp_len)
+{
+ int rc;
+ struct trusty_ipc_iovec resp_iovs[2] = {
+ { .base = msg, .len = sizeof(*msg) },
+ { .base = resp, .len = resp_len },
+ };
+
+ rc = trusty_ipc_recv(&avb_chan, resp_iovs, resp ? 2 : 1, true);
+ if (rc < 0) {
+ trusty_error("failed (%d) to recv response\n", rc);
+ return rc;
+ }
+ if (msg->cmd != (cmd | AVB_RESP_BIT)) {
+ trusty_error("malformed response\n");
+ return TRUSTY_ERR_GENERIC;
+ }
+ /* return payload size */
+ return rc - sizeof(*msg);
+}
+
+/*
+ * Convenience function to send a request to the AVB service and read the
+ * response.
+ *
+ * @cmd: the command
+ * @req: the request buffer
+ * @req_size: size of the request buffer
+ * @resp: the response buffer
+ * @resp_size_p: pointer to the size of the response buffer. changed to the
+ actual size of the response read from the secure side
+ * @handle_rpmb: true if the request is expected to invoke RPMB callbacks
+ */
+static int avb_do_tipc(uint32_t cmd, void *req, uint32_t req_size, void *resp,
+ uint32_t *resp_size_p, bool handle_rpmb)
+{
+ int rc;
+ struct avb_message msg = { .cmd = cmd };
+
+ if (!initialized && cmd != AVB_GET_VERSION) {
+ trusty_error("%s: AVB TIPC client not initialized\n", __func__);
+ return TRUSTY_ERR_GENERIC;
+ }
+
+ rc = avb_send_request(&msg, req, req_size);
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to send AVB request\n", __func__, rc);
+ return rc;
+ }
+
+ if (handle_rpmb) {
+ /* handle any incoming RPMB requests */
+ rc = rpmb_storage_proxy_poll();
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to get RPMB requests\n", __func__,
+ rc);
+ return rc;
+ }
+ }
+
+ uint32_t resp_size = resp_size_p ? *resp_size_p : 0;
+ rc = avb_read_response(&msg, cmd, resp, resp_size);
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to read AVB response\n", __func__, rc);
+ return rc;
+ }
+ /* change response size to actual response size */
+ if (resp_size_p && rc != *resp_size_p) {
+ *resp_size_p = rc;
+ }
+ if (msg.result != AVB_ERROR_NONE) {
+ trusty_error("%s: AVB service returned error (%d)\n", __func__,
+ msg.result);
+ return TRUSTY_ERR_GENERIC;
+ }
+ return TRUSTY_ERR_NONE;
+}
+
+static int avb_get_version(uint32_t *version)
+{
+ int rc;
+ struct avb_get_version_resp resp;
+ uint32_t resp_size = sizeof(resp);
+
+ rc = avb_do_tipc(AVB_GET_VERSION, NULL, 0, &resp, &resp_size, false);
+
+ *version = resp.version;
+ return rc;
+}
+
+
+int avb_tipc_init(struct trusty_ipc_dev *dev)
+{
+ int rc;
+ uint32_t version = 0;
+
+ trusty_assert(dev);
+ trusty_assert(!initialized);
+
+ trusty_ipc_chan_init(&avb_chan, dev);
+ trusty_debug("Connecting to AVB service\n");
+
+ /* connect to AVB service and wait for connect to complete */
+ rc = trusty_ipc_connect(&avb_chan, AVB_PORT, true);
+ if (rc < 0) {
+ trusty_error("failed (%d) to connect to '%s'\n", rc, AVB_PORT);
+ return rc;
+ }
+
+ /* check for version mismatch */
+ rc = avb_get_version(&version);
+ if (rc != 0) {
+ trusty_error("Error getting version");
+ return TRUSTY_ERR_GENERIC;
+ }
+ if (version != avb_tipc_version) {
+ trusty_error("AVB TIPC version mismatch. Expected %u, received %u\n",
+ avb_tipc_version, version);
+ return TRUSTY_ERR_GENERIC;
+ }
+
+ /* mark as initialized */
+ initialized = true;
+
+ return TRUSTY_ERR_NONE;
+}
+
+void avb_tipc_shutdown(struct trusty_ipc_dev *dev)
+{
+ if (!initialized)
+ return; /* nothing to do */
+
+ /* close channel */
+ trusty_ipc_close(&avb_chan);
+
+ initialized = false;
+}
+
+int trusty_read_rollback_index(uint32_t slot, uint64_t *value)
+{
+ int rc;
+ struct avb_rollback_req req = { .slot = slot, .value = 0 };
+ struct avb_rollback_resp resp;
+ uint32_t resp_size = sizeof(resp);
+
+ rc = avb_do_tipc(READ_ROLLBACK_INDEX, &req, sizeof(req), &resp,
+ &resp_size, true);
+
+ *value = resp.value;
+ return rc;
+}
+
+int trusty_write_rollback_index(uint32_t slot, uint64_t value)
+{
+ int rc;
+ struct avb_rollback_req req = { .slot = slot, .value = value };
+ struct avb_rollback_resp resp;
+ uint32_t resp_size = sizeof(resp);
+
+ rc = avb_do_tipc(WRITE_ROLLBACK_INDEX, &req, sizeof(req), &resp,
+ &resp_size, true);
+ return rc;
+}
+
+int trusty_read_permanent_attributes(uint8_t *attributes, uint32_t size)
+{
+ uint8_t resp_buf[AVB_MAX_BUFFER_LENGTH];
+ uint32_t resp_size = AVB_MAX_BUFFER_LENGTH;
+ int rc = avb_do_tipc(READ_PERMANENT_ATTRIBUTES, NULL, 0, resp_buf,
+ &resp_size, true);
+ if (rc != 0) {
+ return rc;
+ }
+ /* ensure caller passed size matches size returned by Trusty */
+ if (size != resp_size) {
+ return TRUSTY_ERR_INVALID_ARGS;
+ }
+ trusty_memcpy(attributes, resp_buf, resp_size);
+ return rc;
+}
+
+int trusty_write_permanent_attributes(uint8_t *attributes, uint32_t size)
+{
+ return avb_do_tipc(WRITE_PERMANENT_ATTRIBUTES, attributes, size, NULL, NULL,
+ true);
+}
+
+int trusty_read_lock_state(uint8_t *lock_state)
+{
+ uint32_t resp_size = sizeof(*lock_state);
+ return avb_do_tipc(READ_LOCK_STATE, NULL, 0, lock_state,
+ &resp_size, true);
+}
+
+int trusty_write_lock_state(uint8_t lock_state)
+{
+ return avb_do_tipc(WRITE_LOCK_STATE, &lock_state, sizeof(lock_state), NULL,
+ NULL, true);
+}
+
+int trusty_lock_boot_state(void)
+{
+ return avb_do_tipc(LOCK_BOOT_STATE, NULL, 0, NULL, NULL, false);
+}
diff --git a/lib/trusty/ql-tipc/ipc.c b/lib/trusty/ql-tipc/ipc.c
new file mode 100644
index 0000000000..95c0ee605c
--- /dev/null
+++ b/lib/trusty/ql-tipc/ipc.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/trusty_ipc.h>
+#include <trusty/util.h>
+
+#define LOCAL_LOG 0
+
+static int sync_ipc_on_connect_complete(struct trusty_ipc_chan *chan)
+{
+ trusty_assert(chan);
+
+ chan->complete = 1;
+ return TRUSTY_EVENT_HANDLED;
+}
+
+static int sync_ipc_on_message(struct trusty_ipc_chan *chan)
+{
+ trusty_assert(chan);
+
+ chan->complete = 1;
+ return TRUSTY_EVENT_HANDLED;
+}
+
+static int sync_ipc_on_disconnect(struct trusty_ipc_chan *chan)
+{
+ trusty_assert(chan);
+
+ chan->complete = TRUSTY_ERR_CHANNEL_CLOSED;
+ return TRUSTY_EVENT_HANDLED;
+}
+
+static int wait_for_complete(struct trusty_ipc_chan *chan)
+{
+ int rc;
+
+ chan->complete = 0;
+ for (;;) {
+ rc = trusty_ipc_poll_for_event(chan);
+ if (rc < 0)
+ return rc;
+
+ if (chan->complete)
+ break;
+
+ trusty_ipc_dev_idle(chan->dev);
+ }
+
+ return chan->complete;
+}
+
+static int wait_for_connect(struct trusty_ipc_chan *chan)
+{
+ trusty_debug("%s: chan %x: waiting for connect\n", __func__,
+ (int)chan->handle);
+ return wait_for_complete(chan);
+}
+
+static int wait_for_send(struct trusty_ipc_chan *chan)
+{
+ trusty_debug("%s: chan %d: waiting for send\n", __func__, chan->handle);
+ return wait_for_complete(chan);
+}
+
+static int wait_for_reply(struct trusty_ipc_chan *chan)
+{
+ trusty_debug("%s: chan %d: waiting for reply\n", __func__, chan->handle);
+ return wait_for_complete(chan);
+}
+
+static struct trusty_ipc_ops sync_ipc_ops = {
+ .on_connect_complete = sync_ipc_on_connect_complete,
+ .on_message = sync_ipc_on_message,
+ .on_disconnect = sync_ipc_on_disconnect,
+};
+
+void trusty_ipc_chan_init(struct trusty_ipc_chan *chan,
+ struct trusty_ipc_dev *dev)
+{
+ trusty_assert(chan);
+ trusty_assert(dev);
+
+ trusty_memset(chan, 0, sizeof(*chan));
+
+ chan->handle = INVALID_IPC_HANDLE;
+ chan->dev = dev;
+ chan->ops = &sync_ipc_ops;
+ chan->ops_ctx = chan;
+}
+
+int trusty_ipc_connect(struct trusty_ipc_chan *chan, const char *port,
+ bool wait)
+{
+ int rc;
+
+ trusty_assert(chan);
+ trusty_assert(chan->dev);
+ trusty_assert(chan->handle == INVALID_IPC_HANDLE);
+ trusty_assert(port);
+
+ rc = trusty_ipc_dev_connect(chan->dev, port, (uint64_t)(uintptr_t)chan);
+ if (rc < 0) {
+ trusty_error("%s: init connection failed (%d)\n", __func__, rc);
+ return rc;
+ }
+ chan->handle = (handle_t)rc;
+ trusty_debug("chan->handle: %x\n", (int)chan->handle);
+
+ /* got valid channel */
+ if (wait) {
+ rc = wait_for_connect(chan);
+ if (rc < 0) {
+ trusty_error("%s: wait for connect failed (%d)\n", __func__, rc);
+ trusty_ipc_close(chan);
+ }
+ }
+
+ return rc;
+}
+
+int trusty_ipc_close(struct trusty_ipc_chan *chan)
+{
+ int rc;
+
+ trusty_assert(chan);
+
+ rc = trusty_ipc_dev_close(chan->dev, chan->handle);
+ chan->handle = INVALID_IPC_HANDLE;
+
+ return rc;
+}
+
+int trusty_ipc_send(struct trusty_ipc_chan *chan,
+ const struct trusty_ipc_iovec *iovs, size_t iovs_cnt,
+ bool wait)
+{
+ int rc;
+
+ trusty_assert(chan);
+ trusty_assert(chan->dev);
+ trusty_assert(chan->handle);
+
+Again:
+ rc = trusty_ipc_dev_send(chan->dev, chan->handle, iovs, iovs_cnt);
+ if (rc == TRUSTY_ERR_SEND_BLOCKED) {
+ if (wait) {
+ rc = wait_for_send(chan);
+ if (rc < 0) {
+ trusty_error("%s: wait to send failed (%d)\n", __func__, rc);
+ return rc;
+ }
+ goto Again;
+ }
+ }
+ return rc;
+}
+
+int trusty_ipc_recv(struct trusty_ipc_chan *chan,
+ const struct trusty_ipc_iovec *iovs, size_t iovs_cnt,
+ bool wait)
+{
+ int rc;
+ trusty_assert(chan);
+ trusty_assert(chan->dev);
+ trusty_assert(chan->handle);
+
+Again:
+ rc = trusty_ipc_dev_recv(chan->dev, chan->handle, iovs, iovs_cnt);
+ if (rc == TRUSTY_ERR_NO_MSG) {
+ if (wait) {
+ rc = wait_for_reply(chan);
+ if (rc < 0) {
+ trusty_error("%s: wait to reply failed (%d)\n", __func__, rc);
+ return rc;
+ }
+ goto Again;
+ }
+ }
+
+ return rc;
+}
+
+int trusty_ipc_poll_for_event(struct trusty_ipc_chan *chan)
+{
+ int rc;
+ struct trusty_ipc_event evt;
+ trusty_assert(chan && chan->ops);
+
+ rc = trusty_ipc_dev_get_event(chan->dev, chan->handle, &evt);
+ if (rc) {
+ trusty_error("%s: get event failed (%d)\n", __func__, rc);
+ return rc;
+ }
+
+ /* check if we have an event */
+ if (!evt.event) {
+ trusty_debug("%s: no event\n", __func__);
+ return TRUSTY_EVENT_NONE;
+ }
+
+ /* check if we have raw event handler */
+ if (chan->ops->on_raw_event) {
+ /* invoke it first */
+ rc = chan->ops->on_raw_event(chan, &evt);
+ if (rc < 0) {
+ trusty_error("%s: chan %d: raw event cb returned (%d)\n", __func__,
+ chan->handle, rc);
+ return rc;
+ }
+ if (rc > 0)
+ return rc; /* handled */
+ }
+
+ if (evt.event & IPC_HANDLE_POLL_ERROR) {
+ /* something is very wrong */
+ trusty_error("%s: chan %d: chan in error state\n", __func__,
+ chan->handle);
+ return TRUSTY_ERR_GENERIC;
+ }
+
+ /* send unblocked should be handled first as it is edge truggered event */
+ if (evt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
+ if (chan->ops->on_send_unblocked) {
+ rc = chan->ops->on_send_unblocked(chan);
+ if (rc < 0) {
+ trusty_error("%s: chan %d: send unblocked cb returned (%d)\n",
+ __func__, chan->handle, rc);
+ return rc;
+ }
+ if (rc > 0)
+ return rc; /* handled */
+ }
+ }
+
+ /* check for connection complete */
+ if (evt.event & IPC_HANDLE_POLL_READY) {
+ if (chan->ops->on_connect_complete) {
+ rc = chan->ops->on_connect_complete(chan);
+ if (rc < 0) {
+ trusty_error("%s: chan %d: ready cb returned (%d)\n", __func__,
+ chan->handle, rc);
+ return rc;
+ }
+ if (rc > 0)
+ return rc; /* handled */
+ }
+ }
+
+ /* check for incomming messages */
+ if (evt.event & IPC_HANDLE_POLL_MSG) {
+ if (chan->ops->on_message) {
+ rc = chan->ops->on_message(chan);
+ if (rc < 0) {
+ trusty_error("%s: chan %d: msg cb returned (%d)\n", __func__,
+ chan->handle, rc);
+ return rc;
+ }
+ if (rc > 0)
+ return rc;
+ }
+ }
+
+ /* check for hangups */
+ if (evt.event & IPC_HANDLE_POLL_HUP) {
+ if (chan->ops->on_disconnect) {
+ rc = chan->ops->on_disconnect(chan);
+ if (rc < 0) {
+ trusty_error("%s: chan %d: hup cb returned (%d)\n", __func__,
+ chan->handle, rc);
+ return rc;
+ }
+ if (rc > 0)
+ return rc;
+ }
+ }
+
+ return TRUSTY_ERR_NONE;
+}
diff --git a/lib/trusty/ql-tipc/ipc_dev.c b/lib/trusty/ql-tipc/ipc_dev.c
new file mode 100644
index 0000000000..5924d44891
--- /dev/null
+++ b/lib/trusty/ql-tipc/ipc_dev.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/trusty_dev.h>
+#include <trusty/trusty_ipc.h>
+#include <trusty/util.h>
+
+#define NS_PTE_PHYSADDR(pte) ((pte) & 0xFFFFFFFFF000ULL)
+
+#define QL_TIPC_DEV_RESP 0x8000
+#define QL_TIPC_DEV_CONNECT 0x1
+#define QL_TIPC_DEV_GET_EVENT 0x2
+#define QL_TIPC_DEV_SEND 0x3
+#define QL_TIPC_DEV_RECV 0x4
+#define QL_TIPC_DEV_DISCONNECT 0x5
+
+#define LOCAL_LOG 0
+
+struct trusty_ipc_cmd_hdr {
+ uint16_t opcode;
+ uint16_t flags;
+ uint32_t status;
+ uint32_t handle;
+ uint32_t payload_len;
+ uint8_t payload[0];
+};
+
+struct trusty_ipc_wait_req {
+ uint64_t reserved;
+};
+
+struct trusty_ipc_connect_req {
+ uint64_t cookie;
+ uint64_t reserved;
+ uint8_t name[0];
+};
+
+static size_t iovec_size(const struct trusty_ipc_iovec *iovs, size_t iovs_cnt)
+{
+ size_t i;
+ size_t cb = 0;
+
+ trusty_assert(iovs);
+
+ for (i = 0; i < iovs_cnt; i++) {
+ cb += iovs[i].len;
+ }
+
+ return cb;
+}
+
+static size_t iovec_to_buf(void *buf, size_t buf_len,
+ const struct trusty_ipc_iovec *iovs, size_t iovs_cnt)
+{
+ size_t i;
+ size_t buf_pos = 0;
+
+ trusty_assert(iovs);
+
+ for (i = 0; i < iovs_cnt; i++) {
+ size_t to_copy = (size_t)iovs[i].len;
+
+ if (!to_copy)
+ continue;
+
+ if (to_copy > buf_len)
+ to_copy = buf_len;
+
+ trusty_memcpy((uint8_t *)buf + buf_pos, iovs[i].base, to_copy);
+
+ buf_pos += to_copy;
+ buf_len -= to_copy;
+
+ if (buf_len == 0)
+ break;
+ }
+
+ return buf_pos;
+}
+
+static size_t buf_to_iovec(const struct trusty_ipc_iovec *iovs, size_t iovs_cnt,
+ const void *buf, size_t buf_len)
+{
+ size_t i;
+ size_t copied = 0;
+ const uint8_t *buf_ptr = buf;
+
+ trusty_assert(buf_ptr);
+ trusty_assert(iovs);
+
+ if (iovs_cnt == 0 || buf_len == 0)
+ return 0;
+
+ for (i = 0; i < iovs_cnt; i++) {
+ size_t to_copy = buf_len;
+
+ if (to_copy > iovs[i].len)
+ to_copy = iovs[i].len;
+
+ if (!to_copy)
+ continue;
+
+ trusty_memcpy(iovs[i].base, buf_ptr, to_copy);
+
+ copied += to_copy;
+ buf_ptr += to_copy;
+ buf_len -= to_copy;
+
+ if (buf_len == 0)
+ break;
+ }
+
+ return copied;
+}
+
+static int check_response(struct trusty_ipc_dev *dev,
+ volatile struct trusty_ipc_cmd_hdr *hdr, uint16_t cmd)
+{
+ if (hdr->opcode != (cmd | QL_TIPC_DEV_RESP)) {
+ /* malformed response */
+ trusty_error("%s: malformed response cmd: 0x%x\n",
+ __func__, hdr->opcode);
+ return TRUSTY_ERR_SECOS_ERR;
+ }
+
+ if (hdr->status) {
+ /* secure OS responded with error: TODO need error code */
+ trusty_error("%s: cmd 0x%x: status = %d\n",
+ __func__, hdr->opcode, hdr->status);
+ return TRUSTY_ERR_SECOS_ERR;
+ }
+
+ return TRUSTY_ERR_NONE;
+}
+
+int trusty_ipc_dev_create(struct trusty_ipc_dev **idev,
+ struct trusty_dev *tdev,
+ size_t buf_size)
+{
+ int rc;
+ struct trusty_ipc_dev *dev;
+
+ trusty_assert(idev);
+
+ trusty_debug("%s: Create new Trusty IPC device (%zu)\n", __func__, buf_size);
+
+ /* allocate device context */
+ dev = trusty_calloc(1, sizeof(*dev));
+ if (!dev) {
+ trusty_error("%s: failed to allocate Trusty IPC device\n", __func__);
+ return TRUSTY_ERR_NO_MEMORY;
+ }
+ dev->tdev = tdev;
+
+ /* allocate shared buffer */
+ dev->buf_size = buf_size;
+ dev->buf_vaddr = trusty_membuf_alloc(&dev->buf_ns, buf_size);
+ if (!dev->buf_vaddr) {
+ trusty_error("%s: failed to allocate shared memory\n", __func__);
+ rc = TRUSTY_ERR_NO_MEMORY;
+ goto err_alloc_membuf;
+ }
+
+ /* call secure OS to register shared buffer */
+ rc = trusty_dev_init_ipc(dev->tdev, &dev->buf_ns, dev->buf_size);
+ if (rc != 0) {
+ trusty_error("%s: failed (%d) to create Trusty IPC device\n",
+ __func__, rc);
+ rc = TRUSTY_ERR_SECOS_ERR;
+ goto err_create_sec_dev;
+ }
+
+ trusty_debug("%s: new Trusty IPC device (%p)\n", __func__, dev);
+
+ *idev = dev;
+ return TRUSTY_ERR_NONE;
+
+err_create_sec_dev:
+err_alloc_membuf:
+ trusty_membuf_free(dev->buf_vaddr);
+ trusty_free(dev);
+ return rc;
+}
+
+void trusty_ipc_dev_shutdown(struct trusty_ipc_dev *dev)
+{
+ int rc;
+ trusty_assert(dev);
+
+ trusty_debug("%s: shutting down Trusty IPC device (%p)\n", __func__, dev);
+
+ /* shutdown Trusty IPC device */
+ rc = trusty_dev_shutdown_ipc(dev->tdev, &dev->buf_ns, dev->buf_size);
+ trusty_assert(!rc);
+ if (rc != 0) {
+ trusty_error("%s: failed (%d) to shutdown Trusty IPC device\n",
+ __func__, rc);
+ }
+ trusty_membuf_free(dev->buf_vaddr);
+ trusty_free(dev);
+}
+
+int trusty_ipc_dev_connect(struct trusty_ipc_dev *dev, const char *port,
+ uint64_t cookie)
+{
+ int rc;
+ size_t port_len;
+ volatile struct trusty_ipc_cmd_hdr *cmd;
+ struct trusty_ipc_connect_req *req;
+
+ trusty_assert(dev);
+ trusty_assert(port);
+
+ trusty_debug("%s: connecting to '%s'\n", __func__, port);
+
+ /* check port name length */
+ port_len = trusty_strlen(port) + 1;
+ if (port_len > (dev->buf_size - sizeof(*cmd) + sizeof(*req))) {
+ /* it would not fit into buffer */
+ trusty_error("%s: port name is too long (%zu)\n", __func__, port_len);
+ return TRUSTY_ERR_INVALID_ARGS;
+ }
+
+ /* prepare command */
+ cmd = dev->buf_vaddr;
+ trusty_memset((void *)cmd, 0, sizeof(*cmd));
+ cmd->opcode = QL_TIPC_DEV_CONNECT;
+
+ /* prepare payload */
+ req = (struct trusty_ipc_connect_req *)cmd->payload;
+ trusty_memset((void *)req, 0, sizeof(*req));
+ req->cookie = cookie;
+ trusty_strcpy((char *)req->name, port);
+ cmd->payload_len = sizeof(*req) + port_len;
+
+ /* call secure os */
+ rc = trusty_dev_exec_ipc(dev->tdev,
+ &dev->buf_ns, sizeof(*cmd) + cmd->payload_len);
+ if (rc) {
+ /* secure OS returned an error */
+ trusty_error("%s: secure OS returned (%d)\n", __func__, rc);
+ return TRUSTY_ERR_SECOS_ERR;
+ }
+
+ rc = check_response(dev, cmd, QL_TIPC_DEV_CONNECT);
+ if (rc) {
+ trusty_error("%s: connect cmd failed (%d)\n", __func__, rc);
+ return rc;
+ }
+
+ /* success */
+ return cmd->handle;
+}
+
+int trusty_ipc_dev_close(struct trusty_ipc_dev *dev, handle_t handle)
+{
+ int rc;
+ volatile struct trusty_ipc_cmd_hdr *cmd;
+
+ trusty_assert(dev);
+
+ trusty_debug("%s: chan %d: closing\n", __func__, handle);
+
+ /* prepare command */
+ cmd = dev->buf_vaddr;
+ trusty_memset((void *)cmd, 0, sizeof(*cmd));
+ cmd->opcode = QL_TIPC_DEV_DISCONNECT;
+ cmd->handle = handle;
+ /* no payload */
+
+ /* call into secure os */
+ rc = trusty_dev_exec_ipc(dev->tdev,
+ &dev->buf_ns, sizeof(*cmd) + cmd->payload_len);
+ if (rc) {
+ trusty_error("%s: secure OS returned (%d)\n", __func__, rc);
+ return TRUSTY_ERR_SECOS_ERR;
+ }
+
+ rc = check_response(dev, cmd, QL_TIPC_DEV_DISCONNECT);
+ if (rc) {
+ trusty_error("%s: disconnect cmd failed (%d)\n", __func__, rc);
+ return rc;
+ }
+
+ trusty_debug("%s: chan %d: closed\n", __func__, handle);
+
+ return TRUSTY_ERR_NONE;
+}
+
+int trusty_ipc_dev_get_event(struct trusty_ipc_dev *dev, handle_t chan,
+ struct trusty_ipc_event *event)
+{
+ int rc;
+ volatile struct trusty_ipc_cmd_hdr *cmd;
+
+ trusty_assert(dev);
+ trusty_assert(event);
+
+ /* prepare command */
+ cmd = dev->buf_vaddr;
+ trusty_memset((void *)cmd, 0, sizeof(*cmd));
+ cmd->opcode = QL_TIPC_DEV_GET_EVENT;
+ cmd->handle = chan;
+
+ /* prepare payload */
+ trusty_memset((void *)cmd->payload, 0, sizeof(struct trusty_ipc_wait_req));
+ cmd->payload_len = sizeof(struct trusty_ipc_wait_req);
+
+ /* call into secure os */
+ rc = trusty_dev_exec_ipc(dev->tdev,
+ &dev->buf_ns, sizeof(*cmd) + cmd->payload_len);
+ if (rc) {
+ trusty_error("%s: secure OS returned (%d)\n", __func__, rc);
+ return TRUSTY_ERR_SECOS_ERR;
+ }
+
+ rc = check_response(dev, cmd, QL_TIPC_DEV_GET_EVENT);
+ if (rc) {
+ trusty_error("%s: get event cmd failed (%d)\n", __func__, rc);
+ return rc;
+ }
+
+ if ((size_t)cmd->payload_len < sizeof(*event)) {
+ trusty_error("%s: invalid response length (%zd)\n",
+ __func__, (size_t)cmd->payload_len);
+ return TRUSTY_ERR_SECOS_ERR;
+ }
+
+ /* copy out event */
+ trusty_memcpy(event, (const void *)cmd->payload, sizeof(*event));
+ return TRUSTY_ERR_NONE;
+}
+
+int trusty_ipc_dev_send(struct trusty_ipc_dev *dev, handle_t chan,
+ const struct trusty_ipc_iovec *iovs, size_t iovs_cnt)
+{
+ int rc;
+ size_t msg_size;
+ volatile struct trusty_ipc_cmd_hdr *cmd;
+
+ trusty_assert(dev);
+ /* calc message length */
+ msg_size = iovec_size(iovs, iovs_cnt);
+ if (msg_size > dev->buf_size - sizeof(*cmd)) {
+ /* msg is too big to fit provided buffer */
+ trusty_error("%s: chan %d: msg is too long (%zu)\n", __func__,
+ chan, msg_size);
+ return TRUSTY_ERR_MSG_TOO_BIG;
+ }
+
+ /* prepare command */
+ cmd = dev->buf_vaddr;
+ trusty_memset((void *)cmd, 0, sizeof(*cmd));
+ cmd->opcode = QL_TIPC_DEV_SEND;
+ cmd->handle = chan;
+
+ /* copy in message data */
+ cmd->payload_len = (uint32_t)msg_size;
+ msg_size = iovec_to_buf(dev->buf_vaddr + sizeof(*cmd), dev->buf_size - sizeof(*cmd),
+ iovs, iovs_cnt);
+ trusty_assert(msg_size == (size_t)cmd->payload_len);
+
+ /* call into secure os */
+ rc = trusty_dev_exec_ipc(dev->tdev,
+ &dev->buf_ns, sizeof(*cmd) + cmd->payload_len);
+ if (rc < 0) {
+ trusty_error("%s: secure OS returned (%d)\n", __func__, rc);
+ return TRUSTY_ERR_SECOS_ERR;
+ }
+
+ rc = check_response(dev, cmd, QL_TIPC_DEV_SEND);
+ if (rc) {
+ trusty_error("%s: send msg failed (%d)\n", __func__, rc);
+ }
+
+ return rc;
+}
+
+
+int trusty_ipc_dev_recv(struct trusty_ipc_dev *dev, handle_t chan,
+ const struct trusty_ipc_iovec *iovs, size_t iovs_cnt)
+{
+ int rc;
+ size_t copied;
+ volatile struct trusty_ipc_cmd_hdr *cmd;
+
+ trusty_assert(dev);
+
+ /* prepare command */
+ cmd = dev->buf_vaddr;
+ trusty_memset((void *)cmd, 0, sizeof(*cmd));
+ cmd->opcode = QL_TIPC_DEV_RECV;
+ cmd->handle = chan;
+ /* no payload */
+
+ /* call into secure os */
+ rc = trusty_dev_exec_ipc(dev->tdev,
+ &dev->buf_ns, sizeof(*cmd) + cmd->payload_len);
+ if (rc < 0) {
+ trusty_error("%s: secure OS returned (%d)\n", __func__, rc);
+ return TRUSTY_ERR_SECOS_ERR;
+ }
+
+ rc = check_response(dev, cmd, QL_TIPC_DEV_RECV);
+ if (rc) {
+ trusty_error("%s: recv cmd failed (%d)\n", __func__, rc);
+ return rc;
+ }
+
+ /* copy data out to proper destination */
+ copied = buf_to_iovec(iovs, iovs_cnt,
+ (const void *)cmd->payload, cmd->payload_len);
+ if (copied != (size_t)cmd->payload_len) {
+ /* msg is too big to fit provided buffer */
+ trusty_error("%s: chan %d: buffer too small (%zu vs. %zu)\n",
+ __func__, chan, copied, (size_t)cmd->payload_len);
+ return TRUSTY_ERR_MSG_TOO_BIG;
+ }
+
+ return (int)copied;
+}
+
+void trusty_ipc_dev_idle(struct trusty_ipc_dev *dev)
+{
+ trusty_idle(dev->tdev);
+}
+
diff --git a/lib/trusty/ql-tipc/keymaster.c b/lib/trusty/ql-tipc/keymaster.c
new file mode 100644
index 0000000000..d3c0be4a8e
--- /dev/null
+++ b/lib/trusty/ql-tipc/keymaster.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/keymaster.h>
+#include <trusty/rpmb.h>
+#include <trusty/trusty_ipc.h>
+#include <trusty/util.h>
+
+#define LOCAL_LOG 0
+
+static struct trusty_ipc_chan km_chan;
+static bool initialized;
+static int trusty_km_version = 2;
+
+static int km_send_request(struct keymaster_message *msg, void *req,
+ size_t req_len)
+{
+ int num_iovecs = req ? 2 : 1;
+
+ struct trusty_ipc_iovec req_iovs[2] = {
+ { .base = msg, .len = sizeof(*msg) },
+ { .base = req, .len = req_len },
+ };
+
+ return trusty_ipc_send(&km_chan, req_iovs, num_iovecs, true);
+}
+
+static int km_read_response(struct keymaster_message *msg, uint32_t cmd,
+ void *resp, size_t resp_len)
+{
+ int rc = TRUSTY_ERR_GENERIC;
+ struct trusty_ipc_iovec resp_iovs[2] = {
+ { .base = msg, .len = sizeof(*msg) },
+ { .base = resp, .len = resp_len },
+ };
+
+ rc = trusty_ipc_recv(&km_chan, resp_iovs, resp ? 2 : 1, true);
+ if (rc < 0) {
+ trusty_error("failed (%d) to recv response\n", rc);
+ return rc;
+ }
+ if ((msg->cmd & ~(KEYMASTER_STOP_BIT)) != (cmd | KEYMASTER_RESP_BIT)) {
+ trusty_error("malformed response\n");
+ return TRUSTY_ERR_GENERIC;
+ }
+
+ return rc;
+}
+
+static int km_do_tipc(uint32_t cmd, void *req, uint32_t req_len,
+ bool handle_rpmb)
+{
+ int rc = TRUSTY_ERR_GENERIC;
+ struct keymaster_message msg = { .cmd = cmd };
+ struct km_no_response resp;
+
+ rc = km_send_request(&msg, req, req_len);
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to send km request\n", __func__, rc);
+ return rc;
+ }
+
+ if (handle_rpmb) {
+ /* handle any incoming RPMB requests */
+ rc = rpmb_storage_proxy_poll();
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to get RPMB requests\n", __func__,
+ rc);
+ return rc;
+ }
+ }
+
+ rc = km_read_response(&msg, cmd, &resp, sizeof(resp));
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to read km response\n", __func__, rc);
+ return rc;
+ }
+ return resp.error;
+}
+
+static int32_t MessageVersion(uint8_t major_ver, uint8_t minor_ver,
+ uint8_t subminor_ver) {
+ int32_t message_version = -1;
+ switch (major_ver) {
+ case 0:
+ message_version = 0;
+ break;
+ case 1:
+ switch (minor_ver) {
+ case 0:
+ message_version = 1;
+ break;
+ case 1:
+ message_version = 2;
+ break;
+ }
+ break;
+ case 2:
+ message_version = 3;
+ break;
+ }
+ return message_version;
+}
+
+static int km_get_version(int32_t *version)
+{
+ int rc = TRUSTY_ERR_GENERIC;
+ struct keymaster_message msg = { .cmd = KM_GET_VERSION };
+ struct km_get_version_resp resp;
+
+ rc = km_send_request(&msg, NULL, 0);
+ if (rc < 0) {
+ trusty_error("failed to send km version request", rc);
+ return rc;
+ }
+
+ rc = km_read_response(&msg, KM_GET_VERSION, &resp, sizeof(resp));
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to read km response\n", __func__, rc);
+ return rc;
+ }
+
+ *version = MessageVersion(resp.major_ver, resp.minor_ver,
+ resp.subminor_ver);
+ return rc;
+}
+
+int km_tipc_init(struct trusty_ipc_dev *dev)
+{
+ int rc = TRUSTY_ERR_GENERIC;
+
+ trusty_assert(dev);
+
+ trusty_ipc_chan_init(&km_chan, dev);
+ trusty_debug("Connecting to Keymaster service\n");
+
+ /* connect to km service and wait for connect to complete */
+ rc = trusty_ipc_connect(&km_chan, KEYMASTER_PORT, true);
+ if (rc < 0) {
+ trusty_error("failed (%d) to connect to '%s'\n", rc, KEYMASTER_PORT);
+ return rc;
+ }
+
+ int32_t version = -1;
+ rc = km_get_version(&version);
+ if (rc < 0) {
+ trusty_error("failed (%d) to get keymaster version\n", rc);
+ return rc;
+ }
+ if (version < trusty_km_version) {
+ trusty_error("keymaster version mismatch. Expected %d, received %d\n",
+ trusty_km_version, version);
+ return TRUSTY_ERR_GENERIC;
+ }
+
+ return TRUSTY_ERR_NONE;
+}
+
+void km_tipc_shutdown(struct trusty_ipc_dev *dev)
+{
+ if (!initialized)
+ return;
+ /* close channel */
+ trusty_ipc_close(&km_chan);
+
+ initialized = false;
+}
+
+/**
+ * Appends |data_len| bytes at |data| to |buf|. Performs no bounds checking,
+ * assumes sufficient memory allocated at |buf|. Returns |buf| + |data_len|.
+ */
+static uint8_t *append_to_buf(uint8_t *buf, const void *data, size_t data_len)
+{
+ if (data && data_len) {
+ trusty_memcpy(buf, data, data_len);
+ }
+ return buf + data_len;
+}
+
+/**
+ * Appends |val| to |buf|. Performs no bounds checking. Returns |buf| +
+ * sizeof(uint32_t).
+ */
+static uint8_t *append_uint32_to_buf(uint8_t *buf, uint32_t val)
+{
+ return append_to_buf(buf, &val, sizeof(val));
+}
+
+/**
+ * Appends a sized buffer to |buf|. First appends |data_len| to |buf|, then
+ * appends |data_len| bytes at |data| to |buf|. Performs no bounds checking.
+ * Returns |buf| + sizeof(uint32_t) + |data_len|.
+ */
+static uint8_t *append_sized_buf_to_buf(uint8_t *buf, const uint8_t *data,
+ uint32_t data_len)
+{
+ buf = append_uint32_to_buf(buf, data_len);
+ return append_to_buf(buf, data, data_len);
+}
+
+int km_boot_params_serialize(const struct km_boot_params *params, uint8_t** out,
+ uint32_t *out_size)
+{
+ uint8_t *tmp;
+
+ if (!out || !params || !out_size) {
+ return TRUSTY_ERR_INVALID_ARGS;
+ }
+ *out_size = (sizeof(params->os_version) + sizeof(params->os_patchlevel) +
+ sizeof(params->device_locked) +
+ sizeof(params->verified_boot_state) +
+ sizeof(params->verified_boot_key_hash_size) +
+ sizeof(params->verified_boot_hash_size) +
+ params->verified_boot_key_hash_size +
+ params->verified_boot_hash_size);
+ *out = trusty_calloc(*out_size, 1);
+ if (!*out) {
+ return TRUSTY_ERR_NO_MEMORY;
+ }
+
+ tmp = append_uint32_to_buf(*out, params->os_version);
+ tmp = append_uint32_to_buf(tmp, params->os_patchlevel);
+ tmp = append_uint32_to_buf(tmp, params->device_locked);
+ tmp = append_uint32_to_buf(tmp, params->verified_boot_state);
+ tmp = append_sized_buf_to_buf(tmp, params->verified_boot_key_hash,
+ params->verified_boot_key_hash_size);
+ tmp = append_sized_buf_to_buf(tmp, params->verified_boot_hash,
+ params->verified_boot_hash_size);
+
+ return TRUSTY_ERR_NONE;
+}
+
+int km_attestation_data_serialize(const struct km_attestation_data *data,
+ uint8_t** out, uint32_t *out_size)
+{
+ uint8_t *tmp;
+
+ if (!out || !data || !out_size) {
+ return TRUSTY_ERR_INVALID_ARGS;
+ }
+ *out_size = (sizeof(data->algorithm) + sizeof(data->data_size) +
+ data->data_size);
+ *out = trusty_calloc(*out_size, 1);
+ if (!*out) {
+ return TRUSTY_ERR_NO_MEMORY;
+ }
+
+ tmp = append_uint32_to_buf(*out, data->algorithm);
+ tmp = append_sized_buf_to_buf(tmp, data->data, data->data_size);
+
+ return TRUSTY_ERR_NONE;
+}
+
+int trusty_set_boot_params(uint32_t os_version, uint32_t os_patchlevel,
+ keymaster_verified_boot_t verified_boot_state,
+ bool device_locked,
+ const uint8_t *verified_boot_key_hash,
+ uint32_t verified_boot_key_hash_size,
+ const uint8_t *verified_boot_hash,
+ uint32_t verified_boot_hash_size)
+{
+ struct km_boot_params params = {
+ .os_version = os_version,
+ .os_patchlevel = os_patchlevel,
+ .device_locked = (uint32_t)device_locked,
+ .verified_boot_state = (uint32_t)verified_boot_state,
+ .verified_boot_key_hash_size = verified_boot_key_hash_size,
+ .verified_boot_key_hash = verified_boot_key_hash,
+ .verified_boot_hash_size = verified_boot_hash_size,
+ .verified_boot_hash = verified_boot_hash
+ };
+ uint8_t *req = NULL;
+ uint32_t req_size = 0;
+ int rc = km_boot_params_serialize(&params, &req, &req_size);
+
+ if (rc < 0) {
+ trusty_error("failed (%d) to serialize request\n", rc);
+ goto end;
+ }
+ rc = km_do_tipc(KM_SET_BOOT_PARAMS, req, req_size, false);
+
+end:
+ if (req) {
+ trusty_free(req);
+ }
+ return rc;
+}
+
+static int trusty_send_attestation_data(uint32_t cmd, const uint8_t *data,
+ uint32_t data_size,
+ keymaster_algorithm_t algorithm)
+{
+ struct km_attestation_data attestation_data = {
+ .algorithm = (uint32_t)algorithm,
+ .data_size = data_size,
+ .data = data,
+ };
+ uint8_t *req = NULL;
+ uint32_t req_size = 0;
+ int rc = km_attestation_data_serialize(&attestation_data, &req, &req_size);
+
+ if (rc < 0) {
+ trusty_error("failed (%d) to serialize request\n", rc);
+ goto end;
+ }
+ rc = km_do_tipc(cmd, req, req_size, true);
+
+end:
+ if (req) {
+ trusty_free(req);
+ }
+ return rc;
+}
+
+int trusty_set_attestation_key(const uint8_t *key, uint32_t key_size,
+ keymaster_algorithm_t algorithm)
+{
+ return trusty_send_attestation_data(KM_SET_ATTESTATION_KEY, key, key_size,
+ algorithm);
+}
+
+int trusty_append_attestation_cert_chain(const uint8_t *cert,
+ uint32_t cert_size,
+ keymaster_algorithm_t algorithm)
+{
+ return trusty_send_attestation_data(KM_APPEND_ATTESTATION_CERT_CHAIN,
+ cert, cert_size, algorithm);
+}
diff --git a/lib/trusty/ql-tipc/libtipc.c b/lib/trusty/ql-tipc/libtipc.c
new file mode 100644
index 0000000000..1f3fa66973
--- /dev/null
+++ b/lib/trusty/ql-tipc/libtipc.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/avb.h>
+#include <trusty/keymaster.h>
+#include <trusty/rpmb.h>
+#include <trusty/trusty_dev.h>
+#include <trusty/trusty_ipc.h>
+#include <trusty/util.h>
+
+#define LOCAL_LOG 0
+
+typedef uintptr_t vaddr_t;
+
+static struct trusty_ipc_dev *_ipc_dev;
+static struct trusty_dev _tdev; /* There should only be one trusty device */
+static void *rpmb_ctx;
+
+void trusty_ipc_shutdown(void)
+{
+ (void)rpmb_storage_proxy_shutdown(_ipc_dev);
+ (void)rpmb_storage_put_ctx(rpmb_ctx);
+
+ (void)avb_tipc_shutdown(_ipc_dev);
+ (void)km_tipc_shutdown(_ipc_dev);
+
+ /* shutdown Trusty IPC device */
+ (void)trusty_ipc_dev_shutdown(_ipc_dev);
+
+ /* shutdown Trusty device */
+ (void)trusty_dev_shutdown(&_tdev);
+}
+
+int trusty_ipc_init(void)
+{
+ int rc;
+ /* init Trusty device */
+ trusty_info("Initializing Trusty device\n");
+ rc = trusty_dev_init(&_tdev, NULL);
+ if (rc != 0) {
+ trusty_error("Initializing Trusty device failed (%d)\n", rc);
+ return rc;
+ }
+
+ /* create Trusty IPC device */
+ trusty_info("Initializing Trusty IPC device\n");
+ rc = trusty_ipc_dev_create(&_ipc_dev, &_tdev, PAGE_SIZE);
+ if (rc != 0) {
+ trusty_error("Initializing Trusty IPC device failed (%d)\n", rc);
+ return rc;
+ }
+
+ /* get storage rpmb */
+ rpmb_ctx = rpmb_storage_get_ctx();
+
+ /* start secure storage proxy service */
+ trusty_info("Initializing RPMB storage proxy service\n");
+ rc = rpmb_storage_proxy_init(_ipc_dev, rpmb_ctx);
+ if (rc != 0) {
+ trusty_error("Initlializing RPMB storage proxy service failed (%d)\n",
+ rc);
+ return rc;
+ }
+
+ trusty_info("Initializing Trusty AVB client\n");
+ rc = avb_tipc_init(_ipc_dev);
+ if (rc != 0) {
+ trusty_error("Initlializing Trusty AVB client failed (%d)\n", rc);
+ return rc;
+ }
+
+ trusty_info("Initializing Trusty Keymaster client\n");
+ rc = km_tipc_init(_ipc_dev);
+ if (rc != 0) {
+ trusty_error("Initlializing Trusty Keymaster client failed (%d)\n", rc);
+ return rc;
+ }
+
+ return TRUSTY_ERR_NONE;
+}
diff --git a/lib/trusty/ql-tipc/rpmb_proxy.c b/lib/trusty/ql-tipc/rpmb_proxy.c
new file mode 100644
index 0000000000..e4a684f5f3
--- /dev/null
+++ b/lib/trusty/ql-tipc/rpmb_proxy.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/rpmb.h>
+#include <trusty/trusty_ipc.h>
+#include <trusty/util.h>
+#include <interface/storage/storage.h>
+
+#define LOCAL_LOG 1
+
+static bool initialized;
+/* Address of rpmb device */
+static void *proxy_rpmb;
+struct trusty_ipc_chan proxy_chan;
+
+struct storage_msg req_msg;
+static uint8_t req_buf[4096];
+static uint8_t read_buf[4096];
+
+/*
+ * Read RPMB request from storage service. Writes message to @msg
+ * and @req.
+ *
+ * @chan: proxy ipc channel
+ * @msg: address of storage message header
+ * @req: address of storage message request
+ * @req_len: length of req in bytes
+ */
+static int proxy_read_request(struct trusty_ipc_chan *chan,
+ struct storage_msg *msg, void *req,
+ size_t req_len)
+{
+ int rc;
+
+ struct trusty_ipc_iovec req_iovs[2] = {
+ { .base = msg, .len = sizeof(*msg) },
+ { .base = req, .len = req_len },
+ };
+ rc = trusty_ipc_recv(chan, req_iovs, 2, false);
+ if (rc < 0) {
+ /* recv message failed */
+ trusty_error("%s: failed (%d) to recv request\n", __func__, rc);
+ return rc;
+ }
+
+ if ((size_t)rc < sizeof(*msg)) {
+ /* malformed message */
+ trusty_error("%s: malformed request (%zu)\n", __func__, (size_t)rc);
+ return TRUSTY_ERR_GENERIC;
+ }
+
+ return rc - sizeof(*msg); /* return payload size */
+}
+
+/*
+ * Send RPMB response to storage service
+ *
+ * @chan: proxy ipc channel
+ * @msg: address of storage message header
+ * @resp: address of storage message response
+ * @resp_len: length of resp in bytes
+ */
+static int proxy_send_response(struct trusty_ipc_chan *chan,
+ struct storage_msg *msg, void *resp,
+ size_t resp_len)
+{
+ struct trusty_ipc_iovec resp_iovs[2] = {
+ { .base = msg, .len = sizeof(*msg) },
+ { .base = resp, .len = resp_len }
+ };
+
+ msg->cmd |= STORAGE_RESP_BIT;
+ return trusty_ipc_send(chan, resp_iovs, resp ? 2 : 1, false);
+}
+
+/*
+ * Executes the RPMB request at @r, sends response to storage service.
+ *
+ * @chan: proxy ipc channel
+ * @msg: address of storage message header
+ * @r: address of storage message request
+ * @req_len: length of resp in bytes
+ */
+static int proxy_handle_rpmb(struct trusty_ipc_chan *chan,
+ struct storage_msg *msg, const void *r,
+ size_t req_len)
+{
+ int rc;
+ size_t exp_len;
+ const void *write_data = NULL;
+ const void *rel_write_data = NULL;
+ const struct storage_rpmb_send_req *req = r;
+
+ if (req_len < sizeof(req)) {
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ exp_len = sizeof(*req) + req->reliable_write_size + req->write_size;
+ if (req_len != exp_len) {
+ trusty_error(
+ "%s: malformed rpmb request: invalid length (%zu != %zu)\n",
+ __func__, req_len, exp_len);
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ if (req->reliable_write_size) {
+ if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) {
+ trusty_error("%s: invalid reliable write size %u\n", __func__,
+ req->reliable_write_size);
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+ rel_write_data = req->payload;
+ }
+
+ if (req->write_size) {
+ if ((req->write_size % MMC_BLOCK_SIZE) != 0) {
+ trusty_error("%: invalid write size %u\n", __func__,
+ req->write_size);
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+ write_data = req->payload + req->reliable_write_size;
+ }
+
+ if (req->read_size) {
+ if (req->read_size % MMC_BLOCK_SIZE != 0 ||
+ req->read_size > sizeof(read_buf)) {
+ trusty_error("%s: invalid read size %u\n", __func__,
+ req->read_size);
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+ }
+
+ /* execute rpmb command */
+ rc = rpmb_storage_send(proxy_rpmb,
+ rel_write_data, req->reliable_write_size,
+ write_data, req->write_size,
+ read_buf, req->read_size);
+ if (rc) {
+ trusty_error("%s: rpmb_storage_send failed: %d\n", __func__, rc);
+ msg->result = STORAGE_ERR_GENERIC;
+ goto err_response;
+ }
+
+ if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
+ /*
+ * Nothing todo for post msg commit request as MMC_IOC_MULTI_CMD
+ * is fully synchronous in this implementation.
+ */
+ }
+
+ msg->result = STORAGE_NO_ERROR;
+ return proxy_send_response(chan, msg, read_buf, req->read_size);
+
+err_response:
+ return proxy_send_response(chan, msg, NULL, 0);
+}
+
+/*
+ * Handles storage request.
+ *
+ * @chan: proxy ipc channel
+ * @msg: address of storage message header
+ * @req: address of storage message request
+ * @req_len: length of resp in bytes
+ */
+static int proxy_handle_req(struct trusty_ipc_chan *chan,
+ struct storage_msg *msg, const void *req,
+ size_t req_len)
+{
+ int rc;
+
+ if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT) {
+ /* nothing to do */
+ }
+
+ switch (msg->cmd) {
+ case STORAGE_RPMB_SEND:
+ rc = proxy_handle_rpmb(chan, msg, req, req_len);
+ break;
+
+ case STORAGE_FILE_DELETE:
+ case STORAGE_FILE_OPEN:
+ case STORAGE_FILE_CLOSE:
+ case STORAGE_FILE_WRITE:
+ case STORAGE_FILE_READ:
+ case STORAGE_FILE_GET_SIZE:
+ case STORAGE_FILE_SET_SIZE:
+ /* Bulk filesystem is not supported */
+ msg->result = STORAGE_ERR_UNIMPLEMENTED;
+ rc = proxy_send_response(chan, msg, NULL, 0);
+ break;
+
+ default:
+ msg->result = STORAGE_ERR_UNIMPLEMENTED;
+ rc = proxy_send_response(chan, msg, NULL, 0);
+ }
+
+ return rc;
+}
+
+/*
+ * Invalidates @chan on hangup event
+ *
+ * @chan: proxy ipc channel
+ */
+static int proxy_on_disconnect(struct trusty_ipc_chan *chan)
+{
+ trusty_assert(chan);
+
+ trusty_debug("%s: closed by peer\n", __func__);
+ chan->handle = INVALID_IPC_HANDLE;
+ return TRUSTY_EVENT_HANDLED;
+}
+
+/*
+ * Handles received storage message on message event
+ *
+ * @chan: proxy ipc channel
+ */
+static int proxy_on_message(struct trusty_ipc_chan *chan)
+{
+ int rc;
+
+ trusty_assert(chan);
+
+ /* read request */
+ rc = proxy_read_request(chan, &req_msg, req_buf, sizeof(req_buf));
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to read request\n", __func__, rc);
+ trusty_ipc_close(chan);
+ return rc;
+ }
+
+ /* handle it and send reply */
+ rc = proxy_handle_req(chan, &req_msg, req_buf, rc);
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to handle request\n", __func__, rc);
+ trusty_ipc_close(chan);
+ return rc;
+ }
+
+ return TRUSTY_EVENT_HANDLED;
+}
+
+static struct trusty_ipc_ops proxy_ops = {
+ .on_message = proxy_on_message,
+ .on_disconnect = proxy_on_disconnect,
+};
+
+/*
+ * Initialize RPMB storage proxy
+ */
+int rpmb_storage_proxy_init(struct trusty_ipc_dev *dev, void *rpmb_dev)
+{
+ int rc;
+
+ trusty_assert(dev);
+ trusty_assert(!initialized);
+
+ /* attach rpmb device */
+ proxy_rpmb = rpmb_dev;
+
+ /* init ipc channel */
+ trusty_ipc_chan_init(&proxy_chan, dev);
+
+ /* connect to proxy service and wait for connect to complete */
+ rc = trusty_ipc_connect(&proxy_chan, STORAGE_DISK_PROXY_PORT, true);
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to connect to '%s'\n", __func__, rc,
+ STORAGE_DISK_PROXY_PORT);
+ return rc;
+ }
+
+ /* override default ops */
+ proxy_chan.ops = &proxy_ops;
+
+ rc = rpmb_storage_proxy_poll();
+ if (rc < 0) {
+ return rc;
+ }
+
+ /* mark as initialized */
+ initialized = true;
+
+ return TRUSTY_ERR_NONE;
+}
+
+int rpmb_storage_proxy_poll(void)
+{
+ int rc = 0;
+ while (rc != TRUSTY_EVENT_NONE) {
+ /* Check for RPMB events */
+ rc = trusty_ipc_poll_for_event(&proxy_chan);
+ if (rc < 0) {
+ trusty_error("%s: failed (%d) to get rpmb event\n", __func__, rc);
+ return rc;
+ }
+ }
+ return TRUSTY_ERR_NONE;
+}
+
+void rpmb_storage_proxy_shutdown(struct trusty_ipc_dev *dev)
+{
+ if (!initialized)
+ return; /* nothing to do */
+
+ /* close channel */
+ trusty_ipc_close(&proxy_chan);
+
+ initialized = false;
+}
diff --git a/lib/trusty/ql-tipc/sysdeps/Makefile b/lib/trusty/ql-tipc/sysdeps/Makefile
new file mode 100644
index 0000000000..f9b19d05cc
--- /dev/null
+++ b/lib/trusty/ql-tipc/sysdeps/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+
+# Sample Makefile for U-boot
+
+#ccflags-y += -DTIPC_ENABLE_DEBUG
+
+TRUSTY_DIR = lib/trusty
+#ccflags-y += -I$(TRUSTY_DIR)/ql-tipc/include
+ccflags-y += -I$(TRUSTY_DIR)/interface/include
+
+QL_TIPC = ../
+obj-y += \
+ $(QL_TIPC)/avb.o \
+ $(QL_TIPC)/keymaster.o \
+ $(QL_TIPC)/ipc.o \
+ $(QL_TIPC)/ipc_dev.o \
+ $(QL_TIPC)/libtipc.o \
+ $(QL_TIPC)/rpmb_proxy.o \
+ sysdeps_uboot.o \
+ storage_ops_uboot.o
+
+obj-$(CONFIG_ARM) += \
+ $(QL_TIPC)/arch/arm/trusty_mem.o \
+ $(QL_TIPC)/arch/arm/trusty_dev.o
diff --git a/lib/trusty/ql-tipc/sysdeps/storage_ops_uboot.c b/lib/trusty/ql-tipc/sysdeps/storage_ops_uboot.c
new file mode 100644
index 0000000000..de1217427c
--- /dev/null
+++ b/lib/trusty/ql-tipc/sysdeps/storage_ops_uboot.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/rpmb.h>
+#include <trusty/trusty_dev.h>
+#include <trusty/util.h>
+
+#include <common.h>
+#include <memalign.h>
+#include <mmc.h>
+
+void *rpmb_storage_get_ctx(void)
+{
+ /* Unused for U-boot */
+ return NULL;
+}
+
+void rpmb_storage_put_ctx(void *dev)
+{
+}
+
+int rpmb_storage_send(void *rpmb_dev, const void *rel_write_data,
+ size_t rel_write_size, const void *write_data,
+ size_t write_size, void *read_buf, size_t read_size)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(uint8_t, rpmb_rel_write_data, rel_write_size);
+ ALLOC_CACHE_ALIGN_BUFFER(uint8_t, rpmb_write_data, write_size);
+ ALLOC_CACHE_ALIGN_BUFFER(uint8_t, rpmb_read_data, read_size);
+ int ret = TRUSTY_ERR_NONE;
+ struct mmc *mmc = find_mmc_device(mmc_get_env_dev());
+ char original_part = mmc->block_dev.hwpart;
+
+ /* Switch to RPMB partition */
+ if (mmc->block_dev.hwpart != MMC_PART_RPMB) {
+ ret = mmc_switch_part(mmc, MMC_PART_RPMB);
+ if (ret) {
+ trusty_error("failed to switch to RPMB partition\n");
+ ret = TRUSTY_ERR_GENERIC;
+ goto end;
+ }
+ mmc->block_dev.hwpart = MMC_PART_RPMB;
+ }
+
+ if (rel_write_size) {
+ if (rel_write_size % MMC_BLOCK_SIZE) {
+ trusty_error(
+ "rel_write_size is not a multiple of MMC_BLOCK_SIZE: %d\n",
+ rel_write_size);
+ ret = TRUSTY_ERR_INVALID_ARGS;
+ goto end;
+ }
+ trusty_memcpy(rpmb_rel_write_data, rel_write_data, rel_write_size);
+ ret = mmc_rpmb_request(mmc,
+ (const struct s_rpmb *)rpmb_rel_write_data,
+ rel_write_size / MMC_BLOCK_SIZE, true);
+ if (ret) {
+ trusty_error("failed to execute rpmb reliable write\n");
+ goto end;
+ }
+ }
+ if (write_size) {
+ if (write_size % MMC_BLOCK_SIZE) {
+ trusty_error("write_size is not a multiple of MMC_BLOCK_SIZE: %d\n",
+ write_size);
+ ret = TRUSTY_ERR_INVALID_ARGS;
+ goto end;
+ }
+ trusty_memcpy(rpmb_write_data, write_data, write_size);
+ ret = mmc_rpmb_request(mmc, (const struct s_rpmb *)rpmb_write_data,
+ write_size / MMC_BLOCK_SIZE, false);
+ if (ret) {
+ trusty_error("failed to execute rpmb write\n");
+ goto end;
+ }
+ }
+ if (read_size) {
+ if (read_size % MMC_BLOCK_SIZE) {
+ trusty_error("read_size is not a multiple of MMC_BLOCK_SIZE: %d\n",
+ read_size);
+ ret = TRUSTY_ERR_INVALID_ARGS;
+ goto end;
+ }
+ ret = mmc_rpmb_response(mmc, (struct s_rpmb *)rpmb_read_data,
+ read_size / MMC_BLOCK_SIZE, 0);
+ trusty_memcpy((void *)read_buf, rpmb_read_data, read_size);
+ if (ret < 0) {
+ trusty_error("failed to execute rpmb read\n");
+ }
+ }
+
+end:
+ /* Return to original partition */
+ if (mmc->block_dev.hwpart != original_part) {
+ if (mmc_switch_part(mmc, original_part) != 0) {
+ trusty_error("failed to switch back to original partition\n");
+ return TRUSTY_ERR_GENERIC;
+ }
+ mmc->block_dev.hwpart = original_part;
+ }
+ return ret;
+}
diff --git a/lib/trusty/ql-tipc/sysdeps/sysdeps_uboot.c b/lib/trusty/ql-tipc/sysdeps/sysdeps_uboot.c
new file mode 100644
index 0000000000..a452689b2d
--- /dev/null
+++ b/lib/trusty/ql-tipc/sysdeps/sysdeps_uboot.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <trusty/sysdeps.h>
+
+#include <common.h>
+#include <linux/string.h>
+#include <malloc.h>
+
+extern int trusty_encode_page_info(struct ns_mem_page_info *page_info,
+ void *vaddr);
+
+void trusty_lock(struct trusty_dev *dev)
+{
+}
+void trusty_unlock(struct trusty_dev *dev)
+{
+}
+
+void trusty_local_irq_disable(unsigned long *state)
+{
+ disable_interrupts();
+}
+
+void trusty_local_irq_restore(unsigned long *state)
+{
+ enable_interrupts();
+}
+
+void trusty_idle(struct trusty_dev *dev)
+{
+ wfi();
+}
+
+void trusty_abort(void)
+{
+ do_reset(NULL, 0, 0, NULL);
+ __builtin_unreachable();
+}
+
+void trusty_printv(const char *message, ...)
+{
+ va_list ap;
+
+ va_start(ap, message);
+ vprintf(message, ap);
+ va_end(ap);
+}
+
+void *trusty_memcpy(void *dest, const void *src, size_t n)
+{
+ return memcpy(dest, src, n);
+}
+
+void *trusty_memset(void *dest, const int c, size_t n)
+{
+ return memset(dest, c, n);
+}
+
+char *trusty_strcpy(char *dest, const char *src)
+{
+ return strcpy(dest, src);
+}
+
+size_t trusty_strlen(const char *str)
+{
+ return strlen(str);
+}
+
+void *trusty_calloc(size_t n, size_t size)
+{
+ return calloc(n, size);
+}
+
+void trusty_free(void *addr)
+{
+ if (addr)
+ free(addr);
+}
+
+void *trusty_membuf_alloc(struct ns_mem_page_info *page_info, size_t size)
+{
+ void *va = NULL;
+ int res;
+
+ va = memalign(4096, size);
+ if (!va)
+ return NULL;
+
+ /* get memory attibutes */
+ res = trusty_encode_page_info(page_info, va);
+ if (res) {
+ trusty_membuf_free(va);
+ return NULL;
+ }
+ return va;
+}
+
+void trusty_membuf_free(void *va)
+{
+ if (va)
+ free(va);
+}