[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/mt2712/dapc/include/dapc_public.h b/src/bsp/trustzone/optee/source/mt2xxx/mt2712/dapc/include/dapc_public.h
new file mode 100644
index 0000000..89e023c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/mt2712/dapc/include/dapc_public.h
@@ -0,0 +1,94 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+#ifndef __TEE_DAPC_PUBLIC_H__
+#define __TEE_DAPC_PUBLIC_H__
+
+/******************************************************************************
+ * CONST
+ ******************************************************************************/
+typedef enum
+{
+    E_NO_PROTECTION = 0,
+    E_SEC_RW,
+    E_SEC_RW_NS_R,
+    E_FORBIDDEN,
+    E_MAX_APC_ATTR,
+    E_APC_ATTR_RESERVRD = 0x7FFFFFFF  /* force enum to use 32 bits */
+} APC_ATTR;
+
+typedef enum
+{
+    E_DOMAIN_0 = 0,
+    E_DOMAIN_1,
+    E_DOMAIN_2,
+    E_DOMAIN_3,
+    E_MAX_DOMAIN,
+    E_MASK_DOM_RESERVRD = 0x7FFFFFFF  /* force enum to use 32 bits */
+} E_MASK_DOM;
+
+
+/******************************************************************************
+ * API
+ ******************************************************************************/
+void dump_devapc(void);
+
+/*
+ * set_module_apc: set module permission on device apc.
+ * @module: the index of the moudle to specify permission
+ * @domain_num: domain index number (AP or MD domain)
+ * @permission_control: specified permission
+ * no return value.
+ */
+void set_module_apc(unsigned int module, E_MASK_DOM domain_num, APC_ATTR permission_control);
+
+/*
+ * set_master_transaction: set master transaction type on device apc.
+ * @master_index: the index of the master to set the transaction type
+ * @transaction_type: 1 for secure or 0 for non-secure
+ * @return value:    0 on success,
+ *                -100 for devapc not correctly init,
+ *                  -1 for master index invalid,
+ *                  -2 for transaction type invalid
+ */
+int set_master_transaction(unsigned int master_index, unsigned int transaction_type);
+
+
+/* Index */
+#define INFRA_AO_DEVICE_APC_AO   14
+
+
+
+#endif // __TEE_DAPC_PUBLIC_H__
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/mt2712/dapc/libdapc.a b/src/bsp/trustzone/optee/source/mt2xxx/mt2712/dapc/libdapc.a
new file mode 100644
index 0000000..cdddeb6
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/mt2712/dapc/libdapc.a
Binary files differ
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/.gitignore b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/.gitignore
new file mode 100644
index 0000000..e90e7d0
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/.gitignore
@@ -0,0 +1,19 @@
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+*.cmd
+*.d
+*.dmp
+*.elf
+*.lds
+*.map
+*.o
+*.swp
+*.ta
+cscope.*
+out/
+hello_world/host/optee_example_hello_world
+random/host/optee_example_random
+aes/host/optee_example_aes
+hotp/host/optee_example_hotp
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/CMakeLists.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/CMakeLists.txt
new file mode 100644
index 0000000..b8879b8
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required (VERSION 3.2)
+project (optee_examples C)
+
+# https://cmake.org/Wiki/CMake_Useful_Variables
+set (CMAKE_TOOLCHAIN_FILE CMakeToolchain.txt)
+
+include(GNUInstallDirs)
+
+add_compile_options (-Wall)
+#add_compile_options (
+#	-Wall -Wbad-function-cast -Wcast-align
+#	-Werror-implicit-function-declaration -Wextra
+#	-Wfloat-equal -Wformat-nonliteral -Wformat-security
+#	-Wformat=2 -Winit-self -Wmissing-declarations
+#	-Wmissing-format-attribute -Wmissing-include-dirs
+#	-Wmissing-noreturn -Wmissing-prototypes -Wnested-externs
+#	-Wpointer-arith -Wshadow -Wstrict-prototypes
+#	-Wswitch-default -Wunsafe-loop-optimizations
+#	-Wwrite-strings -Werror -fPIC
+#)
+
+find_program(CCACHE_FOUND ccache)
+if(CCACHE_FOUND)
+	set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
+	set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
+endif(CCACHE_FOUND)
+
+file(GLOB dirs *)
+foreach(dir ${dirs})
+	if(EXISTS ${dir}/CMakeLists.txt)
+		add_subdirectory(${dir})
+	endif()
+endforeach()
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/CMakeToolchain.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/CMakeToolchain.txt
new file mode 100644
index 0000000..3c10f45
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/CMakeToolchain.txt
@@ -0,0 +1 @@
+set (CMAKE_SYSTEM_NAME Linux)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/LICENSE b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/LICENSE
new file mode 100644
index 0000000..12e3c07
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/LICENSE
@@ -0,0 +1,27 @@
+Unless it has its own copyright/license embedded in its body, each source file
+is subject to the following license terms:
+
+Copyright (c) 2018, Linaro Limited
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/Makefile
new file mode 100644
index 0000000..4f4ed70
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/Makefile
@@ -0,0 +1,41 @@
+export V ?= 0
+
+$(warning OUTPUT_DIR:$(OUTPUT_DIR))
+OUTPUT_DIR ?= $(CURDIR)/out
+
+EXAMPLE_LIST := $(subst /,,$(dir $(wildcard */Makefile)))
+
+.PHONY: all
+all: examples prepare-for-rootfs
+
+.PHONY: clean
+clean: examples-clean prepare-for-rootfs-clean
+
+examples:
+	@for example in $(EXAMPLE_LIST); do \
+		$(MAKE) -C $$example O=$(OUTPUT_DIR)/$$example CROSS_COMPILE="$(HOST_CROSS_COMPILE)" || exit -1; \
+	done
+
+examples-clean:
+	@for example in $(EXAMPLE_LIST); do \
+		$(MAKE) -C $$example clean || exit -1; \
+	done
+
+prepare-for-rootfs: examples
+	@echo "Copying example CA and TA binaries to $(OUTPUT_DIR)..."
+	@mkdir -p $(OUTPUT_DIR)
+	@mkdir -p $(OUTPUT_DIR)/ta
+	@mkdir -p $(OUTPUT_DIR)/ca
+	@for example in $(EXAMPLE_LIST); do \
+		if [ -e $(OUTPUT_DIR)/$$example/host/optee_example_$$example ]; then \
+			cp -p $(OUTPUT_DIR)/$$example/host/optee_example_$$example $(OUTPUT_DIR)/ca/; \
+		fi; \
+		if [ -d $(OUTPUT_DIR)/$$example/ta/ ]; then \
+			cp -pr $(OUTPUT_DIR)/$$example/ta/*.ta $(OUTPUT_DIR)/ta/; \
+		fi; \
+	done
+
+prepare-for-rootfs-clean:
+	@rm -rf $(OUTPUT_DIR)/ta
+	@rm -rf $(OUTPUT_DIR)/ca
+	@rmdir --ignore-fail-on-non-empty $(OUTPUT_DIR) || test ! -e $(OUTPUT_DIR)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/README.md b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/README.md
new file mode 100644
index 0000000..fb96770
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/README.md
@@ -0,0 +1,42 @@
+# OP-TEE Sample Applications
+## Contents
+1. [Introduction](#1-introduction)
+2. [List of sample applications](#2-list-of-sample-applications)
+3. [How to build a Trusted Application](#3-how-to-build-a-trusted-application)
+
+
+## 1. Introduction
+This document describes the sample applications that are included in the OP-TEE,
+that aim to showcase specific functionality and use case.
+
+For sake of simplicity, all OP-TEE example test application are prefixed with
+`optee_example_`.
+
+---
+## 2. List of sample applications
+
+Directory **hello_world/**:
+* A very simple Trusted Application to answer a hello command and incrementing
+an integer value.
+* Test application: `optee_example_hello_world`
+* Trusted application UUID: 8aaaf200-2450-11e4-abe2-0002a5d5c51b
+
+Directory **random/**:
+* Generates a random UUID using capabilities of TEE API (`TEE_GenerateRandom()`).
+* Test application: `optee_example_random`
+* Trusted application UUID: b6c53aba-9669-4668-a7f2-205629d00f86
+
+Directory **aes/**:
+* Runs an AES encryption and decryption from a TA using the GPD TEE Internal
+Core API. Non secure test application provides the key, initial vector and
+ciphered data.
+* Test application: `optee_example_aes`
+* Trusted application UUID: 5dbac793-f574-4871-8ad3-04331ec17f24
+
+## 3. How to build a Trusted Application
+[TA basics] documentation presents the basics for  implementing and building
+an OP-TEE trusted application.
+
+One can also refer to the examples provided: source files and make scripts.
+
+[TA basics]:	./docs/TA_basics.md
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/Android.mk
new file mode 100644
index 0000000..b2e1393
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/Android.mk
@@ -0,0 +1,23 @@
+ifeq ($(OPTEE_TEE_SUPPORT),true)
+LOCAL_PATH := $(call my-dir)
+
+OPTEE_CLIENT_EXPORT ?= $(LOCAL_PATH)/../../optee_client/out/export
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DANDROID_BUILD
+LOCAL_CFLAGS += -Wall
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+
+LOCAL_SRC_FILES += host/main.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include \
+		    $(OPTEE_CLIENT_EXPORT)/include
+
+LOCAL_SHARED_LIBRARIES := libteec
+LOCAL_MODULE := optee_example_aes
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+include $(LOCAL_PATH)/ta/Android.mk
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/CMakeLists.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/CMakeLists.txt
new file mode 100644
index 0000000..3972ff5
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/CMakeLists.txt
@@ -0,0 +1,13 @@
+project (aes C)
+
+set (SRC host/main.c)
+
+add_executable (${PROJECT_NAME} ${SRC})
+
+target_include_directories(${PROJECT_NAME}
+			   PRIVATE ta/include
+			   PRIVATE include)
+
+target_link_libraries (${PROJECT_NAME} PRIVATE teec)
+
+install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/Makefile
new file mode 100644
index 0000000..c6526b9
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/Makefile
@@ -0,0 +1,15 @@
+export V ?= 0
+
+# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE
+HOST_CROSS_COMPILE ?= $(CROSS_COMPILE)
+TA_CROSS_COMPILE ?= $(CROSS_COMPILE)
+
+.PHONY: all
+all:
+	$(MAKE) -C host O=$(O)/host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables
+	$(MAKE) -C ta O=$(O)/ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" LDFLAGS=""
+
+.PHONY: clean
+clean:
+	$(MAKE) -C host clean
+	$(MAKE) -C ta clean
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/host/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/host/Makefile
new file mode 100644
index 0000000..cc08b2d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/host/Makefile
@@ -0,0 +1,36 @@
+CC      ?= $(CROSS_COMPILE)gcc
+LD      ?= $(CROSS_COMPILE)ld
+AR      ?= $(CROSS_COMPILE)ar
+NM      ?= $(CROSS_COMPILE)nm
+OBJCOPY ?= $(CROSS_COMPILE)objcopy
+OBJDUMP ?= $(CROSS_COMPILE)objdump
+READELF ?= $(CROSS_COMPILE)readelf
+
+ifneq ($O,)
+out-dir := $O
+else
+out-dir := .
+endif
+
+OBJS = main.o
+OOBJS = $(foreach obj, $(OBJS), $(out-dir)/$(obj))
+
+CFLAGS += -Wall -I../ta/include -I./include
+CFLAGS += -I$(TEEC_EXPORT)/include
+LDADD += -lteec -L$(TEEC_EXPORT)/lib $(LDFLAGS)
+
+BINARY = $(out-dir)/optee_example_aes
+
+.PHONY: all
+all: $(BINARY)
+
+$(BINARY): $(OOBJS)
+	$(CC) -o $@ $< $(LDADD)
+
+.PHONY: clean
+clean:
+	rm -f $(OOBJS) $(BINARY)
+
+$(out-dir)/%.o: %.c
+	mkdir -p $(dir $@);
+	$(CC) $(CFLAGS) -c $< -o $@
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/host/main.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/host/main.c
new file mode 100644
index 0000000..a3f3130
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/host/main.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+/* OP-TEE TEE client API (built by optee_client) */
+#include <tee_client_api.h>
+
+/* To the the UUID (found the the TA's h-file(s)) */
+#include <aes_ta.h>
+#include <sys/time.h>
+
+#define AES_TEST_BUFFER_SIZE	4096
+#define AES_TEST_KEY_SIZE	16
+
+#define DECODE			0
+#define ENCODE			1
+
+/* TEE resources */
+struct test_ctx {
+	TEEC_Context ctx;
+	TEEC_Session sess;
+};
+
+void prepare_tee_session(struct test_ctx *ctx)
+{
+	TEEC_UUID uuid = TA_AES_UUID;
+	uint32_t origin;
+	TEEC_Result res;
+
+	/* Initialize a context connecting us to the TEE */
+	res = TEEC_InitializeContext(NULL, &ctx->ctx);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
+
+	/* Open a session with the TA */
+	res = TEEC_OpenSession(&ctx->ctx, &ctx->sess, &uuid,
+			       TEEC_LOGIN_PUBLIC, NULL, NULL, &origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
+			res, origin);
+}
+
+void terminate_tee_session(struct test_ctx *ctx)
+{
+	TEEC_CloseSession(&ctx->sess);
+	TEEC_FinalizeContext(&ctx->ctx);
+}
+
+void prepare_aes(struct test_ctx *ctx, int encode)
+{
+	TEEC_Operation op;
+	uint32_t origin;
+	TEEC_Result res;
+
+	memset(&op, 0, sizeof(op));
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+					 TEEC_VALUE_INPUT,
+					 TEEC_VALUE_INPUT,
+					 TEEC_NONE);
+
+	op.params[0].value.a = TA_AES_ALGO_CBC;
+	op.params[1].value.a = TA_AES_SIZE_128BIT;
+	op.params[2].value.a = encode ? TA_AES_MODE_ENCODE :
+					TA_AES_MODE_DECODE;
+
+	res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_PREPARE,
+				 &op, &origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InvokeCommand(PREPARE) failed 0x%x origin 0x%x",
+			res, origin);
+}
+
+void set_key(struct test_ctx *ctx, char *key, size_t key_sz)
+{
+	TEEC_Operation op;
+	uint32_t origin;
+	TEEC_Result res;
+
+	memset(&op, 0, sizeof(op));
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+					 TEEC_NONE, TEEC_NONE, TEEC_NONE);
+
+	op.params[0].tmpref.buffer = key;
+	op.params[0].tmpref.size = key_sz;
+
+	res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_KEY,
+				 &op, &origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InvokeCommand(SET_KEY) failed 0x%x origin 0x%x",
+			res, origin);
+}
+
+void set_iv(struct test_ctx *ctx, char *iv, size_t iv_sz)
+{
+	TEEC_Operation op;
+	uint32_t origin;
+	TEEC_Result res;
+
+	memset(&op, 0, sizeof(op));
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+					  TEEC_NONE, TEEC_NONE, TEEC_NONE);
+	op.params[0].tmpref.buffer = iv;
+	op.params[0].tmpref.size = iv_sz;
+
+	res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_IV,
+				 &op, &origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InvokeCommand(SET_IV) failed 0x%x origin 0x%x",
+			res, origin);
+}
+
+void cipher_buffer(struct test_ctx *ctx, char *in, char *out, size_t sz)
+{
+	TEEC_Operation op;
+	uint32_t origin;
+	TEEC_Result res;
+
+	memset(&op, 0, sizeof(op));
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+					 TEEC_MEMREF_TEMP_OUTPUT,
+					 TEEC_NONE, TEEC_NONE);
+	op.params[0].tmpref.buffer = in;
+	op.params[0].tmpref.size = sz;
+	op.params[1].tmpref.buffer = out;
+	op.params[1].tmpref.size = sz;
+
+	res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_CIPHER,
+				 &op, &origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InvokeCommand(CIPHER) failed 0x%x origin 0x%x",
+			res, origin);
+}
+
+int performance(void)
+{
+	size_t test_size = AES_TEST_BUFFER_SIZE * 10;
+	char *clear = NULL;
+	char *ciph = NULL;
+	char *temp  = NULL;
+	struct test_ctx ctx;
+	char key[AES_TEST_KEY_SIZE];
+	char iv[AES_TEST_KEY_SIZE];
+	int index = 0;
+	int round = 250;
+
+	clear = malloc(test_size);
+	if (clear == NULL) {
+		errx(1, "Malloc clear buffer failed!");
+	}
+	ciph = malloc(test_size);
+	if (ciph == NULL) {
+		errx(1, "Malloc cipher buffer failed!");
+	}
+
+	temp = malloc(test_size);
+	if (temp == NULL){
+		errx(1, "Malloc temp buffer failed!");
+	}
+	printf("Prepare session with the TA\n");
+	prepare_tee_session(&ctx);
+
+	printf("Prepare encode operation\n");
+	prepare_aes(&ctx, ENCODE);
+
+	printf("Load key in TA\n");
+	memset(key, 0xa5, sizeof(key)); /* Load some dummy value */
+	set_key(&ctx, key, AES_TEST_KEY_SIZE);
+
+	printf("Reset ciphering operation in TA (provides the initial vector)\n");
+	memset(iv, 0, sizeof(iv)); /* Load some dummy value */
+	set_iv(&ctx, iv, AES_TEST_KEY_SIZE);
+
+	printf("Encore buffer from TA with %d bytes data\n", test_size);
+	memset(clear, 0x5a, test_size); /* Load some dummy value */
+	cipher_buffer(&ctx, clear, ciph, test_size);
+
+    printf("Prepare decode operation\n");
+	prepare_aes(&ctx, DECODE);
+
+	printf("Load key in TA\n");
+	memset(key, 0xa5, sizeof(key)); /* Load some dummy value */
+	set_key(&ctx, key, AES_TEST_KEY_SIZE);
+
+	printf("Reset ciphering operation in TA (provides the initial vector)\n");
+	memset(iv, 0, sizeof(iv)); /* Load some dummy value */
+	set_iv(&ctx, iv, AES_TEST_KEY_SIZE);
+
+	printf("Decode buffer from TA with %d bytes data\n", test_size);
+	memset(clear, 0x5a, test_size); /* Load some dummy value */
+	cipher_buffer(&ctx, ciph, temp, test_size);
+
+	/* Check decoded is the clear content */
+	if (memcmp(clear, temp, test_size))
+		printf("Clear text and decoded text differ => ERROR\n");
+	else
+		printf("Clear text and decoded text match\n");
+	// Performace test begain.
+	printf("Prepare encode performance operation\n");
+	prepare_aes(&ctx, ENCODE);
+
+	printf("Load key in TA\n");
+	memset(key, 0xa5, sizeof(key)); /* Load some dummy value */
+	set_key(&ctx, key, AES_TEST_KEY_SIZE);
+
+	printf("Reset ciphering operation in TA (provides the initial vector)\n");
+	memset(iv, 0, sizeof(iv)); /* Load some dummy value */
+	set_iv(&ctx, iv, AES_TEST_KEY_SIZE);
+
+	printf("Encore buffer from TA with %d bytes data with round %d\n", test_size, round);
+	memset(clear, 0x5a, test_size); /* Load some dummy value */
+	struct timeval tval_be, tval_af, tval_res;
+	gettimeofday(&tval_be, NULL);
+	for (index = 0; index < round; index++)
+	{
+		cipher_buffer(&ctx, ciph, temp, test_size);
+	}
+	gettimeofday(&tval_af, NULL);
+	timersub(&tval_af, &tval_be, &tval_res);
+	printf("Time elapsed:%ld.%06ld\n", (long int)tval_res.tv_sec, (long int)tval_res.tv_usec);
+	printf("Finish encore buffer from TA with %d bytes data with round %d\n", test_size, round);
+
+}
+
+int aes_basic(void)
+{
+	struct test_ctx ctx;
+	char key[AES_TEST_KEY_SIZE];
+	char iv[AES_TEST_KEY_SIZE];
+	char clear[AES_TEST_BUFFER_SIZE];
+	char ciph[AES_TEST_BUFFER_SIZE];
+	char temp[AES_TEST_BUFFER_SIZE];
+
+	printf("Prepare session with the TA\n");
+	prepare_tee_session(&ctx);
+
+	printf("Prepare encode operation\n");
+	prepare_aes(&ctx, ENCODE);
+
+	printf("Load key in TA\n");
+	memset(key, 0xa5, sizeof(key)); /* Load some dummy value */
+	set_key(&ctx, key, AES_TEST_KEY_SIZE);
+
+	printf("Reset ciphering operation in TA (provides the initial vector)\n");
+	memset(iv, 0, sizeof(iv)); /* Load some dummy value */
+	set_iv(&ctx, iv, AES_TEST_KEY_SIZE);
+
+	printf("Encore buffer from TA\n");
+	memset(clear, 0x5a, sizeof(clear)); /* Load some dummy value */
+	cipher_buffer(&ctx, clear, ciph, AES_TEST_BUFFER_SIZE);
+
+	printf("Prepare decode operation\n");
+	prepare_aes(&ctx, DECODE);
+
+	printf("Load key in TA\n");
+	memset(key, 0xa5, sizeof(key)); /* Load some dummy value */
+	set_key(&ctx, key, AES_TEST_KEY_SIZE);
+
+	printf("Reset ciphering operation in TA (provides the initial vector)\n");
+	memset(iv, 0, sizeof(iv)); /* Load some dummy value */
+	set_iv(&ctx, iv, AES_TEST_KEY_SIZE);
+
+	printf("Decode buffer from TA\n");
+	memset(clear, 0x5a, sizeof(clear)); /* Load some dummy value */
+	cipher_buffer(&ctx, ciph, temp, AES_TEST_BUFFER_SIZE);
+
+	/* Check decoded is the clear content */
+	if (memcmp(clear, temp, AES_TEST_BUFFER_SIZE))
+		printf("Clear text and decoded text differ => ERROR\n");
+	else
+		printf("Clear text and decoded text match\n");
+
+	terminate_tee_session(&ctx);
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	aes_basic();
+	performance();
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/Android.mk
new file mode 100644
index 0000000..931f8e4
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH := $(call my-dir)
+
+local_module := 5dbac793-f574-4871-8ad3-04331ec17f24.ta
+include $(BUILD_OPTEE_MK)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/Makefile
new file mode 100644
index 0000000..406b4f8
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/Makefile
@@ -0,0 +1,13 @@
+CFG_TEE_TA_LOG_LEVEL ?= 4
+CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL)
+
+# The UUID for the Trusted Application
+BINARY=5dbac793-f574-4871-8ad3-04331ec17f24
+
+-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk
+
+ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), )
+clean:
+	@echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA'
+	@echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)'
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/aes_ta.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/aes_ta.c
new file mode 100644
index 0000000..0814464
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/aes_ta.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <inttypes.h>
+
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+
+#include <aes_ta.h>
+
+#define AES128_KEY_BIT_SIZE		128
+#define AES128_KEY_BYTE_SIZE		(AES128_KEY_BIT_SIZE / 8)
+#define AES256_KEY_BIT_SIZE		256
+#define AES256_KEY_BYTE_SIZE		(AES256_KEY_BIT_SIZE / 8)
+
+/*
+ * Ciphering context: each opened session relates to a cipehring operation.
+ * - configure the AES flavour from a command.
+ * - load key from a command (here the key is provided by the REE)
+ * - reset init vector (here IV is provided by the REE)
+ * - cipher a buffer frame (here input and output buffers are non-secure)
+ */
+struct aes_cipher {
+	uint32_t algo;			/* AES flavour */
+	uint32_t mode;			/* Encode or decode */
+	uint32_t key_size;		/* AES key size in byte */
+	TEE_OperationHandle op_handle;	/* AES ciphering operation */
+	TEE_ObjectHandle key_handle;	/* transient object to load the key */
+};
+
+/*
+ * Few routines to convert IDs from TA API into IDs from OP-TEE.
+ */
+static TEE_Result ta2tee_algo_id(uint32_t param, uint32_t *algo)
+{
+	switch (param) {
+	case TA_AES_ALGO_ECB:
+		*algo = TEE_ALG_AES_ECB_NOPAD;
+		return TEE_SUCCESS;
+	case TA_AES_ALGO_CBC:
+		*algo = TEE_ALG_AES_CBC_NOPAD;
+		return TEE_SUCCESS;
+	case TA_AES_ALGO_CTR:
+		*algo = TEE_ALG_AES_CTR;
+		return TEE_SUCCESS;
+	default:
+		EMSG("Invalid algo %u", param);
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+}
+static TEE_Result ta2tee_key_size(uint32_t param, uint32_t *key_size)
+{
+	switch (param) {
+	case AES128_KEY_BYTE_SIZE:
+	case AES256_KEY_BYTE_SIZE:
+		*key_size = param;
+		return TEE_SUCCESS;
+	default:
+		EMSG("Invalid key size %u", param);
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+}
+static TEE_Result ta2tee_mode_id(uint32_t param, uint32_t *mode)
+{
+	switch (param) {
+	case TA_AES_MODE_ENCODE:
+		*mode = TEE_MODE_ENCRYPT;
+		return TEE_SUCCESS;
+	case TA_AES_MODE_DECODE:
+		*mode = TEE_MODE_DECRYPT;
+		return TEE_SUCCESS;
+	default:
+		EMSG("Invalid mode %u", param);
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+}
+
+/*
+ * Process command TA_AES_CMD_PREPARE. API in aes_ta.h
+ *
+ * Allocate resources required for the ciphering operation.
+ * During ciphering operation, when expect client can:
+ * - update the key materials (provided by client)
+ * - reset the initial vector (provided by client)
+ * - cipher an input buffer into an output buffer (provided by client)
+ */
+static TEE_Result alloc_resources(void *session, uint32_t param_types,
+				  TEE_Param params[4])
+{
+	const uint32_t exp_param_types =
+		TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
+				TEE_PARAM_TYPE_VALUE_INPUT,
+				TEE_PARAM_TYPE_VALUE_INPUT,
+				TEE_PARAM_TYPE_NONE);
+	struct aes_cipher *sess;
+	TEE_Attribute attr;
+	TEE_Result res;
+	char *key;
+
+	/* Get ciphering context from session ID */
+	DMSG("Session %p: get ciphering resources", session);
+	sess = (struct aes_cipher *)session;
+
+	/* Safely get the invocation parameters */
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	res = ta2tee_algo_id(params[0].value.a, &sess->algo);
+	if (res != TEE_SUCCESS)
+		return res;
+
+	res = ta2tee_key_size(params[1].value.a, &sess->key_size);
+	if (res != TEE_SUCCESS)
+		return res;
+
+	res = ta2tee_mode_id(params[2].value.a, &sess->mode);
+	if (res != TEE_SUCCESS)
+		return res;
+
+	/*
+	 * Ready to allocate the resources which are:
+	 * - an operation handle, for an AES ciphering of given configuration
+	 * - a transient object that will be use to load the key materials
+	 *   into the AES ciphering operation.
+	 */
+
+	/* Free potential previous operation */
+	if (sess->op_handle != TEE_HANDLE_NULL)
+		TEE_FreeOperation(sess->op_handle);
+
+	/* Allocate operation: AES/CTR, mode and size from params */
+	res = TEE_AllocateOperation(&sess->op_handle,
+				    sess->algo,
+				    sess->mode,
+				    sess->key_size * 8);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to allocate operation");
+		sess->op_handle = TEE_HANDLE_NULL;
+		goto err;
+	}
+
+	/* Free potential previous transient object */
+	if (sess->key_handle != TEE_HANDLE_NULL)
+		TEE_FreeTransientObject(sess->key_handle);
+
+	/* Allocate transient object according to target key size */
+	res = TEE_AllocateTransientObject(TEE_TYPE_AES,
+					  sess->key_size * 8,
+					  &sess->key_handle);
+	if (res != TEE_SUCCESS) {
+		EMSG("Failed to allocate transient object");
+		sess->key_handle = TEE_HANDLE_NULL;
+		goto err;
+	}
+
+	/*
+	 * When loading a key in the cipher session, set_aes_key()
+	 * will reset the operation and load a key. But we cannot
+	 * reset and operation that has no key yet (GPD TEE Internal
+	 * Core API Specification – Public Release v1.1.1, section
+	 * 6.2.5 TEE_ResetOperation). In consequence, we will load a
+	 * dummy key in the operation so that operation can be reset
+	 * when updating the key.
+	 */
+	key = TEE_Malloc(sess->key_size, 0);
+	if (!key) {
+		res = TEE_ERROR_OUT_OF_MEMORY;
+		goto err;
+	}
+
+	TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, sess->key_size);
+
+	res = TEE_PopulateTransientObject(sess->key_handle, &attr, 1);
+	if (res != TEE_SUCCESS) {
+		EMSG("TEE_PopulateTransientObject failed, %x", res);
+		goto err;
+	}
+
+	res = TEE_SetOperationKey(sess->op_handle, sess->key_handle);
+	if (res != TEE_SUCCESS) {
+		EMSG("TEE_SetOperationKey failed %x", res);
+		goto err;
+	}
+
+	return res;
+
+err:
+	if (sess->op_handle != TEE_HANDLE_NULL)
+		TEE_FreeOperation(sess->op_handle);
+	sess->op_handle = TEE_HANDLE_NULL;
+
+	if (sess->key_handle != TEE_HANDLE_NULL)
+		TEE_FreeTransientObject(sess->key_handle);
+	sess->key_handle = TEE_HANDLE_NULL;
+
+	return res;
+}
+
+/*
+ * Process command TA_AES_CMD_SET_KEY. API in aes_ta.h
+ */
+static TEE_Result set_aes_key(void *session, uint32_t param_types,
+				TEE_Param params[4])
+{
+	const uint32_t exp_param_types =
+		TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
+				TEE_PARAM_TYPE_NONE,
+				TEE_PARAM_TYPE_NONE,
+				TEE_PARAM_TYPE_NONE);
+	struct aes_cipher *sess;
+	TEE_Attribute attr;
+	TEE_Result res;
+	uint32_t key_sz;
+	char *key;
+
+	/* Get ciphering context from session ID */
+	DMSG("Session %p: load key material", session);
+	sess = (struct aes_cipher *)session;
+
+	/* Safely get the invocation parameters */
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	key = params[0].memref.buffer;
+	key_sz = params[0].memref.size;
+
+	if (key_sz != sess->key_size) {
+		EMSG("Wrong key size %" PRIu32 ", expect %" PRIu32 " bytes",
+		     key_sz, sess->key_size);
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	/*
+	 * Load the key material into the configured operation
+	 * - create a secret key attribute with the key material
+	 *   TEE_InitRefAttribute()
+	 * - reset transient object and load attribute data
+	 *   TEE_ResetTransientObject()
+	 *   TEE_PopulateTransientObject()
+	 * - load the key (transient object) into the cihering operation
+	 *   TEE_SetOperationKey()
+	 *
+	 * TEE_SetOperationKey() requires operation to be in "initial state".
+	 * We can use TEE_ResetOperation() to reset the operation but this
+	 * api cannot be used on operation with key(s) not yet set. Hence,
+	 * when allocating the operation handle, we prevovision a dummy key.
+	 * Thus, set_key sequence always reset then set key on operation.
+	 */
+
+	TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, key_sz);
+
+	TEE_ResetTransientObject(sess->key_handle);
+	res = TEE_PopulateTransientObject(sess->key_handle, &attr, 1);
+	if (res != TEE_SUCCESS) {
+		EMSG("TEE_PopulateTransientObject failed, %x", res);
+		return res;
+	}
+
+	TEE_ResetOperation(sess->op_handle);
+	res = TEE_SetOperationKey(sess->op_handle, sess->key_handle);
+	if (res != TEE_SUCCESS) {
+		EMSG("TEE_SetOperationKey failed %x", res);
+		return res;
+	}
+
+	return res;
+}
+
+/*
+ * Process command TA_AES_CMD_SET_IV. API in aes_ta.h
+ */
+static TEE_Result reset_aes_iv(void *session, uint32_t param_types,
+				TEE_Param params[4])
+{
+	const uint32_t exp_param_types =
+		TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
+				TEE_PARAM_TYPE_NONE,
+				TEE_PARAM_TYPE_NONE,
+				TEE_PARAM_TYPE_NONE);
+	struct aes_cipher *sess;
+	size_t iv_sz;
+	char *iv;
+
+	/* Get ciphering context from session ID */
+	DMSG("Session %p: reset initial vector", session);
+	sess = (struct aes_cipher *)session;
+
+	/* Safely get the invocation parameters */
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	iv = params[0].memref.buffer;
+	iv_sz = params[0].memref.size;
+
+	/*
+	 * Init cipher operation with the initialization vector.
+	 */
+	TEE_CipherInit(sess->op_handle, iv, iv_sz);
+
+	return TEE_SUCCESS;
+}
+
+/*
+ * Process command TA_AES_CMD_CIPHER. API in aes_ta.h
+ */
+static TEE_Result cipher_buffer(void *session, uint32_t param_types,
+				TEE_Param params[4])
+{
+	const uint32_t exp_param_types =
+		TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
+				TEE_PARAM_TYPE_MEMREF_OUTPUT,
+				TEE_PARAM_TYPE_NONE,
+				TEE_PARAM_TYPE_NONE);
+	struct aes_cipher *sess;
+
+	/* Get ciphering context from session ID */
+	DMSG("Session %p: cipher buffer", session);
+	sess = (struct aes_cipher *)session;
+
+	/* Safely get the invocation parameters */
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (params[1].memref.size < params[0].memref.size) {
+		EMSG("Bad sizes: in %d, out %d", params[0].memref.size,
+						 params[1].memref.size);
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	if (sess->op_handle == TEE_HANDLE_NULL)
+		return TEE_ERROR_BAD_STATE;
+
+	/*
+	 * Process ciphering operation on provided buffers
+	 */
+	return TEE_CipherUpdate(sess->op_handle,
+				params[0].memref.buffer, params[0].memref.size,
+				params[1].memref.buffer, &params[1].memref.size);
+}
+
+TEE_Result TA_CreateEntryPoint(void)
+{
+	/* Nothing to do */
+	return TEE_SUCCESS;
+}
+
+void TA_DestroyEntryPoint(void)
+{
+	/* Nothing to do */
+}
+
+TEE_Result TA_OpenSessionEntryPoint(uint32_t __unused param_types,
+					TEE_Param __unused params[4],
+					void __unused **session)
+{
+	struct aes_cipher *sess;
+
+	/*
+	 * Allocate and init ciphering materials for the session.
+	 * The address of the structure is used as session ID for
+	 * the client.
+	 */
+	sess = TEE_Malloc(sizeof(*sess), 0);
+	if (!sess)
+		return TEE_ERROR_OUT_OF_MEMORY;
+
+	sess->key_handle = TEE_HANDLE_NULL;
+	sess->op_handle = TEE_HANDLE_NULL;
+
+	*session = (void *)sess;
+	DMSG("Session %p: newly allocated", *session);
+
+	return TEE_SUCCESS;
+}
+
+void TA_CloseSessionEntryPoint(void *session)
+{
+	struct aes_cipher *sess;
+
+	/* Get ciphering context from session ID */
+	DMSG("Session %p: release session", session);
+	sess = (struct aes_cipher *)session;
+
+	/* Release the session resources */
+	if (sess->key_handle != TEE_HANDLE_NULL)
+		TEE_FreeTransientObject(sess->key_handle);
+	if (sess->op_handle != TEE_HANDLE_NULL)
+		TEE_FreeOperation(sess->op_handle);
+	TEE_Free(sess);
+}
+
+TEE_Result TA_InvokeCommandEntryPoint(void *session,
+					uint32_t cmd,
+					uint32_t param_types,
+					TEE_Param params[4])
+{
+	switch (cmd) {
+	case TA_AES_CMD_PREPARE:
+		return alloc_resources(session, param_types, params);
+	case TA_AES_CMD_SET_KEY:
+		return set_aes_key(session, param_types, params);
+	case TA_AES_CMD_SET_IV:
+		return reset_aes_iv(session, param_types, params);
+	case TA_AES_CMD_CIPHER:
+		return cipher_buffer(session, param_types, params);
+	default:
+		EMSG("Command ID 0x%x is not supported", cmd);
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/include/aes_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/include/aes_ta.h
new file mode 100644
index 0000000..ecdddb6
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/include/aes_ta.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __AES_TA_H__
+#define __AES_TA_H__
+
+/* UUID of the AES example trusted application */
+#define TA_AES_UUID \
+	{ 0x5dbac793, 0xf574, 0x4871, \
+		{ 0x8a, 0xd3, 0x04, 0x33, 0x1e, 0xc1, 0x7f, 0x24 } }
+
+/*
+ * TA_AES_CMD_PREPARE - Allocate resources for the AES ciphering
+ * param[0] (value) a: TA_AES_ALGO_xxx, b: unused
+ * param[1] (value) a: key size in bytes, b: unused
+ * param[2] (value) a: TA_AES_MODE_ENCODE/_DECODE, b: unused
+ * param[3] unused
+ */
+#define TA_AES_CMD_PREPARE		0
+
+#define TA_AES_ALGO_ECB			0
+#define TA_AES_ALGO_CBC			1
+#define TA_AES_ALGO_CTR			2
+
+#define TA_AES_SIZE_128BIT		(128 / 8)
+#define TA_AES_SIZE_256BIT		(256 / 8)
+
+#define TA_AES_MODE_ENCODE		1
+#define TA_AES_MODE_DECODE		0
+
+/*
+ * TA_AES_CMD_SET_KEY - Allocate resources for the AES ciphering
+ * param[0] (memref) key data, size shall equal key length
+ * param[1] unused
+ * param[2] unused
+ * param[3] unused
+ */
+#define TA_AES_CMD_SET_KEY		1
+
+/*
+ * TA_AES_CMD_SET_IV - reset IV
+ * param[0] (memref) initial vector, size shall equal key length
+ * param[1] unused
+ * param[2] unused
+ * param[3] unused
+ */
+#define TA_AES_CMD_SET_IV		2
+
+/*
+ * TA_AES_CMD_CIPHER - Ciphere inut buffer into output buffer
+ * param[0] (memref) input buffer
+ * param[1] (memref) output buffer (shall be bigger than input buffer)
+ * param[2] unused
+ * param[3] unused
+ */
+#define TA_AES_CMD_CIPHER		3
+
+#endif /* __AES_TA_H */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/sub.mk
new file mode 100644
index 0000000..96c58b2
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/sub.mk
@@ -0,0 +1,2 @@
+global-incdirs-y += include
+srcs-y += aes_ta.c
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/user_ta_header_defines.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/user_ta_header_defines.h
new file mode 100644
index 0000000..9f944b8
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/aes/ta/user_ta_header_defines.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The name of this file must not be modified
+ */
+
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+#include <aes_ta.h>
+
+#define TA_UUID				TA_AES_UUID
+
+#define TA_FLAGS			TA_FLAG_EXEC_DDR
+#define TA_STACK_SIZE			(2 * 1024)
+#define TA_DATA_SIZE			(32 * 1024)
+
+#define TA_CURRENT_TA_EXT_PROPERTIES \
+    { "gp.ta.description", USER_TA_PROP_TYPE_STRING, \
+        "Example of TA using an AES sequence" }, \
+    { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } }
+
+#endif /*USER_TA_HEADER_DEFINES_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/Android.mk
new file mode 100644
index 0000000..7142a22
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/Android.mk
@@ -0,0 +1,39 @@
+ifeq ($(OPTEE_TEE_SUPPORT),true)
+###################### optee-dapc ######################
+LOCAL_PATH := $(call my-dir)
+
+OPTEE_CLIENT_EXPORT = $(LOCAL_PATH)/../../../../optee_client/out/export
+
+## include variants like TA_DEV_KIT_DIR
+## and OPTEE_BIN
+INCLUDE_FOR_BUILD_TA := false
+include $(BUILD_OPTEE_MK)
+INCLUDE_FOR_BUILD_TA :=
+
+# TA_DEV_KIT_DIR must be set to non-empty value to
+# avoid the Android build scripts complaining about
+# includes pointing outside the Android source tree.
+# This var is expected to be set when OPTEE OS built.
+# We set the default value to an invalid path.
+TA_DEV_KIT_DIR ?= ../invalid_include_path
+$(warning TA_DEV_KIT_DIR:$(TA_DEV_KIT_DIR))
+-include $(TA_DEV_KIT_DIR)/host_include/conf.mk
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DANDROID_BUILD
+LOCAL_CFLAGS += -Wall
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+
+LOCAL_SRC_FILES += host/main.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../pta/mt2712/pta_dapc/include \
+        $(LOCAL_PATH)/../../mt2712/dapc/include \
+        $(OPTEE_CLIENT_EXPORT)/include
+
+LOCAL_SHARED_LIBRARIES := libteec
+LOCAL_MODULE := optee_example_dapc
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/Makefile
new file mode 100644
index 0000000..4f37540
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/Makefile
@@ -0,0 +1,13 @@
+export V?=0
+
+# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE
+HOST_CROSS_COMPILE ?= $(CROSS_COMPILE)
+TA_CROSS_COMPILE ?= $(CROSS_COMPILE)
+
+.PHONY: all
+all:
+	$(MAKE) -C host O=$(O)/host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables
+
+.PHONY: clean
+clean:
+	$(MAKE) -C host clean
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/host/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/host/Makefile
new file mode 100644
index 0000000..02c279a
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/host/Makefile
@@ -0,0 +1,36 @@
+CC      ?= $(CROSS_COMPILE)gcc
+LD      ?= $(CROSS_COMPILE)ld
+AR      ?= $(CROSS_COMPILE)ar
+NM      ?= $(CROSS_COMPILE)nm
+OBJCOPY ?= $(CROSS_COMPILE)objcopy
+OBJDUMP ?= $(CROSS_COMPILE)objdump
+READELF ?= $(CROSS_COMPILE)readelf
+
+ifneq ($O,)
+out-dir := $O
+else
+out-dir := .
+endif
+
+OBJS = main.o
+OOBJS = $(foreach obj, $(OBJS), $(out-dir)/$(obj))
+
+CFLAGS += -Wall -I../ta/include -I$(TEEC_EXPORT)/include -I./include -I../../../pta/mt2712/pta_dapc/include -I../../../mt2712/dapc/include
+#Add/link other required libraries here
+LDADD += -lteec -L$(TEEC_EXPORT)/lib $(LDFLAGS)
+
+BINARY = $(out-dir)/optee_example_dapc
+
+.PHONY: all
+all: $(BINARY)
+
+$(BINARY): $(OOBJS)
+	$(CC) -o $@ $< $(LDADD)
+
+.PHONY: clean
+clean:
+	rm -f $(OOBJS) $(BINARY)
+
+$(out-dir)/%.o: %.c
+	mkdir -p $(dir $@);
+	$(CC) $(CFLAGS) -c $< -o $@
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/host/main.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/host/main.c
new file mode 100644
index 0000000..814746a
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/dapc/host/main.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2020, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+/* OP-TEE TEE client API (built by optee_client) */
+#include <tee_client_api.h>
+
+/* To the the UUID (found the the TA's h-file(s)) */
+#include <pta_dapc.h>
+
+/* For DAPC index */
+#include <dapc_public.h>
+
+int main(int argc, char *argv[])
+{
+	TEEC_Result res;
+	TEEC_Context ctx;
+	TEEC_Session sess;
+	TEEC_Operation op;
+	TEEC_UUID uuid = PTA_DAPC_UUID;
+	uint32_t err_origin;
+
+	/* Initialize a context connecting us to the TEE */
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
+
+	/*
+	 * Open a session to the "dapc" PTA, the PTA will print "hello
+	 * world!" in the log when the session is created.
+	 */
+	res = TEEC_OpenSession(&ctx, &sess, &uuid,
+			       TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
+			res, err_origin);
+
+	/*
+	 * Execute a function in the TA by invoking it, in this case
+	 * we're incrementing a number.
+	 *
+	 * The value of command ID part and how the parameters are
+	 * interpreted is part of the interface provided by the TA.
+	 */
+
+	/* Clear the TEEC_Operation struct */
+	memset(&op, 0, sizeof(op));
+
+	/*
+	 * Prepare the argument. Pass a value in the first parameter,
+	 * the remaining three parameters are unused.
+	 */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE,
+					 TEEC_NONE, TEEC_NONE);
+	op.params[0].value.a = 56;
+	op.params[0].value.b = 57;
+
+	/*
+	 * PTA_CMD_DAPC_TEST is the actual function in the PTA to be
+	 * called.
+	 */
+	printf("Invoking PTA to test DAPC\n");
+	printf("params[0].a is %d\n", op.params[0].value.a);
+	printf("params[0].b is %d\n", op.params[0].value.b);
+	res = TEEC_InvokeCommand(&sess, PTA_CMD_DAPC_TEST, &op,
+				 &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x",
+			res, err_origin);
+
+	/* Test PTA_CMD_DAPC_MASTER_TEST */
+	memset(&op, 0, sizeof(op));
+
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_VALUE_INOUT,
+					 TEEC_NONE, TEEC_NONE);
+	op.params[0].value.a = 8;
+	op.params[1].value.a = 1;
+
+	res = TEEC_InvokeCommand(&sess, PTA_CMD_DAPC_MASTER_TEST, &op,
+				 &err_origin);
+
+	/* Test PTA_CMD_DAPC_SLAVE_APC_TEST */
+	memset(&op, 0, sizeof(op));
+
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_VALUE_INOUT,
+					 TEEC_VALUE_INOUT, TEEC_NONE);
+	op.params[0].value.a = INFRA_AO_DEVICE_APC_AO;
+	op.params[1].value.a = 1;
+	op.params[2].value.a = 1;
+
+	res = TEEC_InvokeCommand(&sess, PTA_CMD_DAPC_SLAVE_APC_TEST, &op,
+				 &err_origin);
+	/*
+	 * We're done with the PTA, close the session and
+	 * destroy the context.
+	 *
+	 * The TA will print "Goodbye!" in the log when the
+	 * session is closed.
+	 */
+
+	TEEC_CloseSession(&sess);
+
+	TEEC_FinalizeContext(&ctx);
+
+	return 0;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/docs/TA_basics.md b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/docs/TA_basics.md
new file mode 100644
index 0000000..2e08b50
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/docs/TA_basics.md
@@ -0,0 +1,304 @@
+Basics for Development of OP-TEE Trusted Applications
+=====================================================
+
+This document show how to implement a basic trusted application for OP-TEE,
+using the OP-TEE devkit to build and sign the trusted application binary.
+
+In this document, a trusted application running in the OP-TEE os is referred
+to as a TA.
+
+### Contents
+1. [TA Minimal Source Files](#1-ta-minimal-source-files)
+2. [TA Makefile Script Basics](#2-ta-makefile-script-basics)
+3. [Android Build Environment](#3-android-build-environment)
+4. [TA Entry Points Implementation Basics](#4-ta-entry-points-implementation-basics)
+5. [TA Properties Basics](#5-ta-properties-basics)
+6. [Specific cares on TA invocation parameters](#6-specific-cares-on-ta-invocation-parameters)
+
+
+---
+# 1. TA Minimal Source Files
+
+Trusted Application Makefile must be designed to rely on OP-TEE devkit
+resources in order to successfully build the target application. The OP-TEE
+devkit is built (maybe installed) when one builds (installs) the optee_os.
+
+To build a TA, one must provide:
+
+- **Makefile**, a make script that should set some configuration variables and
+  include the devkit make script.
+
+- **sub.mk**, a make script that lists the sources to build (local source files,
+  subdirectories to parse, source file specific build directives).
+
+- **user_ta_header_defines.h**, a specific ANSI-C header file to define most of
+  the TA properties.
+
+- A implementation of at least the TA entry points, as extern functions:
+    `TA_CreateEntryPoint()`, `TA_DestroyEntryPoint()`,
+    `TA_OpenSessionEntryPoint()`, `TA_CloseSessionEntryPoint()`,
+    `TA_InvokeCommandEntryPoint()`
+
+Looking at example hello_world:
+```
+hello_world/
+├── ...
+└── ta
+    ├── Makefile                  BINARY=<uuid>
+    ├── Android.mk                Android way to invoke the Makefile
+    ├── sub.mk                    srcs-y += hello_world_ta.c
+    ├── include
+    │   └── hello_world_ta.h      Header exported to non-secure: TA commands API
+    ├── hello_world_ta.c          Implementaion of TA entry points
+    └── user_ta_header_defines.h  TA_UUID, TA_FLAGS, TA_DATA/STACK_SIZE, ...
+```
+
+---
+# 2. TA Makefile Script Basics
+
+## 2.1. Devkit Makefile Requirements
+
+The devkit make script is located in the devkit filetree at path
+**mk/ta_dev_kit.mk**.
+
+The make script supports rules `all` and `clean` to build a TA or
+a library and clean the built objects.
+
+The make script expects some configuration variables:
+
+- Variable `TA_DEV_KIT_DIR`
+
+  Base directory of the devkit. Used the devkit itself to locate its tools.
+
+- Variables `BINARY` and `LIBNAME`
+
+  `BINARY` and `LIBNAME` are exclusives.
+
+  If building a TA, `BINARY` shall provide the TA filename used to load the TA.
+  The built signed TA binary file will be named `${BINARY}.ta`.
+  In native OP-TEE, it is the TA uuid, used by tee-supplicant to identify TAs.
+
+  if building a static library (that will be later linked by a TA),
+  `LIBNAME` shall provide the name of the library. The generated library
+  binary file will be named `lib${LIBNAME}.a`
+
+- Variables `CROSS_COMPILE` and `CROSS_COMPILE32`
+
+  Cross compiler for the TA or the library source files. `CROSS_COMPILE32`
+  is optional. It allows to target AArch32 builds on AArch64 capable systems.
+  On AArch32 systems, `CROSS_COMPILE32` defaults to `CROSS_COMPILE`.
+
+Some optional configuration variables can be supported, check optee_os
+delivery. For examples:
+
+- Variable `O`
+
+  Base directory for build objects filetree. If not set, devit defaults to
+  **./out** from the TA source tree base directory.
+
+A tipical makefile to drive the build of a TA is:
+```make
+# Append specific configuration to the C source build (here log=info)
+# The UUID for the Trusted Application
+BINARY=8aaaf200-2450-11e4-abe2-0002a5d5c51b
+
+# Source the devkit make script
+include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk
+```
+
+## 2.2. Listing Source Files to Build and Build directives
+
+The make script expects that current directory contains a file `sub.mk` that
+is the entry point for listing the source files to build and other specific
+build directives.
+
+Following are examples of directive one can implement in a sub.mk make script:
+
+* `srcs-y += hello_world_ta.c`\
+  Adds **./hello_world_ta.c** from current directory to the list of the source
+  file to build and link.
+
+* `global-incdirs-y += include/`\
+  Includes path **./include/** from the current directory to the include path.
+
+* `cflags-hello_world_ta.c-y += -Wno-strict-prototypes`\
+  Adds directive `-Wno-strict-prototypes` to the build directove of
+  **./hello_world_ta.c** specific source file.
+
+* `cflags-remove-hello_world_ta.c-y += -Wno-strict-prototypes`\
+  Removes directive `-Wno-strict-prototypes` from the build directives of
+  **./hello_world_ta.c** specific source file.
+
+* `libnames += foo`\
+  Adds the static library `foo` to the list of the linker directives:
+  `-lfoo`.
+
+* `libdirs += path/to/libfoo/install/directory`\
+  Adds the directory path to the libraries pathes list. Archive file
+  **libfoo.a** is expectd in this directory.
+
+* `libdeps += path/to/greatlib/libgreatlib.a`\
+  Adds the static library binary to the TA build dependencies.
+
+---
+# 3. Android Build Environment
+
+OP-TEE devkit supports building in Android build environment. One can
+implement an Android.mk script for its TA next to the Makefile script.
+
+The Android build will parse the TA Android make script which will parse a
+devkit Android make script to locate TA build resources. Then the Android
+build will execute a `make` command to built the TA through its generic
+Makefile script.
+
+A typical Android.mk script for a TA is:
+```make
+$ cat hello_world/ta/Android.mk
+# Define base path for the TA sources filetree
+LOCAL_PATH := $(call my-dir)
+# Define the module name as the signed TA binary filename.
+local_module := 8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta
+# Include the devikt Android mak script
+include $(OPTEE_OS_DIR)/mk/aosp_optee.mk
+```
+
+---
+# 4. TA Entry Points Implementation Basics
+
+TA source code is expected to provide implemenation for the following
+functions:
+
+```c
+TEE_Result TA_CreateEntryPoint(void)
+{
+	/* Allocate some resources, init something, ... */
+	...
+
+	/* Return with a status */
+	return TEE_SUCCESS;
+}
+
+void TA_DestroyEntryPoint(void)
+{
+	/* Release resources if required before TA destruction */
+	...
+}
+
+TEE_Result TA_OpenSessionEntryPoint(uint32_t ptype,
+				    TEE_Param param[4],
+				    void **session_id_ptr)
+{
+	/* Check client identity, and alloc/init some session resources if any */
+	...
+
+	/* Return with a status */
+	return TEE_SUCCESS;
+}
+
+void TA_CloseSessionEntryPoint(void *sess_ptr)
+{
+	/* check client and handle session resource release, if any */
+	...
+}
+
+TEE_Result TA_InvokeCommandEntryPoint(void *session_id,
+				      uint32_t command_id,
+				      uint32_t parameters_type,
+				      TEE_Param parameters[4])
+{
+	/* Decode the command and process execution of the target service */
+	...
+
+	/* Return with a status */
+	return TEE_SUCCESS;
+}
+```
+
+---
+# 5. TA Properties Basics
+
+Trusted Application properties shall be defined in a specific ANSI-C header
+file named **user_ta_header_defines.h**. The header file shall define the following macros:
+
+- `TA_UUID` defines the TA uuid value
+
+- `TA_FLAGS` define some of the TA properties
+
+- `TA_STACK_SIZE` defines the RAM size to be reserved for TA stack
+
+- `TA_DATA_SIZE` defines the RAM size to be reserved for TA heap (TEE_Malloc() pool)
+
+Refer to [TA properties] to configure these macros.
+
+**user_ta_header_defines.h** file may provide the following macro:
+
+- `TA_CURRENT_TA_EXT_PROPERTIES` may define extra properties of the TA.
+
+
+Example of **user_ta_header_defines.h**:
+
+```c
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+#define TA_UUID
+	{ 0x8aaaf200, 0x2450, 0x11e4, \
+		{ 0xab, 0xe2, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} }
+
+#define TA_FLAGS			(TA_FLAG_EXEC_DDR | \
+						TA_FLAG_SINGLE_INSTANCE | \
+						TA_FLAG_MULTI_SESSION)
+#define TA_STACK_SIZE			(2 * 1024)
+#define TA_DATA_SIZE			(32 * 1024)
+
+#define TA_CURRENT_TA_EXT_PROPERTIES \
+	{ "gp.ta.description", USER_TA_PROP_TYPE_STRING, "Foo TA for some purpose." }, \
+	{ "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0100 } }
+
+#endif /* USER_TA_HEADER_DEFINES_H */
+```
+
+---
+# 6. Specific cares on TA invocation parameters
+
+GPD TEE Client APIs `TEEC_InvokeCommand()` and `TEE_OpenSession()` allow a client
+to invoke a TA with some invocation parameters: values or references to memory buffers.
+
+It is mandatory that TAs verify the parameters types before using the parameters
+themsleves.
+
+TA can rely on macro TEE_PARAM_TYPE_GET(param_type, param_index)` to get the
+type of a parameter and check its value according to the expected parameter.
+
+For example, if TA expect that command ID 0 comes with param#0 being a input
+value, param#2 being a output value, and param#3 being a in/out memory
+reference (buffer), TA should implemented the following sequence:
+
+```c
+TEE_Result handle_command_0(void *session, uint32_t cmd_id,
+			    uint32_t param_types, TEE_Param params[4])
+{
+	if ((TEE_PARAM_TYPE_GET(param_types, 0) != TEE_PARAM_TYPE_VALUE_IN) ||
+	    (TEE_PARAM_TYPE_GET(param_types, 1) != TEE_PARAM_TYPE_VALUE_OUT) ||
+	    (TEE_PARAM_TYPE_GET(param_types, 2) != TEE_PARAM_TYPE_MEMREF_INOUT) ||
+	    (TEE_PARAM_TYPE_GET(param_types, 3) != TEE_PARAM_TYPE_NONE)) {
+		return TEE_ERROR_BAD_PARAMETERS
+	}
+
+	/* process command */
+	...
+}
+
+TEE_Result TA_InvokeCommandEntryPoint(void *session, uint32_t command_id,
+				      uint32_t param_types, TEE_Param params[4])
+{
+	switch (command_id) {
+	case 0:
+		return handle_command_0(session, param_types, params);
+	default:
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+}
+```
+
+[TA properties]: ./TA_properties.md
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/docs/TA_properties.md b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/docs/TA_properties.md
new file mode 100644
index 0000000..7a705b8
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/docs/TA_properties.md
@@ -0,0 +1,140 @@
+Defining Properties of Trusted Applications
+===========================================
+
+This document is related to the trusted application examples documentation [TA basics].
+
+
+### Contents
+
+1. [TA properties defined by GPD TEE specifications](#1-ta-properties-defined-by-gpd-tee-specifications)
+2. [TA Property Flags from the OP-TEE Extensions](#2-ta-property-flags-from-the-op-tee-extensions)
+
+
+# 1. TA properties defined by GPD TEE specifications
+
+Standard TA properties must be defined through property flag in macro
+`TA_FLAGS` by **user_ta_header_defines.h**.
+
+## 1.1. Single Instance Property
+
+`"gpd.ta.singleInstance"` is a boolean property of the TA.
+
+This property defines if one instance of the TA must be created and will
+receive all open session request, or if a new specific TA instance must be
+created for each incoming open session request.
+
+OP-TEE TA flag `TA_FLAG_SINGLE_INSTANCE` sets to configuration of this
+property.
+
+The boolean property is set to `true` if `TA_FLAGS` sets bit
+`TA_FLAG_SINGLE_INSTANCE`, otherwise the boolean property is set to `false`.
+
+## 1.2. Multi-session Property
+
+`"gpd.ta.multiSession"` is a boolean property of the TA.
+
+This property defines if the TA instance can handle several sessions. If
+disabled, TA instance support only one session. In such case, if the TA
+already has a opened session, any open session request will return with a
+busy error status.
+
+This property is meaningless if TA is NOT SingleInstance.
+
+OP-TEE TA flag `TA_FLAG_MULTI_SESSION` sets to configuration of this
+property.
+
+The boolean property is set to `true` if `TA_FLAGS` sets bit
+`TA_FLAG_MULTI_SESSION`, otherwise the boolean property is set to `false`.
+
+## 1.3. Keep Alive Property
+
+`"gpd.ta.instanceKeepAlive"` is a boolean property of the TA.
+
+This property defines if the TA instance created must be destroyed or not when
+all sessions opened towards the TA are closed. If the property is enabled, TA
+instance, once created (at 1st open session request), is never removed unless
+the TEE itself is restarted (boot/reboot).
+
+This property is meaningless if TA is NOT SingleInstance.
+
+OP-TEE TA flag `TA_FLAG_INSTANCE_KEEP_ALIVE` sets to configuration of this
+property.
+
+The boolean property is set to `true` if `TA_FLAGS` sets bit
+`TA_FLAG_INSTANCE_KEEP_ALIVE`, otherwise the boolean property is set to `false`.
+
+## 1.4. Heap Size Property
+
+`"gpd.ta.dataSize"` is a 32bit integer property of the TA.
+
+This property defines the size in bytes of the TA allocation pool, in which
+`TEE_Malloc()` and friends allocate memory.
+
+The value of the property must be defined by the macro `TA_DATA_SIZE` from
+**user_ta_header_defines.h**.
+
+## 1.5. Stack Size Property
+
+`"gpd.ta.stackSize"` is a 32bit integer property of the TA.
+
+This property defines the size in bytes of the stack used for TA execution.
+
+The value of the property must be defined by the macro `TA_STACK_SIZE` from
+**user_ta_header_defines.h**.
+
+# 2. TA Property Flags from the OP-TEE Extensions
+
+## 2.1. User Mode Property Flag
+
+`TA_FLAG_USER_MODE` is a bit flag supported by `TA_FLAGS`.
+
+This property flag is currently meaningless in OP-TEE. It may be set or not
+without impact on TA execution. All OP-TEE TAs are executed in user mode/level.
+
+Because of this we do not recommend to use this flag.
+
+## 2.2. Exec-in-DDR Property Flag
+
+`TA_FLAG_EXEC_DDR` is a bit flag supported by `TA_FLAGS`.
+
+This property flag is currently meaningless in OP-TEE. Nevertheless it shall
+be set. It is a legacy property flag that aimed at targeting location for the TA
+execution, internal RAM or external DDR.
+
+Therefore all TAs must set `TA_FLAG_EXEC_DDR` in `TA_FLAGS` in their
+**user_ta_header_defines.h** header file.
+
+Note: this flag will soon be deprecated.
+
+## 2.3. Secure Data Path Support Property Flag
+
+`TA_FLAG_SECURE_DATA_PATH` is a bit flag supported by `TA_FLAGS`.
+
+This property flag claims the secure data support from the OP-TEE OS for the TA.
+Refer to the OP-TEE OS for secure data path support.
+
+TAs that do not set `TA_FLAG_SECURE_DATA_PATH` in the value of `TA_FLAGS` will
+not be able to handle memory reference invocation parameters that relate to
+secure data path buffers.
+
+## 2.4. Remap Support Property Flag
+
+`TA_FLAG_REMAP_SUPPORT` is a bit flag supported by `TA_FLAGS`.
+
+This property flag is currently meaningless in OP-TEE and therefore we
+recommend to not use this flag.
+
+Note: this flag will soon be deprecated.
+
+## 2.5. Cache maintenance Property Flag
+
+`TA_FLAG_CACHE_MAINTENANCE` is a bit flag supported by `TA_FLAGS`.
+
+This property flag claims access to the cache maintenance API for the TA:
+`TEE_CacheXxxx()`. Refer to the OP-TEE to check if cache API support is
+enabled.
+
+TAs that do not set `TA_FLAG_CACHE_MAINTENANCE` in the value of their `TA_FLAGS`
+will not be able to call the cache maintenance API.
+
+[TA basics]: ./TA_basics.md
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/Android.mk
new file mode 100644
index 0000000..1223ab2
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/Android.mk
@@ -0,0 +1,39 @@
+ifeq ($(OPTEE_TEE_SUPPORT),true)
+###################### optee-hello-world ######################
+LOCAL_PATH := $(call my-dir)
+
+OPTEE_CLIENT_EXPORT = $(LOCAL_PATH)/../../optee_client/out/export
+
+## include variants like TA_DEV_KIT_DIR
+## and OPTEE_BIN
+INCLUDE_FOR_BUILD_TA := false
+include $(BUILD_OPTEE_MK)
+INCLUDE_FOR_BUILD_TA :=
+
+# TA_DEV_KIT_DIR must be set to non-empty value to
+# avoid the Android build scripts complaining about
+# includes pointing outside the Android source tree.
+# This var is expected to be set when OPTEE OS built.
+# We set the default value to an invalid path.
+TA_DEV_KIT_DIR ?= ../invalid_include_path
+$(warning TA_DEV_KIT_DIR:$(TA_DEV_KIT_DIR))
+-include $(TA_DEV_KIT_DIR)/host_include/conf.mk
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DANDROID_BUILD
+LOCAL_CFLAGS += -Wall
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+
+LOCAL_SRC_FILES += host/main.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include \
+		$(OPTEE_CLIENT_EXPORT)/include \
+
+LOCAL_SHARED_LIBRARIES := libteec
+LOCAL_MODULE := optee_example_interrupt_gpt
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+# include $(LOCAL_PATH)/ta/Android.mk
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/CMakeLists.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/CMakeLists.txt
new file mode 100644
index 0000000..1b46b4c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/CMakeLists.txt
@@ -0,0 +1,13 @@
+project (hello_world C)
+
+set (SRC host/main.c)
+
+add_executable (${PROJECT_NAME} ${SRC})
+
+target_include_directories(${PROJECT_NAME}
+			   PRIVATE ta/include
+			   PRIVATE include)
+
+target_link_libraries (${PROJECT_NAME} PRIVATE teec)
+
+install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/Makefile
new file mode 100644
index 0000000..70f7777
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/Makefile
@@ -0,0 +1,13 @@
+export V?=0
+
+# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE
+HOST_CROSS_COMPILE ?= $(CROSS_COMPILE)
+TA_CROSS_COMPILE ?= $(CROSS_COMPILE)
+
+.PHONY: all
+all:
+	$(MAKE) -C host O=$(O)/host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables
+
+.PHONY: clean
+clean:
+	$(MAKE) -C host clean
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/host/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/host/Makefile
new file mode 100644
index 0000000..eb67a29
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/host/Makefile
@@ -0,0 +1,36 @@
+CC      ?= $(CROSS_COMPILE)gcc
+LD      ?= $(CROSS_COMPILE)ld
+AR      ?= $(CROSS_COMPILE)ar
+NM      ?= $(CROSS_COMPILE)nm
+OBJCOPY ?= $(CROSS_COMPILE)objcopy
+OBJDUMP ?= $(CROSS_COMPILE)objdump
+READELF ?= $(CROSS_COMPILE)readelf
+
+ifneq ($O,)
+out-dir := $O
+else
+out-dir := .
+endif
+
+OBJS = main.o
+OOBJS = $(foreach obj, $(OBJS), $(out-dir)/$(obj))
+
+CFLAGS += -Wall -I../ta/include -I$(TEEC_EXPORT)/include -I./include
+#Add/link other required libraries here
+LDADD += -lteec -L$(TEEC_EXPORT)/lib $(LDFLAGS)
+
+BINARY = $(out-dir)/optee_example_gpt_interrupt
+
+.PHONY: all
+all: $(BINARY)
+
+$(BINARY): $(OOBJS)
+	$(CC) -o $@ $< $(LDADD)
+
+.PHONY: clean
+clean:
+	rm -f $(OOBJS) $(BINARY)
+
+$(out-dir)/%.o: %.c
+	mkdir -p $(dir $@);
+	$(CC) $(CFLAGS) -c $< -o $@
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/host/main.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/host/main.c
new file mode 100644
index 0000000..f152353
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/host/main.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/* OP-TEE TEE client API (built by optee_client) */
+#include <tee_client_api.h>
+
+/* To the the UUID (found the the TA's h-file(s)) */
+#include <interrupt_gpt_ta.h>
+
+int main(int argc, char *argv[])
+{
+	TEEC_Result res;
+	TEEC_Context ctx;
+	TEEC_Session sess;
+	TEEC_Operation op;
+	TEEC_UUID uuid = PTA_GPT_TEST_PTA_UUID;
+	uint32_t err_origin;
+
+	/* Initialize a context connecting us to the TEE */
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
+
+	/*
+	 * Open a session to the "hello world" TA, the TA will print "hello
+	 * world!" in the log when the session is created.
+	 */
+	res = TEEC_OpenSession(&ctx, &sess, &uuid,
+			       TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
+			res, err_origin);
+
+	/*
+	 * Execute a function in the TA by invoking it, in this case
+	 * we're incrementing a number.
+	 *
+	 * The value of command ID part and how the parameters are
+	 * interpreted is part of the interface provided by the TA.
+	 */
+
+	/* Clear the TEEC_Operation struct */
+	memset(&op, 0, sizeof(op));
+
+	/*
+	 * Prepare the argument. Pass a value in the first parameter,
+	 * the remaining three parameters are unused.
+	 */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE,
+					 TEEC_NONE, TEEC_NONE);
+	op.params[0].value.a = 1;
+	op.params[0].value.b = 3;
+
+	/*
+	 * PTA_CMD_GPT_INIT is the actual function in the TA to be
+	 * called.
+	 */
+	printf("Invoking TA to enable gpt %d\n", op.params[0].value.a);
+	res = TEEC_InvokeCommand(&sess, PTA_CMD_GPT_INIT, &op,
+				 &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x",
+			res, err_origin);
+	// printf("TA incremented value to %d\n", op.params[0].value.a);
+	printf("Waited %d seconds for gpt interrupt.\n", op.params[0].value.b);
+	/*
+	 * We're done with the TA, close the session and
+	 * destroy the context.
+	 *
+	 * The TA will print "Goodbye!" in the log when the
+	 * session is closed.
+	 */
+
+	TEEC_CloseSession(&sess);
+
+	TEEC_FinalizeContext(&ctx);
+
+	return 0;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/ta/include/interrupt_gpt_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/ta/include/interrupt_gpt_ta.h
new file mode 100644
index 0000000..9541ce3
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/ta/include/interrupt_gpt_ta.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef TA_INTERRUPT_GPT_TA_H
+#define TA_INTERRUPT_GPT_TA_H
+
+
+/*
+ * This UUID is generated with uuidgen
+ * the ITU-T UUID generator at http://www.itu.int/ITU-T/asn1/uuid.html
+ */
+
+#define PTA_GPT_TEST_PTA_UUID { 0x472567ad, 0xa180, 0x402c, \
+			{ 0x50, 0x95, 0x7b, 0x4e, 0xd3, 0xe0, 0x5e, 0x83 } }
+
+/* The function IDs implemented in this TA */
+#define PTA_CMD_GPT_INIT   0
+
+#endif /*TA_INTERRUPT_GPT_TA_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/ta/user_ta_header_defines.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/ta/user_ta_header_defines.h
new file mode 100644
index 0000000..fdfa6c4
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/gpt_interrupt/ta/user_ta_header_defines.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The name of this file must not be modified
+ */
+
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+/* To get the TA UUID definition */
+#include <hello_world_ta.h>
+
+#define TA_UUID				TA_HELLO_WORLD_UUID
+
+/*
+ * TA properties: multi-instance TA, no specific attribute
+ * TA_FLAG_EXEC_DDR is meaningless but mandated.
+ */
+#define TA_FLAGS			TA_FLAG_EXEC_DDR
+
+/* Provisioned stack size */
+#define TA_STACK_SIZE			(2 * 1024)
+
+/* Provisioned heap size for TEE_Malloc() and friends */
+#define TA_DATA_SIZE			(32 * 1024)
+
+/* Extra properties (give a version id and a string name) */
+#define TA_CURRENT_TA_EXT_PROPERTIES \
+    { "gp.ta.description", USER_TA_PROP_TYPE_STRING, \
+        "Example of OP-TEE Hello World Trusted Application" }, \
+    { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } }
+
+#endif /* USER_TA_HEADER_DEFINES_H */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/Android.mk
new file mode 100644
index 0000000..7060ecb
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/Android.mk
@@ -0,0 +1,39 @@
+ifeq ($(OPTEE_TEE_SUPPORT),true)
+###################### optee-hello-world ######################
+LOCAL_PATH := $(call my-dir)
+
+OPTEE_CLIENT_EXPORT = $(LOCAL_PATH)/../../optee_client/out/export
+
+## include variants like TA_DEV_KIT_DIR
+## and OPTEE_BIN
+INCLUDE_FOR_BUILD_TA := false
+include $(BUILD_OPTEE_MK)
+INCLUDE_FOR_BUILD_TA :=
+
+# TA_DEV_KIT_DIR must be set to non-empty value to
+# avoid the Android build scripts complaining about
+# includes pointing outside the Android source tree.
+# This var is expected to be set when OPTEE OS built.
+# We set the default value to an invalid path.
+TA_DEV_KIT_DIR ?= ../invalid_include_path
+$(warning TA_DEV_KIT_DIR:$(TA_DEV_KIT_DIR))
+-include $(TA_DEV_KIT_DIR)/host_include/conf.mk
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DANDROID_BUILD
+LOCAL_CFLAGS += -Wall
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+
+LOCAL_SRC_FILES += host/main.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include \
+		$(OPTEE_CLIENT_EXPORT)/include \
+
+LOCAL_SHARED_LIBRARIES := libteec
+LOCAL_MODULE := optee_example_hello_world
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+include $(LOCAL_PATH)/ta/Android.mk
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/CMakeLists.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/CMakeLists.txt
new file mode 100644
index 0000000..1b46b4c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/CMakeLists.txt
@@ -0,0 +1,13 @@
+project (hello_world C)
+
+set (SRC host/main.c)
+
+add_executable (${PROJECT_NAME} ${SRC})
+
+target_include_directories(${PROJECT_NAME}
+			   PRIVATE ta/include
+			   PRIVATE include)
+
+target_link_libraries (${PROJECT_NAME} PRIVATE teec)
+
+install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/Makefile
new file mode 100644
index 0000000..e46c1c4
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/Makefile
@@ -0,0 +1,15 @@
+export V?=0
+
+# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE
+HOST_CROSS_COMPILE ?= $(CROSS_COMPILE)
+TA_CROSS_COMPILE ?= $(CROSS_COMPILE)
+
+.PHONY: all
+all:
+	$(MAKE) -C host O=$(O)/host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables
+	$(MAKE) -C ta O=$(O)/ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" LDFLAGS=""
+
+.PHONY: clean
+clean:
+	$(MAKE) -C host clean
+	$(MAKE) -C ta clean
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/host/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/host/Makefile
new file mode 100644
index 0000000..2785e80
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/host/Makefile
@@ -0,0 +1,35 @@
+CC      ?= $(CROSS_COMPILE)gcc
+LD      ?= $(CROSS_COMPILE)ld
+AR      ?= $(CROSS_COMPILE)ar
+NM      ?= $(CROSS_COMPILE)nm
+OBJCOPY ?= $(CROSS_COMPILE)objcopy
+OBJDUMP ?= $(CROSS_COMPILE)objdump
+READELF ?= $(CROSS_COMPILE)readelf
+
+ifneq ($O,)
+out-dir := $O
+else
+out-dir := .
+endif
+
+OBJS = main.o
+OOBJS = $(foreach obj, $(OBJS), $(out-dir)/$(obj))
+
+CFLAGS += -Wall -I../ta/include -I$(TEEC_EXPORT)/include -I./include
+#Add/link other required libraries here
+LDADD += -lteec -L$(TEEC_EXPORT)/lib $(LDFLAGS)
+
+BINARY = $(out-dir)/optee_example_hello_world
+.PHONY: all
+all: $(BINARY)
+
+$(BINARY): $(OOBJS)
+	$(CC) -o $@ $< $(LDADD)
+
+.PHONY: clean
+clean:
+	rm -f $(OOBJS) $(BINARY)
+
+$(out-dir)/%.o: %.c
+	mkdir -p $(dir $@);
+	$(CC) $(CFLAGS) -c $< -o $@
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/host/main.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/host/main.c
new file mode 100644
index 0000000..43f57ab
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/host/main.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+/* OP-TEE TEE client API (built by optee_client) */
+#include <tee_client_api.h>
+
+/* To the the UUID (found the the TA's h-file(s)) */
+#include <hello_world_ta.h>
+
+int main(int argc, char *argv[])
+{
+	TEEC_Result res;
+	TEEC_Context ctx;
+	TEEC_Session sess;
+	TEEC_Operation op;
+	TEEC_UUID uuid = TA_HELLO_WORLD_UUID;
+	uint32_t err_origin;
+
+	/* Initialize a context connecting us to the TEE */
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
+
+	/*
+	 * Open a session to the "hello world" TA, the TA will print "hello
+	 * world!" in the log when the session is created.
+	 */
+	res = TEEC_OpenSession(&ctx, &sess, &uuid,
+			       TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
+			res, err_origin);
+
+	/*
+	 * Execute a function in the TA by invoking it, in this case
+	 * we're incrementing a number.
+	 *
+	 * The value of command ID part and how the parameters are
+	 * interpreted is part of the interface provided by the TA.
+	 */
+
+	/* Clear the TEEC_Operation struct */
+	memset(&op, 0, sizeof(op));
+
+	/*
+	 * Prepare the argument. Pass a value in the first parameter,
+	 * the remaining three parameters are unused.
+	 */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE,
+					 TEEC_NONE, TEEC_NONE);
+	op.params[0].value.a = 42;
+
+	/*
+	 * TA_HELLO_WORLD_CMD_INC_VALUE is the actual function in the TA to be
+	 * called.
+	 */
+	printf("Invoking TA to increment %d\n", op.params[0].value.a);
+	res = TEEC_InvokeCommand(&sess, TA_HELLO_WORLD_CMD_INC_VALUE, &op,
+				 &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x",
+			res, err_origin);
+	printf("TA incremented value to %d\n", op.params[0].value.a);
+
+	/*
+	 * We're done with the TA, close the session and
+	 * destroy the context.
+	 *
+	 * The TA will print "Goodbye!" in the log when the
+	 * session is closed.
+	 */
+
+	TEEC_CloseSession(&sess);
+
+	TEEC_FinalizeContext(&ctx);
+
+	return 0;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/Android.mk
new file mode 100644
index 0000000..ed416e0
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/Android.mk
@@ -0,0 +1,5 @@
+LOCAL_PATH := $(call my-dir)
+
+local_module := 8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta
+$(warning local_module:$(local_module))
+include $(BUILD_OPTEE_MK)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/Makefile
new file mode 100644
index 0000000..3d2e6fc
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/Makefile
@@ -0,0 +1,13 @@
+CFG_TEE_TA_LOG_LEVEL ?= 4
+CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL)
+
+# The UUID for the Trusted Application
+BINARY=8aaaf200-2450-11e4-abe2-0002a5d5c51b
+
+-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk
+
+ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), )
+clean:
+	@echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA'
+	@echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)'
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/hello_world_ta.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/hello_world_ta.c
new file mode 100644
index 0000000..2423b30
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/hello_world_ta.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+
+#include <hello_world_ta.h>
+
+/*
+ * Called when the instance of the TA is created. This is the first call in
+ * the TA.
+ */
+TEE_Result TA_CreateEntryPoint(void)
+{
+	DMSG("has been called");
+
+	return TEE_SUCCESS;
+}
+
+/*
+ * Called when the instance of the TA is destroyed if the TA has not
+ * crashed or panicked. This is the last call in the TA.
+ */
+void TA_DestroyEntryPoint(void)
+{
+	DMSG("has been called");
+}
+
+/*
+ * Called when a new session is opened to the TA. *sess_ctx can be updated
+ * with a value to be able to identify this session in subsequent calls to the
+ * TA. In this function you will normally do the global initialization for the
+ * TA.
+ */
+TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types,
+		TEE_Param __maybe_unused params[4],
+		void __maybe_unused **sess_ctx)
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE);
+
+	DMSG("has been called");
+
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	/* Unused parameters */
+	(void)&params;
+	(void)&sess_ctx;
+
+	/*
+	 * The DMSG() macro is non-standard, TEE Internal API doesn't
+	 * specify any means to logging from a TA.
+	 */
+	IMSG("Hello World!\n");
+
+	/* If return value != TEE_SUCCESS the session will not be created. */
+	return TEE_SUCCESS;
+}
+
+/*
+ * Called when a session is closed, sess_ctx hold the value that was
+ * assigned by TA_OpenSessionEntryPoint().
+ */
+void TA_CloseSessionEntryPoint(void __maybe_unused *sess_ctx)
+{
+	(void)&sess_ctx; /* Unused parameter */
+	IMSG("Goodbye!\n");
+}
+
+static TEE_Result inc_value(uint32_t param_types,
+	TEE_Param params[4])
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE);
+
+	DMSG("has been called");
+
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	IMSG("Got value: %u from NW", params[0].value.a);
+	params[0].value.a++;
+	IMSG("Increase value to: %u", params[0].value.a);
+
+	return TEE_SUCCESS;
+}
+
+static TEE_Result dec_value(uint32_t param_types,
+	TEE_Param params[4])
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE);
+
+	DMSG("has been called");
+
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	IMSG("Got value: %u from NW", params[0].value.a);
+	params[0].value.a--;
+	IMSG("Decrease value to: %u", params[0].value.a);
+
+	return TEE_SUCCESS;
+}
+/*
+ * Called when a TA is invoked. sess_ctx hold that value that was
+ * assigned by TA_OpenSessionEntryPoint(). The rest of the paramters
+ * comes from normal world.
+ */
+TEE_Result TA_InvokeCommandEntryPoint(void __maybe_unused *sess_ctx,
+			uint32_t cmd_id,
+			uint32_t param_types, TEE_Param params[4])
+{
+	(void)&sess_ctx; /* Unused parameter */
+
+	switch (cmd_id) {
+	case TA_HELLO_WORLD_CMD_INC_VALUE:
+		return inc_value(param_types, params);
+	case TA_HELLO_WORLD_CMD_DEC_VALUE:
+		return dec_value(param_types, params);
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/include/hello_world_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/include/hello_world_ta.h
new file mode 100644
index 0000000..8e40276
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/include/hello_world_ta.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef TA_HELLO_WORLD_H
+#define TA_HELLO_WORLD_H
+
+
+/*
+ * This UUID is generated with uuidgen
+ * the ITU-T UUID generator at http://www.itu.int/ITU-T/asn1/uuid.html
+ */
+#define TA_HELLO_WORLD_UUID \
+	{ 0x8aaaf200, 0x2450, 0x11e4, \
+		{ 0xab, 0xe2, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} }
+
+/* The function IDs implemented in this TA */
+#define TA_HELLO_WORLD_CMD_INC_VALUE		0
+#define TA_HELLO_WORLD_CMD_DEC_VALUE		1
+
+#endif /*TA_HELLO_WORLD_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/sub.mk
new file mode 100644
index 0000000..957af07
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/sub.mk
@@ -0,0 +1,5 @@
+global-incdirs-y += include
+srcs-y += hello_world_ta.c
+
+# To remove a certain compiler flag, add a line like this
+#cflags-template_ta.c-y += -Wno-strict-prototypes
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/user_ta_header_defines.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/user_ta_header_defines.h
new file mode 100644
index 0000000..fdfa6c4
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hello_world/ta/user_ta_header_defines.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The name of this file must not be modified
+ */
+
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+/* To get the TA UUID definition */
+#include <hello_world_ta.h>
+
+#define TA_UUID				TA_HELLO_WORLD_UUID
+
+/*
+ * TA properties: multi-instance TA, no specific attribute
+ * TA_FLAG_EXEC_DDR is meaningless but mandated.
+ */
+#define TA_FLAGS			TA_FLAG_EXEC_DDR
+
+/* Provisioned stack size */
+#define TA_STACK_SIZE			(2 * 1024)
+
+/* Provisioned heap size for TEE_Malloc() and friends */
+#define TA_DATA_SIZE			(32 * 1024)
+
+/* Extra properties (give a version id and a string name) */
+#define TA_CURRENT_TA_EXT_PROPERTIES \
+    { "gp.ta.description", USER_TA_PROP_TYPE_STRING, \
+        "Example of OP-TEE Hello World Trusted Application" }, \
+    { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } }
+
+#endif /* USER_TA_HEADER_DEFINES_H */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/Android.mk
new file mode 100644
index 0000000..917c941
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/Android.mk
@@ -0,0 +1,24 @@
+ifeq ($(OPTEE_TEE_SUPPORT),true)
+###################### HOTP ######################
+LOCAL_PATH := $(call my-dir)
+
+OPTEE_CLIENT_EXPORT = $(LOCAL_PATH)/../../optee_client/out/export
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DANDROID_BUILD
+LOCAL_CFLAGS += -Wall
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+
+LOCAL_SRC_FILES += host/main.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include \
+		    $(OPTEE_CLIENT_EXPORT)/include
+
+LOCAL_SHARED_LIBRARIES := libteec
+LOCAL_MODULE := hotp
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+include $(LOCAL_PATH)/ta/Android.mk
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/CMakeLists.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/CMakeLists.txt
new file mode 100644
index 0000000..8d61852
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/CMakeLists.txt
@@ -0,0 +1,13 @@
+project (hotp C)
+
+set (SRC host/main.c)
+
+add_executable (${PROJECT_NAME} ${SRC})
+
+target_include_directories(${PROJECT_NAME}
+			   PRIVATE ta/include
+			   PRIVATE include)
+
+target_link_libraries (${PROJECT_NAME} PRIVATE teec)
+
+install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/Makefile
new file mode 100644
index 0000000..c6526b9
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/Makefile
@@ -0,0 +1,15 @@
+export V ?= 0
+
+# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE
+HOST_CROSS_COMPILE ?= $(CROSS_COMPILE)
+TA_CROSS_COMPILE ?= $(CROSS_COMPILE)
+
+.PHONY: all
+all:
+	$(MAKE) -C host O=$(O)/host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables
+	$(MAKE) -C ta O=$(O)/ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" LDFLAGS=""
+
+.PHONY: clean
+clean:
+	$(MAKE) -C host clean
+	$(MAKE) -C ta clean
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/README.md b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/README.md
new file mode 100644
index 0000000..4e5398c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/README.md
@@ -0,0 +1,54 @@
+# HMAC based One Time Password in OP-TEE
+[HMAC] based One Time Passwords or shortly just 'HOTP' has been around for many
+years and was initially defined in [RFC4226] back in 2005. Since then it has
+been a popular choice for doing [two factor authentication]. With the
+implementation here we are showing how one could leverage OP-TEE for generating
+such HMAC based One Time Passwords in a secure manner.
+
+## Client (OP-TEE) / Server solution
+The most common way of using HOTP is in a client/server setup, where the client
+needs to authenticate itself to be able to get access to some resources on the
+server. In those cases the server will ask for an One Time Password, the client
+will generate that and send it over to the server and if the server is OK with
+the password it will grant access to the client.
+
+Technically how it is working is that the server and the client needs to agree
+on shared key ('`K`') and also start from the same counter ('`C`'). How that is
+done in practice is another topic, but RFC4226 has some discussion about it. You
+should at least have a secure channel between the client and the server when
+sharing the key, but even better would be if you could establish a secure
+channel all the way down to the TEE (currently we have TCP/UDP support in
+OP-TEE, but not TLS).
+
+When both the server and the client knows about and use the same key and
+counter they can start doing client authentication using HOTP. In short what
+happens is that both the client and the server computes the same HOTP and the
+server compares the result of both computations (which should be the same to
+grant access). How that could work can be seen in the sequence diagram below.
+
+In the current implementation we have OP-TEE acting as a client and the server
+is a remote service running somewhere else. There is no server implemented, but
+that should be pretty easy to add in a real scenario. The important thing here
+is to be able to register the shared key in the TEE and to get HOTP values from
+the TEE on request.
+
+Since the current implementation works as a client we do not need to think about
+implementing the look-ahead synchronization window ('`s`') nor do we have to
+think about adding throttling (which prevents/slows down brute force attacks).
+
+#### Sequence diagram - Client / Server
+![Client Server based HOTP using OP-TEE](img/sequence_diagram_01.png?raw=true "Client Server based HOTP using OP-TEE")
+
+##  Client / Server (OP-TEE)?
+Even though the current implementation works as a HOTP client, there is nothing
+saying that the implementation cannot be updated to also work as the validating
+server. One could for example have a simple device (a [security token] only
+generating one time passwords) and use the TEE as a validating service to open
+up other secure services.
+
+[HMAC]: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
+<!--- The link below to mscgen.js.org should be updated when regenerating the image -->
+[link to sequence diagram]: https://mscgen.js.org/?lang=xu&msc=msc%20%7B%0A%20%20wordwraparcs%3Doff%2C%0A%20%20hscale%3D%220.95%22%2C%0A%20%20watermark%3D%22HOTP%20OP-TEE%20%22%3B%0A%0A%20%20tee%20%5Blabel%3D%22TEE%20%2F%20TA%22%2C%20linecolor%3D%22darkgreen%22%2C%20textcolor%3D%22white%22%2C%20textbgcolor%3D%22darkgreen%22%2C%20arclinecolor%3D%22darkgreen%22%2C%20arctextcolor%3D%22darkgreen%22%5D%2C%0A%20%20client%20%5Blabel%3D%22Client%22%2C%20linecolor%3D%22darkgreen%22%2C%20textcolor%3D%22white%22%2C%20textbgcolor%3D%22darkgreen%22%2C%20arclinecolor%3D%22darkgreen%22%2C%20arctextcolor%3D%22darkgreen%22%5D%2C%0A%20%20server%20%5Blabel%3D%22Server%22%2C%20linecolor%3D%22%233a5795%22%2C%20textcolor%3D%22white%22%2C%20textbgcolor%3D%22%233a5795%22%2C%20arclinecolor%3D%22%233a5795%22%2C%20arctextcolor%3D%22%233a5795%22%5D%3B%0A%20%20%0A%20%20client%20note%20client%20%5Blabel%3D%22Shared%20key%20needs%5Cnto%20be%20handled%5Cnusing%20secure%5Cnchannels%20(TLS%2FSSL)%22%5D%3B%0A%20%20client%20%3C%3D%3E%20server%20%5Blabel%3D%22Agree%20on%20shared%20key%22%5D%3B%0A%20%20client%20%3D%3E%20tee%20%5Blabel%3D%22Store%20shared%20key%22%5D%3B%0A%20%20client%20%3D%3E%20server%20%5Blabel%3D%22Login%22%5D%3B%0A%20%20server%20%3D%3E%20client%20%5Blabel%3D%22Request%20HOTP%22%5D%3B%0A%20%20client%20%3D%3E%20tee%20%5Blabel%3D%22Get%20HOTP%20from%20TEE%22%5D%3B%0A%20%20tee%20%3E%3E%20tee%20%5Blabel%3D%22Calulate%20HOTP%22%5D%3B%0A%20%20tee%20%3E%3E%20client%20%5Blabel%3D%22HOPT%20value%22%5D%3B%0A%20%20client%20%3E%3E%20server%20%5Blabel%3D%22Send%20HTOP%20value%22%5D%3B%0A%20%20server%20%3E%3E%20server%20%5Blabel%3D%22Calulate%20HOTP%20locally%22%5D%3B%0A%20%20client%20alt%20server%20%5Blabel%3D%22Client%20HOTP%20%3D%3D%20Server%20HOTP%3F%22%2C%20linecolor%3D%22grey%22%2C%20textbgcolor%3D%22white%22%5D%20%7B%0A%20%20%09%0A%20%20%20%20---%20%5Blabel%3D%22Yes%22%2C%20linecolor%3Dgrey%2C%20textbgcolor%3Dwhite%5D%3B%0A%20%20%20%20server%20%3E%3E%20client%20%5Blabel%3D%22Grant%20access%22%5D%3B%0A%20%20%20%20%0A%20%20%20%20---%20%5Blabel%3D%22No%22%2C%20linecolor%3Dgrey%2C%20textbgcolor%3Dwhite%5D%3B%0A%20%20%20%20server%20%3E%3E%20client%20%5Blabel%3D%22Access%20denied%22%5D%3B%0A%20%20%7D%3B%0A%7D
+[RFC4226]: https://www.ietf.org/rfc/rfc4226.txt
+[security token]: https://en.wikipedia.org/wiki/Security_token
+[two factor authentication]: https://en.wikipedia.org/wiki/Multi-factor_authentication
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/host/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/host/Makefile
new file mode 100644
index 0000000..51e2415
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/host/Makefile
@@ -0,0 +1,36 @@
+CC      ?= $(CROSS_COMPILE)gcc
+LD      ?= $(CROSS_COMPILE)ld
+AR      ?= $(CROSS_COMPILE)ar
+NM      ?= $(CROSS_COMPILE)nm
+OBJCOPY ?= $(CROSS_COMPILE)objcopy
+OBJDUMP ?= $(CROSS_COMPILE)objdump
+READELF ?= $(CROSS_COMPILE)readelf
+
+ifneq ($O,)
+out-dir := $O
+else
+out-dir := .
+endif
+
+OBJS = main.o
+OOBJS = $(foreach obj, $(OBJS), $(out-dir)/$(obj))
+
+CFLAGS += -Wall -I../ta/include -I./include
+CFLAGS += -I$(TEEC_EXPORT)/include
+LDADD += -lteec -L$(TEEC_EXPORT)/lib $(LDFLAGS)
+
+BINARY = $(out-dir)/optee_example_hotp
+
+.PHONY: all
+all: $(BINARY)
+
+$(BINARY): $(OOBJS)
+	$(CC) -o $@ $< $(LDADD)
+
+.PHONY: clean
+clean:
+	rm -f $(OOBJS) $(BINARY)
+
+$(out-dir)/%.o: %.c
+	mkdir -p $(dir $@);
+	$(CC) $(CFLAGS) -c $< -o $@
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/host/main.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/host/main.c
new file mode 100644
index 0000000..c816b40
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/host/main.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+/* OP-TEE TEE client API (built by optee_client) */
+#include <tee_client_api.h>
+
+/* For the UUID (found in the TA's h-file(s)) */
+#include <hotp_ta.h>
+
+struct test_value {
+	size_t count;
+	uint32_t expected;
+};
+
+/*
+ * Test values coming from the RFC4226 specification.
+ */
+struct test_value rfc4226_test_values[] = {
+	{ 0, 755224 },
+	{ 1, 287082 },
+	{ 2, 359152 },
+	{ 3, 969429 },
+	{ 4, 338314 },
+	{ 5, 254676 },
+	{ 6, 287922 },
+	{ 7, 162583 },
+	{ 8, 399871 },
+	{ 9, 520489 }
+};
+
+int main(int argc, char *argv[])
+{
+	TEEC_Context ctx;
+	TEEC_Operation op = { 0 };
+	TEEC_Result res;
+	TEEC_Session sess;
+	TEEC_UUID uuid = TA_HOTP_UUID;
+
+	int i;
+	uint32_t err_origin;
+	uint32_t hotp_value;
+
+	/*
+	 * Shared key K ("12345678901234567890"), this is the key used in
+	 * RFC4226 - Test Vectors.
+	 */
+	uint8_t K[] = {
+		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+		0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+		0x37, 0x38, 0x39, 0x30
+	};
+
+	/* Initialize a context connecting us to the TEE */
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
+
+	res = TEEC_OpenSession(&ctx, &sess, &uuid,
+			       TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
+		     res, err_origin);
+
+	/* 1. Register the shared key */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+					 TEEC_NONE, TEEC_NONE, TEEC_NONE);
+	op.params[0].tmpref.buffer = K;
+	op.params[0].tmpref.size = sizeof(K);
+
+	fprintf(stdout, "Register the shared key: %s\n", K);
+	res = TEEC_InvokeCommand(&sess, TA_HOTP_CMD_REGISTER_SHARED_KEY,
+				 &op, &err_origin);
+	if (res != TEEC_SUCCESS) {
+		fprintf(stderr, "TEEC_InvokeCommand failed with code 0x%x "
+			"origin 0x%x\n",
+			res, err_origin);
+		goto exit;
+	}
+
+	/* 2. Get HMAC based One Time Passwords */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE,
+					 TEEC_NONE, TEEC_NONE);
+
+	for (i = 0; i < sizeof(rfc4226_test_values) / sizeof(struct test_value);
+	     i++) {
+		res = TEEC_InvokeCommand(&sess, TA_HOTP_CMD_GET_HOTP, &op,
+					 &err_origin);
+		if (res != TEEC_SUCCESS) {
+			fprintf(stderr, "TEEC_InvokeCommand failed with code "
+				"0x%x origin 0x%x\n", res, err_origin);
+			goto exit;
+		}
+
+		hotp_value = op.params[0].value.a;
+		fprintf(stdout, "HOTP: %d\n", hotp_value);
+
+		if (hotp_value != rfc4226_test_values[i].expected) {
+			fprintf(stderr, "Got unexpected HOTP from TEE! "
+				"Expected: %d, got: %d\n",
+				rfc4226_test_values[i].expected, hotp_value);
+		}
+	}
+exit:
+	TEEC_CloseSession(&sess);
+	TEEC_FinalizeContext(&ctx);
+
+	return 0;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/img/sequence_diagram_01.png b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/img/sequence_diagram_01.png
new file mode 100644
index 0000000..61ecb3d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/img/sequence_diagram_01.png
Binary files differ
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/Android.mk
new file mode 100644
index 0000000..036c131
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH := $(call my-dir)
+
+local_module := 484d4143-2d53-4841-3120-4a6f636b6542.ta
+include $(BUILD_OPTEE_MK)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/Makefile
new file mode 100644
index 0000000..a719ab1
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/Makefile
@@ -0,0 +1,13 @@
+CFG_TEE_TA_LOG_LEVEL ?= 3
+CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL)
+
+# The UUID for the Trusted Application
+BINARY=484d4143-2d53-4841-3120-4a6f636b6542
+
+-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk
+
+ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), )
+clean:
+	@echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA'
+	@echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)'
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/hotp_ta.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/hotp_ta.c
new file mode 100644
index 0000000..224be60
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/hotp_ta.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#include <hotp_ta.h>
+#include <string.h>
+#include <tee_internal_api_extensions.h>
+#include <tee_internal_api.h>
+
+/* The size of a SHA1 hash in bytes. */
+#define SHA1_HASH_SIZE 20
+
+/* GP says that for HMAC SHA-1, max is 512 bits and min 80 bits. */
+#define MAX_KEY_SIZE 64 /* In bytes */
+#define MIN_KEY_SIZE 10 /* In bytes */
+
+/* Dynamic Binary Code 2 Modulo, which is 10^6 according to the spec. */
+#define DBC2_MODULO 1000000
+
+/*
+ * Currently this only supports a single key, in the future this could be
+ * updated to support multiple users, all with different unique keys (stored
+ * using secure storage).
+ */
+static uint8_t K[MAX_KEY_SIZE];
+static uint32_t K_len;
+
+/* The counter as defined by RFC4226. */
+static uint8_t counter[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
+
+/*
+ *  HMAC a block of memory to produce the authentication tag
+ *  @param key       The secret key
+ *  @param keylen    The length of the secret key (bytes)
+ *  @param in        The data to HMAC
+ *  @param inlen     The length of the data to HMAC (bytes)
+ *  @param out       [out] Destination of the authentication tag
+ *  @param outlen    [in/out] Max size and resulting size of authentication tag
+ */
+static TEE_Result hmac_sha1(const uint8_t *key, const size_t keylen,
+			    const uint8_t *in, const size_t inlen,
+			    uint8_t *out, uint32_t *outlen)
+{
+	TEE_Attribute attr = { 0 };
+	TEE_ObjectHandle key_handle = TEE_HANDLE_NULL;
+	TEE_OperationHandle op_handle = TEE_HANDLE_NULL;
+	TEE_Result res = TEE_SUCCESS;
+
+	if (keylen < MIN_KEY_SIZE || keylen > MAX_KEY_SIZE)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	if (!in || !out || !outlen)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	/*
+	 * 1. Allocate cryptographic (operation) handle for the HMAC operation.
+	 *    Note that the expected size here is in bits (and therefore times
+	 *    8)!
+	 */
+	res = TEE_AllocateOperation(&op_handle, TEE_ALG_HMAC_SHA1, TEE_MODE_MAC,
+				    keylen * 8);
+	if (res != TEE_SUCCESS) {
+		EMSG("0x%08x", res);
+		goto exit;
+	}
+
+	/*
+	 * 2. Allocate a container (key handle) for the HMAC attributes. Note
+	 *    that the expected size here is in bits (and therefore times 8)!
+	 */
+	res = TEE_AllocateTransientObject(TEE_TYPE_HMAC_SHA1, keylen * 8,
+					  &key_handle);
+	if (res != TEE_SUCCESS) {
+		EMSG("0x%08x", res);
+		goto exit;
+	}
+
+	/*
+	 * 3. Initialize the attributes, i.e., point to the actual HMAC key.
+	 *    Here, the expected size is in bytes and not bits as above!
+	 */
+	TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, keylen);
+
+	/* 4. Populate/assign the attributes with the key object */
+	res = TEE_PopulateTransientObject(key_handle, &attr, 1);
+	if (res != TEE_SUCCESS) {
+		EMSG("0x%08x", res);
+		goto exit;
+	}
+
+	/* 5. Associate the key (object) with the operation */
+	res = TEE_SetOperationKey(op_handle, key_handle);
+	if (res != TEE_SUCCESS) {
+		EMSG("0x%08x", res);
+		goto exit;
+	}
+
+	/* 6. Do the HMAC operations */
+	TEE_MACInit(op_handle, NULL, 0);
+	TEE_MACUpdate(op_handle, in, inlen);
+	res = TEE_MACComputeFinal(op_handle, NULL, 0, out, outlen);
+exit:
+	if (op_handle != TEE_HANDLE_NULL)
+		TEE_FreeOperation(op_handle);
+
+	/* It is OK to call this when key_handle is TEE_HANDLE_NULL */
+	TEE_FreeTransientObject(key_handle);
+
+	return res;
+}
+
+/*
+ * Truncate function working as described in RFC4226.
+ */
+static void truncate(uint8_t *hmac_result, uint32_t *bin_code)
+{
+	int offset = hmac_result[19] & 0xf;
+
+	*bin_code = (hmac_result[offset] & 0x7f) << 24 |
+		(hmac_result[offset+1] & 0xff) << 16 |
+		(hmac_result[offset+2] & 0xff) <<  8 |
+		(hmac_result[offset+3] & 0xff);
+
+	*bin_code %= DBC2_MODULO;
+}
+
+static TEE_Result register_shared_key(uint32_t param_types, TEE_Param params[4])
+{
+	TEE_Result res = TEE_SUCCESS;
+
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE);
+
+	if (param_types != exp_param_types) {
+		EMSG("Expected: 0x%x, got: 0x%x", exp_param_types, param_types);
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	memset(K, 0, sizeof(K));
+	memcpy(K, params[0].memref.buffer, params[0].memref.size);
+
+	K_len = params[0].memref.size;
+	DMSG("Got shared key %s (%u bytes).", K, params[0].memref.size);
+
+	return res;
+}
+
+static TEE_Result get_hotp(uint32_t param_types, TEE_Param params[4])
+{
+	TEE_Result res = TEE_SUCCESS;
+	uint32_t hotp_val;
+	uint8_t mac[SHA1_HASH_SIZE];
+	uint32_t mac_len = sizeof(mac);
+	int i;
+
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE);
+
+	if (param_types != exp_param_types) {
+		EMSG("Expected: 0x%x, got: 0x%x", exp_param_types, param_types);
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	res = hmac_sha1(K, K_len, counter, sizeof(counter), mac, &mac_len);
+
+	/* Increment the counter. */
+	for (i = sizeof(counter) - 1; i >= 0; i--) {
+		if (++counter[i])
+			break;
+	}
+
+	truncate(mac, &hotp_val);
+	DMSG("HOTP is: %d", hotp_val);
+	params[0].value.a = hotp_val;
+
+	return res;
+}
+
+/*******************************************************************************
+ * Mandatory TA functions.
+ ******************************************************************************/
+TEE_Result TA_CreateEntryPoint(void)
+{
+	return TEE_SUCCESS;
+}
+
+void TA_DestroyEntryPoint(void)
+{
+}
+
+TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types,
+				    TEE_Param __unused params[4],
+				    void __unused **sess_ctx)
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE);
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	return TEE_SUCCESS;
+}
+
+void TA_CloseSessionEntryPoint(void __unused *sess_ctx)
+{
+}
+
+TEE_Result TA_InvokeCommandEntryPoint(void __unused *sess_ctx,
+				      uint32_t cmd_id,
+				      uint32_t param_types, TEE_Param params[4])
+{
+	switch (cmd_id) {
+	case TA_HOTP_CMD_REGISTER_SHARED_KEY:
+		return register_shared_key(param_types, params);
+
+	case TA_HOTP_CMD_GET_HOTP:
+		return get_hotp(param_types, params);
+
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/include/hotp_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/include/hotp_ta.h
new file mode 100644
index 0000000..b9a787c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/include/hotp_ta.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+#ifndef __HOTP_TA_H__
+#define __HOTP_TA_H__
+
+/*
+ * This TA implements HOTP according to:
+ * https://www.ietf.org/rfc/rfc4226.txt
+ */
+
+#define TA_HOTP_UUID \
+	{ 0x484d4143, 0x2d53, 0x4841, \
+		{ 0x31, 0x20, 0x4a, 0x6f, 0x63, 0x6b, 0x65, 0x42 } }
+
+/* The function ID(s) implemented in this TA */
+#define TA_HOTP_CMD_REGISTER_SHARED_KEY	0
+#define TA_HOTP_CMD_GET_HOTP		1
+
+#endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/sub.mk
new file mode 100644
index 0000000..122c5bb
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/sub.mk
@@ -0,0 +1,2 @@
+global-incdirs-y += include
+srcs-y += hotp_ta.c
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/user_ta_header_defines.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/user_ta_header_defines.h
new file mode 100644
index 0000000..5018a69
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/hotp/ta/user_ta_header_defines.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/* The name of this file must not be modified */
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+ /* To get the TA_HOTP_UUID define */
+#include <hotp_ta.h>
+
+#define TA_UUID		TA_HOTP_UUID
+
+#define TA_FLAGS	TA_FLAG_EXEC_DDR
+
+/* Provisioned stack size */
+#define TA_STACK_SIZE	(2 * 1024)
+
+/* Provisioned heap size for TEE_Malloc() and friends */
+#define TA_DATA_SIZE	(32 * 1024)
+
+/* Extra properties (give a version id and a string name) */
+#define TA_CURRENT_TA_EXT_PROPERTIES \
+	{ "gp.ta.description", USER_TA_PROP_TYPE_STRING, \
+	  "HMAC-Based One-Time Password Algorithm (RFC4226)" }, \
+	{ "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } }
+
+#endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/Android.mk
new file mode 100644
index 0000000..72800e2
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/Android.mk
@@ -0,0 +1,24 @@
+ifeq ($(OPTEE_TEE_SUPPORT),true)
+###################### optee-random ######################
+LOCAL_PATH := $(call my-dir)
+
+OPTEE_CLIENT_EXPORT = $(LOCAL_PATH)/../../optee_client/out/export
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DANDROID_BUILD
+LOCAL_CFLAGS += -Wall
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+
+LOCAL_SRC_FILES += host/main.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include \
+		    $(OPTEE_CLIENT_EXPORT)/include
+
+LOCAL_SHARED_LIBRARIES := libteec
+LOCAL_MODULE := optee_example_random
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+include $(LOCAL_PATH)/ta/Android.mk
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/CMakeLists.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/CMakeLists.txt
new file mode 100644
index 0000000..c0f1a8a
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/CMakeLists.txt
@@ -0,0 +1,13 @@
+project (random C)
+
+set (SRC host/main.c)
+
+add_executable (${PROJECT_NAME} ${SRC})
+
+target_include_directories(${PROJECT_NAME}
+			   PRIVATE ta/include
+			   PRIVATE include)
+
+target_link_libraries (${PROJECT_NAME} PRIVATE teec)
+
+install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/Makefile
new file mode 100644
index 0000000..c6526b9
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/Makefile
@@ -0,0 +1,15 @@
+export V ?= 0
+
+# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE
+HOST_CROSS_COMPILE ?= $(CROSS_COMPILE)
+TA_CROSS_COMPILE ?= $(CROSS_COMPILE)
+
+.PHONY: all
+all:
+	$(MAKE) -C host O=$(O)/host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables
+	$(MAKE) -C ta O=$(O)/ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" LDFLAGS=""
+
+.PHONY: clean
+clean:
+	$(MAKE) -C host clean
+	$(MAKE) -C ta clean
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/host/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/host/Makefile
new file mode 100644
index 0000000..cec7fb3
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/host/Makefile
@@ -0,0 +1,36 @@
+CC      ?= $(CROSS_COMPILE)gcc
+LD      ?= $(CROSS_COMPILE)ld
+AR      ?= $(CROSS_COMPILE)ar
+NM      ?= $(CROSS_COMPILE)nm
+OBJCOPY ?= $(CROSS_COMPILE)objcopy
+OBJDUMP ?= $(CROSS_COMPILE)objdump
+READELF ?= $(CROSS_COMPILE)readelf
+
+ifneq ($O,)
+out-dir := $O
+else
+out-dir := .
+endif
+
+OBJS = main.o
+OOBJS = $(foreach obj, $(OBJS), $(out-dir)/$(obj))
+
+CFLAGS += -Wall -I../ta/include -I./include
+CFLAGS += -I$(TEEC_EXPORT)/include
+LDADD += -lteec -L$(TEEC_EXPORT)/lib $(LDFLAGS)
+
+BINARY = $(out-dir)/optee_example_random
+
+.PHONY: all
+all: $(BINARY)
+
+$(BINARY): $(OOBJS)
+	$(CC) -o $@ $< $(LDADD)
+
+.PHONY: clean
+clean:
+	rm -f $(OOBJS) $(BINARY)
+
+$(out-dir)/%.o: %.c
+	mkdir -p $(dir $@);
+	$(CC) $(CFLAGS) -c $< -o $@
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/host/main.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/host/main.c
new file mode 100644
index 0000000..65318c6
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/host/main.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+/* OP-TEE TEE client API (built by optee_client) */
+#include <tee_client_api.h>
+
+/* To the the UUID (found the the TA's h-file(s)) */
+#include <random_ta.h>
+
+int main(int argc, char *argv[])
+{
+	TEEC_Result res;
+	TEEC_Context ctx;
+	TEEC_Session sess;
+	TEEC_Operation op = { 0 };
+	TEEC_UUID uuid = TA_RANDOM_UUID;
+	uint8_t random_uuid[16] = { 0 };
+	uint32_t err_origin;
+	int i;
+
+	/* Initialize a context connecting us to the TEE */
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
+
+	/*
+	 * Open a session to the Random example TA, the TA will print "hello
+	 * world!" in the log when the session is created.
+	 */
+	res = TEEC_OpenSession(&ctx, &sess, &uuid,
+			       TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
+			res, err_origin);
+
+	/*
+	 * Execute a function in the TA by invoking it, in this case
+	 * we're incrementing a number.
+	 *
+	 * The value of command ID part and how the parameters are
+	 * interpreted is part of the interface provided by the TA.
+	 */
+
+	/* Clear the TEEC_Operation struct */
+	memset(&op, 0, sizeof(op));
+
+	/*
+	 * Prepare the argument. Pass a value in the first parameter,
+	 * the remaining three parameters are unused.
+	 */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_OUTPUT,
+					 TEEC_NONE, TEEC_NONE, TEEC_NONE);
+	op.params[0].tmpref.buffer = random_uuid;
+	op.params[0].tmpref.size = sizeof(random_uuid);
+
+	/*
+	 * TA_EXAMPLE_RANDOM_GENERATE is the actual function in the TA to be
+	 * called.
+	 */
+	printf("Invoking TA to generate random UUID... \n");
+	res = TEEC_InvokeCommand(&sess, TA_RANDOM_CMD_GENERATE,
+				 &op, &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x",
+			res, err_origin);
+
+	printf("TA generated UUID value = 0x");
+	for (i = 0; i < 16; i++)
+		printf("%x", random_uuid[i]);
+	printf("\n");
+
+	/*
+	 * We're done with the TA, close the session and
+	 * destroy the context.
+	 *
+	 * The TA will print "Goodbye!" in the log when the
+	 * session is closed.
+	 */
+
+	TEEC_CloseSession(&sess);
+
+	TEEC_FinalizeContext(&ctx);
+
+	return 0;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/Android.mk
new file mode 100644
index 0000000..edbb4ad
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH := $(call my-dir)
+
+local_module := b6c53aba-9669-4668-a7f2-205629d00f86.ta
+include $(BUILD_OPTEE_MK)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/Makefile
new file mode 100644
index 0000000..066c54e
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/Makefile
@@ -0,0 +1,13 @@
+CFG_TEE_TA_LOG_LEVEL ?= 4
+CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL)
+
+# The UUID for the Trusted Application
+BINARY=b6c53aba-9669-4668-a7f2-205629d00f86
+
+-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk
+
+ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), )
+clean:
+	@echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA'
+	@echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)'
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/include/random_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/include/random_ta.h
new file mode 100644
index 0000000..30eeead
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/include/random_ta.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __RANDOM_TA_H__
+#define __RANDOM_TA_H__
+
+/*
+ * This UUID is generated with uuidgen
+ * the ITU-T UUID generator at http://www.itu.int/ITU-T/asn1/uuid.html
+ */
+#define TA_RANDOM_UUID \
+	{ 0xb6c53aba, 0x9669, 0x4668, \
+		{ 0xa7, 0xf2, 0x20, 0x56, 0x29, 0xd0, 0x0f, 0x86} }
+
+/* The function ID implemented in this TA */
+#define TA_RANDOM_CMD_GENERATE		0
+
+#endif /* __RANDOM_TA_H__ */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/random_example_ta.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/random_example_ta.c
new file mode 100644
index 0000000..ef4696a
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/random_example_ta.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+
+#include <random_ta.h>
+
+TEE_Result TA_CreateEntryPoint(void)
+{
+	return TEE_SUCCESS;
+}
+
+void TA_DestroyEntryPoint(void)
+{
+}
+
+TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types,
+		TEE_Param __maybe_unused params[4],
+		void __maybe_unused **sess_ctx)
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE);
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	(void)&params;
+	(void)&sess_ctx;
+
+	return TEE_SUCCESS;
+}
+
+void TA_CloseSessionEntryPoint(void __maybe_unused *sess_ctx)
+{
+	(void)&sess_ctx;
+}
+
+static TEE_Result random_number_generate(uint32_t param_types,
+	TEE_Param params[4])
+{
+	uint32_t exp_param_types =
+				TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
+						TEE_PARAM_TYPE_NONE,
+						TEE_PARAM_TYPE_NONE,
+						TEE_PARAM_TYPE_NONE);
+
+	DMSG("has been called");
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	IMSG("Generating random data over %u bytes.", params[0].memref.size);
+	/*
+	 * The TEE_GenerateRandom function is a part of TEE Internal Core API,
+	 * which generates random data
+	 *
+	 * Parameters:
+	 * @ randomBuffer : Reference to generated random data
+	 * @ randomBufferLen : Byte length of requested random data
+	 */
+	TEE_GenerateRandom(params[0].memref.buffer, params[0].memref.size);
+
+	return TEE_SUCCESS;
+}
+
+TEE_Result TA_InvokeCommandEntryPoint(void __maybe_unused *sess_ctx,
+			uint32_t cmd_id,
+			uint32_t param_types, TEE_Param params[4])
+{
+	(void)&sess_ctx;
+
+	switch (cmd_id) {
+	case TA_RANDOM_CMD_GENERATE:
+		return random_number_generate(param_types, params);
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/sub.mk
new file mode 100644
index 0000000..5561015
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/sub.mk
@@ -0,0 +1,5 @@
+global-incdirs-y += include
+srcs-y += random_example_ta.c
+
+# To remove a certain compiler flag, add a line like this
+#cflags-template_ta.c-y += -Wno-strict-prototypes
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/user_ta_header_defines.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/user_ta_header_defines.h
new file mode 100644
index 0000000..37dacc1
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/random/ta/user_ta_header_defines.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The name of this file must not be modified
+ */
+
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+ /* To get the TA_RANDOM_EXAMPLE_UUID define */
+#include <random_ta.h>
+
+#define TA_UUID				TA_RANDOM_UUID
+
+/*
+ * TA properties: multi-instance TA, no specific attribute
+ * TA_FLAG_EXEC_DDR is meaningless but mandated.
+ */
+#define TA_FLAGS			TA_FLAG_EXEC_DDR
+
+/* Provisioned stack size */
+#define TA_STACK_SIZE			(2 * 1024)
+
+/* Provisioned heap size for TEE_Malloc() and friends */
+#define TA_DATA_SIZE			(32 * 1024)
+
+/* Extra properties (give a version id and a string name) */
+#define TA_CURRENT_TA_EXT_PROPERTIES \
+    { "gp.ta.description", USER_TA_PROP_TYPE_STRING, \
+      "Example of a TA that returns the output from TEE_GenerateRandom" }, \
+    { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } }
+
+#endif /* USER_TA_HEADER_DEFINES_H */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/Android.mk
new file mode 100644
index 0000000..6c1c8e7
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/Android.mk
@@ -0,0 +1,39 @@
+ifeq ($(OPTEE_TEE_SUPPORT),true)
+###################### optee-hello-world ######################
+LOCAL_PATH := $(call my-dir)
+
+OPTEE_CLIENT_EXPORT = $(LOCAL_PATH)/../../optee_client/out/export
+
+## include variants like TA_DEV_KIT_DIR
+## and OPTEE_BIN
+INCLUDE_FOR_BUILD_TA := false
+include $(BUILD_OPTEE_MK)
+INCLUDE_FOR_BUILD_TA :=
+
+# TA_DEV_KIT_DIR must be set to non-empty value to
+# avoid the Android build scripts complaining about
+# includes pointing outside the Android source tree.
+# This var is expected to be set when OPTEE OS built.
+# We set the default value to an invalid path.
+TA_DEV_KIT_DIR ?= ../invalid_include_path
+$(warning TA_DEV_KIT_DIR:$(TA_DEV_KIT_DIR))
+-include $(TA_DEV_KIT_DIR)/host_include/conf.mk
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS += -DANDROID_BUILD
+LOCAL_CFLAGS += -Wall
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+
+LOCAL_SRC_FILES += host/main.c
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include \
+		$(OPTEE_CLIENT_EXPORT)/include \
+
+LOCAL_SHARED_LIBRARIES := libteec
+LOCAL_MODULE := optee_example_vm_map
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
+
+include $(LOCAL_PATH)/ta/Android.mk
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/CMakeLists.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/CMakeLists.txt
new file mode 100644
index 0000000..a6ecb65
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/CMakeLists.txt
@@ -0,0 +1,13 @@
+project (vm_map C)
+
+set (SRC host/main.c)
+
+add_executable (${PROJECT_NAME} ${SRC})
+
+target_include_directories(${PROJECT_NAME}
+			   PRIVATE ta/include
+			   PRIVATE include)
+
+target_link_libraries (${PROJECT_NAME} PRIVATE teec)
+
+install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/Makefile
new file mode 100644
index 0000000..e46c1c4
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/Makefile
@@ -0,0 +1,15 @@
+export V?=0
+
+# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE
+HOST_CROSS_COMPILE ?= $(CROSS_COMPILE)
+TA_CROSS_COMPILE ?= $(CROSS_COMPILE)
+
+.PHONY: all
+all:
+	$(MAKE) -C host O=$(O)/host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables
+	$(MAKE) -C ta O=$(O)/ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" LDFLAGS=""
+
+.PHONY: clean
+clean:
+	$(MAKE) -C host clean
+	$(MAKE) -C ta clean
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/host/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/host/Makefile
new file mode 100644
index 0000000..a385450
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/host/Makefile
@@ -0,0 +1,35 @@
+CC      ?= $(CROSS_COMPILE)gcc
+LD      ?= $(CROSS_COMPILE)ld
+AR      ?= $(CROSS_COMPILE)ar
+NM      ?= $(CROSS_COMPILE)nm
+OBJCOPY ?= $(CROSS_COMPILE)objcopy
+OBJDUMP ?= $(CROSS_COMPILE)objdump
+READELF ?= $(CROSS_COMPILE)readelf
+
+ifneq ($O,)
+out-dir := $O
+else
+out-dir := .
+endif
+
+OBJS = main.o
+OOBJS = $(foreach obj, $(OBJS), $(out-dir)/$(obj))
+
+CFLAGS += -Wall -I../ta/include -I$(TEEC_EXPORT)/include -I./include
+#Add/link other required libraries here
+LDADD += -lteec -L$(TEEC_EXPORT)/lib $(LDFLAGS)
+
+BINARY = $(out-dir)/optee_example_vm_map
+.PHONY: all
+all: $(BINARY)
+
+$(BINARY): $(OOBJS)
+	$(CC) -o $@ $< $(LDADD)
+
+.PHONY: clean
+clean:
+	rm -f $(OOBJS) $(BINARY)
+
+$(out-dir)/%.o: %.c
+	mkdir -p $(dir $@);
+	$(CC) $(CFLAGS) -c $< -o $@
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/host/main.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/host/main.c
new file mode 100644
index 0000000..529ae8d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/host/main.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+/* OP-TEE TEE client API (built by optee_client) */
+#include <tee_client_api.h>
+
+/* To the the UUID (found the the TA's h-file(s)) */
+#include <vm_map_ta.h>
+#include <stdlib.h>
+
+TEEC_Result call_ta(uint32_t cmd, uint64_t *inout1, uint64_t *intout2, uint32_t attr)
+{
+	TEEC_Result res;
+	TEEC_Context ctx;
+	TEEC_Session sess;
+	TEEC_Operation op;
+	TEEC_UUID uuid = TA_VM_MAP_UUID;
+	uint32_t err_origin;
+
+	/* Initialize a context connecting us to the TEE */
+	res = TEEC_InitializeContext(NULL, &ctx);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
+
+	/*
+	 * Open a session to the "hello world" TA, the TA will print "hello
+	 * world!" in the log when the session is created.
+	 */
+	res = TEEC_OpenSession(&ctx, &sess, &uuid,
+			       TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
+	if (res != TEEC_SUCCESS)
+		errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
+			res, err_origin);
+
+	/*
+	 * Execute a function in the TA by invoking it, in this case
+	 * we're incrementing a number.
+	 *
+	 * The value of command ID part and how the parameters are
+	 * interpreted is part of the interface provided by the TA.
+	 */
+
+	/* Clear the TEEC_Operation struct */
+	memset(&op, 0, sizeof(op));
+
+	/*
+	 * Prepare the argument. Pass a value in the first parameter,
+	 * the remaining three parameters are unused.
+	 */
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_VALUE_INOUT,
+					 TEEC_VALUE_INPUT, TEEC_VALUE_INPUT);
+	op.params[0].value.a = *inout1;
+	op.params[1].value.a = *intout2;
+	op.params[2].value.a = attr;
+	op.params[3].value.a = *inout1>>32;
+
+	printf("TEEC_InvokeCommand cmd:%x, inout1:%x, inout2:%x\n", cmd, op.params[0].value.a,op.params[1].value.a);
+	res = TEEC_InvokeCommand(&sess, cmd, &op,
+				 &err_origin);
+	printf("TEEC_InvokeCommand res:%x, inout1:%x, inout2:%x\n", res, op.params[0].value.a,op.params[1].value.a);
+
+	TEEC_CloseSession(&sess);
+
+	TEEC_FinalizeContext(&ctx);
+
+	return res;
+}
+
+#define CHECK_RESULT(res, exp, info) \
+	do { \
+		if (res!=exp){ \
+			fprintf(stderr, "[%s:%d]Error: %s expect 0x%x bug got 0x%x.\n", __FUNCTION__, __LINE__, info, exp, res); \
+		}else{ \
+			printf("Success: %s\n", info); \
+		} \
+	}while(0)
+
+int test_all_default(){
+	TEEC_Result res = TEEC_SUCCESS;
+	uint64_t inout1 = 0x47000000;
+	uint64_t inout2 = 0x10000;
+	uint32_t attr = 1;
+	res = call_ta(TA_VM_MAP_CMD_MPU_PROTECT, &inout1, &inout2, attr);
+	CHECK_RESULT(res, TEEC_SUCCESS, "EMI MPU protect");
+	inout1 = 0x47000000;
+	inout2 = 0x1000000;
+	attr = 0;
+	res = call_ta(TA_VM_MAP_CMD_MEM_MAP_RANDOM, &inout1, &inout2, attr);
+	CHECK_RESULT(res, TEEC_SUCCESS, "EMI memory map/umap");
+	inout1 = 0x47000000;
+	inout2 = 0x1000000;
+	res = call_ta(TA_VM_MAP_CMD_MEM_MAP_TWICE, &inout1, &inout2, attr);
+	CHECK_RESULT(res, TEEC_SUCCESS, "EMI memory map twice");
+	inout1 = 0x47000000;
+	inout2 = 0x1000000;
+	res = call_ta(TA_VM_MAP_CMD_MEM_MAP_TWO_REGION, &inout1, &inout2, attr);
+	CHECK_RESULT(res, TEEC_ERROR_BAD_PARAMETERS, "EMI memory map two region");
+	inout1 = 0x47000000;
+	inout2 = 0x10000;
+	res = call_ta(TA_VM_MAP_CMD_MPU_UNPROTECT, &inout1, &inout2, attr);
+	CHECK_RESULT(res, TEEC_SUCCESS, "EMI MPU unprotect");
+}
+
+int main(int argc, char *argv[])
+{
+	int i;
+	uint32_t err_origin;
+	uint64_t start_addr=0;
+	size_t   len=0;
+	uint32_t attr=0;
+	TEEC_Result res = TEEC_SUCCESS;
+	printf("argc %d \n", argc);
+	for (i=0; i<argc; i++){
+		printf("%d is %s\n", i, argv[i]);
+	}
+	if (argc == 3){
+		start_addr = strtoull(argv[2], NULL, 0);
+		printf("Input start_addr:0x%llx\n", start_addr);
+		if (0==memcmp(argv[1],"unprotect",strlen("unprotect"))){
+            res = call_ta(TA_VM_MAP_CMD_MPU_UNPROTECT, &start_addr, &len, attr);
+			CHECK_RESULT(res, TEEC_SUCCESS, "EMI MPU unprotect");
+		}
+		if (0==memcmp(argv[1],"unmap",strlen("unmap"))){
+            res = call_ta(TA_VM_MAP_CMD_MEM_UNMAP, &start_addr, &len, attr);
+			CHECK_RESULT(res, TEEC_SUCCESS, "EMI memory map unmap");
+		}
+	}else if (argc == 5){
+		start_addr = strtoull(argv[2], NULL, 0);
+		len = strtoul(argv[3], NULL, 0);
+		attr = strtoul(argv[4], NULL, 0);
+		printf("Input start_addr:0x%llx\n", start_addr);
+		printf("Input start_addr:0x%llx len:0x%llx, attr:0x%x\n", start_addr, len, attr);
+		if (0==memcmp(argv[1],"protect",strlen("protect"))){
+            res = call_ta(TA_VM_MAP_CMD_MPU_PROTECT, &start_addr, &len, attr);
+			CHECK_RESULT(res, TEEC_SUCCESS, "EMI MPU protect");
+		}
+		if (0==memcmp(argv[1],"map",strlen("map"))){
+            res = call_ta(TA_VM_MAP_CMD_MEM_MAP, &start_addr, &len, attr);
+			CHECK_RESULT(res, TEEC_SUCCESS, "");
+		}
+		if (0==memcmp(argv[1],"simple",strlen("simple"))){
+            res = call_ta(TA_VM_MAP_CMD_MEM_MAP_SIMPLE, &start_addr, &len, attr);
+			CHECK_RESULT(res, TEEC_SUCCESS, "");
+		}
+	}else{
+		test_all_default();
+	}
+
+	return 0;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/Android.mk
new file mode 100644
index 0000000..7828169
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/Android.mk
@@ -0,0 +1,5 @@
+LOCAL_PATH := $(call my-dir)
+
+local_module := 86c1e3c4-c271-d3b4-22fe-ab50ee17c8a3.ta
+$(warning local_module:$(local_module))
+include $(BUILD_OPTEE_MK)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/Makefile
new file mode 100644
index 0000000..db0e3d2
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/Makefile
@@ -0,0 +1,13 @@
+CFG_TEE_TA_LOG_LEVEL ?= 4
+CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL)
+
+# The UUID for the Trusted Application
+BINARY=86c1e3c4-c271-d3b4-22fe-ab50ee17c8a3
+
+-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk
+
+ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), )
+clean:
+	@echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA'
+	@echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)'
+endif
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/include/vm_map_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/include/vm_map_ta.h
new file mode 100644
index 0000000..2aac99f
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/include/vm_map_ta.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef TA_VM_MAP_H
+#define TA_VM_MAP_H
+
+
+/*
+ * This UUID is generated with uuidgen
+ * the ITU-T UUID generator at http://www.itu.int/ITU-T/asn1/uuid.html
+ */
+#define TA_VM_MAP_UUID \
+	{0x86c1e3c4, 0xc271, 0xd3b4, \
+	    { 0x22,0xfe,0xab, 0x50, 0xee, 0x17, 0xc8, 0xa3 } }
+
+/* The function IDs implemented in this TA */
+#define TA_VM_MAP_CMD_MPU			  0
+#define TA_VM_MAP_CMD_MPU_PROTECT     1
+#define TA_VM_MAP_CMD_MPU_UNPROTECT   2
+#define TA_VM_MAP_CMD_MAP_MEM         5
+#define TA_VM_MAP_CMD_MEM_MAP_RANDOM  6
+#define TA_VM_MAP_CMD_MEM_MAP_TWICE   7
+#define TA_VM_MAP_CMD_MEM_MAP_TWO_REGION   8
+#define TA_VM_MAP_CMD_MEM_MAP		9
+#define TA_VM_MAP_CMD_MEM_UNMAP     10
+#define TA_VM_MAP_CMD_MEM_MAP_SIMPLE     11
+#endif /*TA_VM_MAP_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/sub.mk
new file mode 100644
index 0000000..11b346f
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/sub.mk
@@ -0,0 +1,5 @@
+global-incdirs-y += include
+srcs-y += vm_map_ta.c
+
+# To remove a certain compiler flag, add a line like this
+#cflags-template_ta.c-y += -Wno-strict-prototypes
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/user_ta_header_defines.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/user_ta_header_defines.h
new file mode 100644
index 0000000..9cb062b
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/user_ta_header_defines.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016-2017, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The name of this file must not be modified
+ */
+
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+/* To get the TA UUID definition */
+#include <vm_map_ta.h>
+
+#define TA_UUID				TA_VM_MAP_UUID
+
+/*
+ * TA properties: multi-instance TA, no specific attribute
+ * TA_FLAG_EXEC_DDR is meaningless but mandated.
+ */
+#define TA_FLAGS			TA_FLAG_EXEC_DDR
+
+/* Provisioned stack size */
+#define TA_STACK_SIZE			(2 * 1024)
+
+/* Provisioned heap size for TEE_Malloc() and friends */
+#define TA_DATA_SIZE			(32 * 1024)
+
+/* Extra properties (give a version id and a string name) */
+#define TA_CURRENT_TA_EXT_PROPERTIES \
+    { "gp.ta.description", USER_TA_PROP_TYPE_STRING, \
+        "Example of OP-TEE Hello World Trusted Application" }, \
+    { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } }
+
+#endif /* USER_TA_HEADER_DEFINES_H */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/vm_map_ta.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/vm_map_ta.c
new file mode 100644
index 0000000..0ee060e
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_examples/vm_map/ta/vm_map_ta.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <assert.h>
+#include <vm_map_ta.h>
+#include "string.h"
+/*
+ * Called when the instance of the TA is created. This is the first call in
+ * the TA.
+ */
+TEE_Result TA_CreateEntryPoint(void)
+{
+	DMSG("has been called");
+
+	return TEE_SUCCESS;
+}
+
+/*
+ * Called when the instance of the TA is destroyed if the TA has not
+ * crashed or panicked. This is the last call in the TA.
+ */
+void TA_DestroyEntryPoint(void)
+{
+	DMSG("has been called");
+}
+
+/*
+ * Called when a new session is opened to the TA. *sess_ctx can be updated
+ * with a value to be able to identify this session in subsequent calls to the
+ * TA. In this function you will normally do the global initialization for the
+ * TA.
+ */
+TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types,
+		TEE_Param __maybe_unused params[4],
+		void __maybe_unused **sess_ctx)
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE,
+						   TEE_PARAM_TYPE_NONE);
+
+	DMSG("has been called");
+
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	/* Unused parameters */
+	(void)&params;
+	(void)&sess_ctx;
+
+	/*
+	 * The DMSG() macro is non-standard, TEE Internal API doesn't
+	 * specify any means to logging from a TA.
+	 */
+	IMSG("Hello World!\n");
+
+	/* If return value != TEE_SUCCESS the session will not be created. */
+	return TEE_SUCCESS;
+}
+
+/*
+ * Called when a session is closed, sess_ctx hold the value that was
+ * assigned by TA_OpenSessionEntryPoint().
+ */
+void TA_CloseSessionEntryPoint(void __maybe_unused *sess_ctx)
+{
+	(void)&sess_ctx; /* Unused parameter */
+	IMSG("Goodbye!\n");
+}
+
+void dbg_dump(uint8_t *buf, size_t buf_len)
+{
+	int i=0;
+	DMSG("size:%zd", buf_len);
+	for(i=0; i<buf_len/8; i++){
+		DMSG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", buf[i*8], buf[i*8+1], buf[i*8+2], buf[i*8+3], buf[i*8+4], buf[i*8+5], buf[i*8+6], buf[i*8+7]);
+	}
+	for(i*=8; i<buf_len; i++){
+		DMSG("0x%02x", buf[i]);
+	}
+}
+
+#define RANDOM_BUF_LEN  128
+#define MAX_RW_LEN      0x200000
+TEE_Result mem_rw_test(uint8_t* start, size_t len)
+{
+	len = len>MAX_RW_LEN ? MAX_RW_LEN : len;
+	IMSG("test range:%p, len:%d", start, len);
+	uint8_t randomBuffer[RANDOM_BUF_LEN];
+	TEE_GenerateRandom(randomBuffer, RANDOM_BUF_LEN);
+	// dbg_dump(randomBuffer, RANDOM_BUF_LEN);
+	int i = 0;
+	size_t i_len = len;
+	i_len = (len/RANDOM_BUF_LEN)*RANDOM_BUF_LEN;
+	for(i=0; i<i_len; i+=RANDOM_BUF_LEN){
+		memcpy(start+i, randomBuffer, RANDOM_BUF_LEN);
+		if (memcmp(start+i, randomBuffer, RANDOM_BUF_LEN)){
+			EMSG("memory rw test fail at 0x%x.", start+i);
+			EMSG("Read:");
+			dbg_dump(start+i, RANDOM_BUF_LEN);
+			EMSG("Expect:");
+			dbg_dump(randomBuffer, RANDOM_BUF_LEN);
+			return -1;
+		}
+	}
+	return TEE_SUCCESS;
+}
+
+TEE_Result mem_rw_rand_pos_test(uint8_t* start, size_t len)
+{
+	DMSG("test range:%p, len:%d", start, len);
+	if (len<0x100000){
+		return mem_rw_test(start, len);
+	}
+	int i = 0;
+	size_t rand_pos;
+	uint8_t* new_start=start;
+	size_t new_len;
+	size_t rest_len;
+	TEE_Result res=TEE_SUCCESS;
+	for(i=0; i<10; i++){
+		TEE_GenerateRandom(&rand_pos, sizeof(rand_pos));
+		rand_pos = rand_pos%len;
+		DMSG("Generated rand position:%x", rand_pos);
+		new_start = start+rand_pos;
+		rest_len = (start+len)-new_start;
+		new_len = rand_pos & (MAX_RW_LEN-1);
+		new_len = new_len > len ? new_len%len : new_len;
+		new_len = new_len > rest_len ? rest_len : new_len;
+		res = mem_rw_test(new_start, new_len);
+		if (res!=TEE_SUCCESS){
+			break;
+		}
+	}
+	return res;
+}
+
+static TEE_Result map_mem(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc;
+	uint64_t va;
+	rc = TEE_MapPhysicalMemory(0x47000000, 0x1000000, 0, &va);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va);
+	DMSG("Read back va address value:%x", *(uint64_t*)va);
+	mem_rw_test((uint8_t*)va, 0x1000000);
+	rc = TEE_UnmapPhysicalMemory(va);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va);
+	// This should abort.
+	// DMSG("Read back va address value:%x", *(uint64_t*)va);
+	return rc;
+}
+
+void get_mem_para(uint32_t param_types, TEE_Param params[4], uint64_t* start, size_t* len, uint32_t* attr)
+{
+	uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT,
+						   TEE_PARAM_TYPE_VALUE_INOUT,
+						   TEE_PARAM_TYPE_VALUE_INPUT,
+						   TEE_PARAM_TYPE_VALUE_INPUT);
+
+	DMSG("has been called");
+
+	if (param_types != exp_param_types)
+		return TEE_ERROR_BAD_PARAMETERS;
+	DMSG("0: 0x%x 1:0x%x 2:0x%x, 3:0x%x", params[0].value.a, params[1].value.a, params[2].value.a, params[3].value.a);
+	uint64_t tmp = (uint64_t)(params[3].value.a)<<32;
+	*start = tmp | params[0].value.a;
+	*len   = params[1].value.a;
+	*attr  = params[2].value.a;
+	DMSG("start addr: 0x%llx, len:%d, attr:%x", *start, *len, *attr);
+}
+
+static TEE_Result mpu_test(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc;
+	uint64_t va;
+	rc = TEE_EMIMPUProtect(0x47000000, 0x10000, 1);
+	DMSG("TEE_EMIMPUProtect res: %x", rc);
+
+	rc = TEE_EMIMPUUnprotect(0x47000000);
+	DMSG("TEE_EMIMPUUnprotect res: %x", rc);
+	return rc;
+}
+
+static TEE_Result mpu_protect_test(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc;
+	uint64_t pa;
+	size_t len;
+	uint32_t attr;
+	get_mem_para(param_types, params, &pa, &len, &attr);
+	rc = TEE_EMIMPUProtect(pa, len, attr);
+	DMSG("TEE_EMIMPUProtect res: %x", rc);
+	return rc;
+}
+
+
+static TEE_Result mpu_unprotect_test(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc;
+	uint64_t pa;
+	size_t len;
+	uint32_t attr;
+	get_mem_para(param_types, params, &pa, &len, &attr);
+	rc = TEE_EMIMPUUnprotect(pa);
+	DMSG("TEE_EMIMPUUnprotect res: %x", rc);
+	return rc;
+}
+
+static TEE_Result mem_map_random_test(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc;
+	uint64_t pa;
+	size_t len;
+	uint32_t attr;
+	get_mem_para(param_types, params, &pa, &len, &attr);
+	uint64_t va;
+	rc = TEE_MapPhysicalMemory(pa, len, attr, &va);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va);
+	rc = mem_rw_rand_pos_test(va, len);
+	DMSG("mem_rw_rand_pos_test res: %x", rc);
+	if (rc){
+		return rc;
+	}
+	rc = TEE_UnmapPhysicalMemory(va);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va);
+	return rc;
+}
+
+static TEE_Result mem_map_simple_test(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc;
+	uint64_t pa;
+	size_t len;
+	uint32_t attr;
+	int i =0;
+	get_mem_para(param_types, params, &pa, &len, &attr);
+	uint64_t va;
+	uint32_t* va_off;
+	uint32_t* va_a;
+	rc = TEE_MapPhysicalMemory(pa, len, attr, &va);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va);
+	va_a = (uint32_t*)va;
+	for (i=0; i<64; i++){
+		va_a[i] = i;
+	}
+	for (i=0; i<64; i++){
+		DMSG("addr: %p, val:%d", (&va_a[i]), va_a[i]);
+	}
+    va_off = va_a+64;
+	for (i=0; i<64; i++){
+		DMSG("addr: %p, val:%d", (&va_off[i]), va_off[i]);
+	}
+	return rc;
+}
+
+static TEE_Result mem_map_test(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc;
+	uint64_t pa;
+	size_t len;
+	uint32_t attr;
+	get_mem_para(param_types, params, &pa, &len, &attr);
+	uint64_t va;
+	DMSG("TEE_MapPhysicalMemory pa: %llx", pa);
+	rc = TEE_MapPhysicalMemory(pa, len, attr, &va);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va);
+	rc = mem_rw_rand_pos_test(va, len);
+	DMSG("mem_rw_rand_pos_test res: %x", rc);
+	return rc;
+}
+
+static TEE_Result mem_unmap_test(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc;
+	uint64_t va;
+	size_t len;
+	uint32_t attr;
+	get_mem_para(param_types, params, &va, &len, &attr);
+	rc = TEE_UnmapPhysicalMemory(va);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va);
+	return rc;
+}
+
+static TEE_Result mem_map_twice_test(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc, rc0;
+	uint64_t pa;
+	size_t len;
+	uint32_t attr;
+	get_mem_para(param_types, params, &pa, &len, &attr);
+	uint64_t va1;
+	uint64_t va2;
+	size_t len1 = len/2;
+
+	rc = TEE_MapPhysicalMemory(pa, len1, attr, &va1);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va1);
+	rc = mem_rw_rand_pos_test(va1, len1);
+	DMSG("mem_rw_rand_pos_test res: %x", rc);
+	if (rc){
+		return rc;
+	}
+	rc = TEE_UnmapPhysicalMemory(va1);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va1);
+	//
+	rc = TEE_MapPhysicalMemory(pa+len1, len1, attr, &va2);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va2);
+	rc = mem_rw_rand_pos_test(va2, len1);
+	DMSG("mem_rw_rand_pos_test res: %x", rc);
+	if (rc){
+		return rc;
+	}
+	rc = TEE_UnmapPhysicalMemory(va2);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va2);
+	return rc;
+}
+static TEE_Result mem_map_two_region(uint32_t param_types,
+	TEE_Param params[4])
+{
+	DMSG("has been called");
+	TEE_Result rc, rc0;
+	uint64_t pa;
+	size_t len;
+	uint32_t attr;
+	get_mem_para(param_types, params, &pa, &len, &attr);
+	uint64_t va1;
+	uint64_t va2;
+	size_t len1 = len/2;
+
+	rc = TEE_MapPhysicalMemory(pa, len1, attr, &va1);
+	DMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc, va1);
+	rc0 = TEE_MapPhysicalMemory(pa+len1, len1, attr, &va2);
+	//The seconde map should be fail.
+	EMSG("TEE_MapPhysicalMemory res: %x, va: %p", rc0, va2);
+
+	rc = TEE_UnmapPhysicalMemory(va1);
+	DMSG("TEE_UnmapPhysicalMemory res: %x, va: %p", rc, va1);
+	return rc0;
+}
+
+/*
+ * Called when a TA is invoked. sess_ctx hold that value that was
+ * assigned by TA_OpenSessionEntryPoint(). The rest of the paramters
+ * comes from normal world.
+ */
+TEE_Result TA_InvokeCommandEntryPoint(void __maybe_unused *sess_ctx,
+			uint32_t cmd_id,
+			uint32_t param_types, TEE_Param params[4])
+{
+	(void)&sess_ctx; /* Unused parameter */
+
+	switch (cmd_id) {
+	case TA_VM_MAP_CMD_MPU:
+		return mpu_test(param_types, params);
+	case TA_VM_MAP_CMD_MPU_PROTECT:
+		return mpu_protect_test(param_types, params);
+	case TA_VM_MAP_CMD_MPU_UNPROTECT:
+		return mpu_unprotect_test(param_types, params);
+	case TA_VM_MAP_CMD_MAP_MEM:
+		return map_mem(param_types, params);
+	case TA_VM_MAP_CMD_MEM_MAP_RANDOM:
+		return mem_map_random_test(param_types, params);
+	case TA_VM_MAP_CMD_MEM_MAP_TWICE:
+		return mem_map_twice_test(param_types, params);
+	case TA_VM_MAP_CMD_MEM_MAP_TWO_REGION:
+		return mem_map_two_region(param_types, params);
+	case TA_VM_MAP_CMD_MEM_MAP:
+		return mem_map_test(param_types, params);
+	case TA_VM_MAP_CMD_MEM_UNMAP:
+		return mem_unmap_test(param_types, params);
+	case TA_VM_MAP_CMD_MEM_MAP_SIMPLE:
+		return mem_map_simple_test(param_types, params);
+	default:
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/Android.mk
new file mode 100644
index 0000000..6361f9b
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/Android.mk
@@ -0,0 +1,2 @@
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/LICENSE b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/LICENSE
new file mode 100644
index 0000000..8e33c9f
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/LICENSE
@@ -0,0 +1,2 @@
+Different modules may have different LICENSE.

+Please reference LICENSE file for each module under current folder
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/Makefile
new file mode 100644
index 0000000..a91119d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/Makefile
@@ -0,0 +1,36 @@
+export V ?= 0
+
+LIBDIR := $(LIBDIR)
+BINDIR := $(BINDIR)
+INCDIR := $(INCDIR)
+TADIR := $(TADIR)
+
+SERVICE_LIST := $(subst /,,$(dir $(wildcard */Makefile)))
+
+.PHONY: all
+all: services prepare-for-rootfs
+
+.PHONY: clean
+clean: services-clean prepare-for-rootfs-clean
+
+services:
+	@for service in $(SERVICE_LIST); do \
+		$(MAKE) -C $$service CROSS_COMPILE="$(HOST_CROSS_COMPILE)" || exit -1; \
+	done
+
+services-clean:
+	@for service in $(SERVICE_LIST); do \
+		$(MAKE) -C $$service clean || exit -1; \
+	done
+
+prepare-for-rootfs: services
+	@echo "Nothing to do"
+
+prepare-for-rootfs-clean:
+	@rm -rf $(TA_OUTPUT_DIR)
+
+.PHONY: install
+install:
+	@for service in $(SERVICE_LIST); do \
+		$(MAKE) -C $$service install LIBDIR="${LIBDIR}" BINDIR="${BINDIR}" INCDIR="${INCDIR}" TADIR="$(TADIR)" || exit -1; \
+	done
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/Android.mk
new file mode 100644
index 0000000..92c855d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/LICENSE b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/LICENSE
new file mode 100644
index 0000000..12e3c07
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/LICENSE
@@ -0,0 +1,27 @@
+Unless it has its own copyright/license embedded in its body, each source file
+is subject to the following license terms:
+
+Copyright (c) 2018, Linaro Limited
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/Makefile
new file mode 100644
index 0000000..cd771ad
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/Makefile
@@ -0,0 +1,24 @@
+export V ?= 0
+
+# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE
+HOST_CROSS_COMPILE ?= $(CROSS_COMPILE)
+TA_CROSS_COMPILE ?= $(CROSS_COMPILE)
+LIBDIR ?= $(LIBDIR)
+BINDIR ?= $(BINDIR)
+BINDIR ?= $(INCDIR)
+TADIR ?= $(TADIR)
+
+.PHONY: all
+all:
+	$(MAKE) -C host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables
+	$(MAKE) -C ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" LDFLAGS=""
+
+.PHONY: clean
+clean:
+	$(MAKE) -C host clean
+	$(MAKE) -C ta clean
+
+.PHONY: install
+install:
+	$(MAKE) -C host install LIBDIR="$(LIBDIR)" BINDIR="$(BINDIR)" INCDIR="$(INCDIR)"
+	$(MAKE) -C ta install TADIR="$(TADIR)"
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/README.md b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/README.md
new file mode 100644
index 0000000..ff04284
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/README.md
@@ -0,0 +1,8 @@
+# OP-TEE TA/Library for Secure Key Services (PKCS#11)
+
+This git repository contains both the Trusted Application and the client
+for the OP-TEE Secure Key Services (PKCS#11).
+
+Code is based on the current work-in-progress implementation started by
+Etienne Carriere <etienne.carriere@linaro.org>, which can be found at
+https://github.com/OP-TEE/optee_os/pull/2342.
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/config.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/config.mk
new file mode 100644
index 0000000..1280f8e
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/config.mk
@@ -0,0 +1,6 @@
+# Default output directory.
+# May be absolute, or relative to the optee_client source directory.
+O               ?= out
+
+# To be used instead of $(O) in sub-directories
+OO := $(if $(filter /%,$(O)),$(O),$(CURDIR)/../$(O))
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/flags.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/flags.mk
new file mode 100644
index 0000000..c2f0e1c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/flags.mk
@@ -0,0 +1,32 @@
+#########################################################################
+# COMMON COMPILATION FLAGS                                              #
+#########################################################################
+
+CROSS_COMPILE   ?= arm-linux-gnueabihf-
+CC              ?= $(CROSS_COMPILE)gcc
+AR		?= $(CROSS_COMPILE)ar
+
+CFLAGS          := -Wall -Wbad-function-cast -Wcast-align \
+		   -Werror-implicit-function-declaration -Wextra \
+		   -Wfloat-equal -Wformat-nonliteral -Wformat-security \
+		   -Wformat=2 -Winit-self -Wmissing-declarations \
+		   -Wmissing-format-attribute -Wmissing-include-dirs \
+		   -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs \
+		   -Wpointer-arith -Wshadow -Wstrict-prototypes \
+		   -Wswitch-default -Wunsafe-loop-optimizations \
+		   -Wwrite-strings -D_FILE_OFFSET_BITS=64
+ifeq ($(CFG_WERROR),y)
+CFLAGS		+= -Werror
+endif
+CFLAGS          += -c -fPIC
+
+DEBUG       ?= 0
+ifeq ($(DEBUG), 1)
+CFLAGS          += -DDEBUG -O0 -g
+endif
+
+RM              := rm -f
+
+define rmdir
+if [ -d "$(1)" ] ; then rmdir --ignore-fail-on-non-empty $(1) ; fi
+endef
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/Android.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/Android.mk
new file mode 100644
index 0000000..bfee020
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/Android.mk
@@ -0,0 +1,52 @@
+# Copyright 2006 The Android Open Source Project
+###############################################################################
+LOCAL_PATH:= $(call my-dir)
+###############################################################################
+
+## include variants like TA_DEV_KIT_DIR
+## and OPTEE_BIN
+INCLUDE_FOR_BUILD_TA := false
+include $(BUILD_OPTEE_MK)
+INCLUDE_FOR_BUILD_TA :=
+
+VERSION = $(shell git describe --always --dirty=-dev 2>/dev/null || echo Unknown)
+
+# TA_DEV_KIT_DIR must be set to non-empty value to
+# avoid the Android build scripts complaining about
+# includes pointing outside the Android source tree.
+# This var is expected to be set when OPTEE OS built.
+# We set the default value to an invalid path.
+TA_DEV_KIT_DIR ?= ../invalid_include_path
+
+-include $(TA_DEV_KIT_DIR)/host_include/conf.mk
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := src/pkcs11_api.c \
+				src/ck_debug.c \
+				src/ck_helpers.c \
+				src/invoke_ta.c \
+				src/pkcs11_token.c \
+				src/serializer.c \
+				src/serialize_ck.c \
+				src/pkcs11_processing.c
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS += -D_GNU_SOURCE -fPIC
+
+LOCAL_SHARED_LIBRARIES := libteec
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(OPTEE_BIN)
+LOCAL_ADDITIONAL_DEPENDENCIES += fd02c9da-306c-48c7-a49c-bbd827ae86ee.ta
+
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+
+LOCAL_MODULE := libsks
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(LOCAL_PATH)/../ta/ta.mk
+
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/CMakeLists.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/CMakeLists.txt
new file mode 100644
index 0000000..40ce003
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/CMakeLists.txt
@@ -0,0 +1,76 @@
+project(sks C)
+
+set(PROJECT_VERSION "1.0.0")
+
+################################################################################
+# Packages
+################################################################################
+find_package(Threads REQUIRED)
+if(NOT THREADS_FOUND)
+	message(FATAL_ERROR "Threads not found")
+endif()
+
+include(GNUInstallDirs)
+
+################################################################################
+# Source files
+################################################################################
+set (SRC
+	src/pkcs11_api.c
+	src/ck_debug.c
+	src/ck_helpers.c
+	src/invoke_ta.c
+	src/pkcs11_token.c
+	src/serializer.c
+	src/serialize_ck.c
+	src/pkcs11_processing.c
+)
+
+################################################################################
+# Built library
+################################################################################
+add_library (sks SHARED ${SRC})
+
+set_target_properties (sks PROPERTIES
+	VERSION ${PROJECT_VERSION}
+	SOVERSION ${PROJECT_NAME}
+)
+
+################################################################################
+# Flags always set
+################################################################################
+target_compile_definitions (sks
+	PRIVATE -D_GNU_SOURCE
+	PRIVATE -DBINARY_PREFIX="LT"
+)
+
+################################################################################
+# Optional flags
+################################################################################
+
+################################################################################
+# Public and private header and library dependencies
+################################################################################
+target_include_directories(sks
+	PUBLIC include
+	PRIVATE src
+)
+
+target_include_directories(teec
+	PUBLIC include
+)
+
+target_link_libraries (sks
+	PRIVATE pthread
+	PRIVATE teec
+	PRIVATE m
+)
+
+################################################################################
+# Install targets
+################################################################################
+install (TARGETS sks
+	DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+add_subdirectory(include)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/Makefile
new file mode 100644
index 0000000..a46e445
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/Makefile
@@ -0,0 +1,76 @@
+include ../flags.mk
+include ../config.mk
+
+OUT_DIR := $(OO)/libsks
+
+.PHONY: all libsks clean install
+
+all: libsks
+
+LIB_NAME	:= libsks
+MAJOR_VERSION	:= 0
+MINOR_VERSION	:= 0
+
+LIB_MAJOR		:= $(LIB_NAME).so.$(MAJOR_VERSION)
+LIB_MAJ_MIN		:= $(LIB_NAME).so.$(MAJOR_VERSION).$(MINOR_VERSION)
+LIBSKS_SO_LIBRARY	:= $(LIB_MAJ_MIN)
+LIBSKS_AR_LIBRARY	:= $(LIB_NAME).a
+
+LIBSKS_SRC_DIR		:= src
+
+LIBSKS_SRCS		= pkcs11_api.c
+LIBSKS_SRCS		+= ck_debug.c
+LIBSKS_SRCS 		+= ck_helpers.c
+LIBSKS_SRCS 		+= invoke_ta.c
+LIBSKS_SRCS 		+= pkcs11_token.c
+LIBSKS_SRCS		+= serializer.c
+LIBSKS_SRCS		+= serialize_ck.c
+LIBSKS_SRCS		+= pkcs11_processing.c
+
+LIBSKS_INCLUDES		= ${CURDIR}/include
+
+LIBSKS_CFLAGS		:= $(addprefix -I, $(LIBSKS_INCLUDES)) \
+				$(CFLAGS) -D_GNU_SOURCE -fPIC
+
+LIBSKS_LFLAGS		:= $(LDFLAGS) -L$(OUT_DIR)/../libteec -lteec
+
+LIBSKS_OBJ_DIR		:= $(OUT_DIR)
+LIBSKS_OBJS		:= $(patsubst %.c,$(LIBSKS_OBJ_DIR)/%.o, $(LIBSKS_SRCS))
+
+$(LIBSKS_OBJ_DIR)/%.o: ${LIBSKS_SRC_DIR}/%.c
+	$(VPREFIX)mkdir -p $(LIBSKS_OBJ_DIR)
+	@echo "  CC      $<"
+	$(VPREFIX)$(CC) $(LIBSKS_CFLAGS) -c $< -o $@
+
+libsks: $(OUT_DIR)/$(LIBSKS_SO_LIBRARY)
+
+$(OUT_DIR)/$(LIBSKS_SO_LIBRARY): $(LIBSKS_OBJS)
+	@echo "  LINK    $@"
+	$(VPREFIX)$(CC) -shared -o $@ $+ $(LIBSKS_LFLAGS)
+	@echo ""
+
+libsks: $(OUT_DIR)/$(LIBSKS_AR_LIBRARY)
+
+$(OUT_DIR)/$(LIBSKS_AR_LIBRARY): $(LIBSKS_OBJS)
+	@echo "  AR      $@"
+	$(VPREFIX)$(AR) rcs $@ $+
+
+libsks:
+	$(VPREFIX)ln -sf $(LIB_MAJ_MIN) $(OUT_DIR)/$(LIB_MAJOR)
+	$(VPREFIX)ln -sf $(LIB_MAJOR) $(OUT_DIR)/$(LIB_NAME).so
+
+################################################################################
+# Cleaning up configuration
+################################################################################
+clean:
+	$(RM) $(LIBSKS_OBJS)
+	$(RM) $(OUT_DIR)/$(LIB_MAJ_MIN)
+	$(RM) $(OUT_DIR)/$(LIB_MAJOR)
+	$(RM) $(OUT_DIR)/$(LIBSKS_SO_LIBRARY)
+	$(RM) $(OUT_DIR)/$(LIBSKS_AR_LIBRARY)
+	$(call rmdir,$(OUT_DIR))
+
+install: libsks
+	cp -f $(OUT_DIR)/$(LIBSKS_SO_LIBRARY) $(LIBDIR)/$(LIB_NAME).so
+	mkdir -p $(INCDIR)/libsks
+	cp -f ${CURDIR}/include/pkcs11.h $(INCDIR)/libsks/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/CMakeLists.txt b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/CMakeLists.txt
new file mode 100644
index 0000000..24344ec
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/CMakeLists.txt
@@ -0,0 +1,7 @@
+project (optee-cryptoki-headers C)
+
+FILE(GLOB INSTALL_HEADERS "*.h")
+
+add_library(${PROJECT_NAME} INTERFACE)
+
+install (FILES ${INSTALL_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/pkcs11.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/pkcs11.h
new file mode 100644
index 0000000..644d10c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/pkcs11.h
@@ -0,0 +1,1562 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2018, Linaro Limited
+ */
+
+#ifndef __PKCS11_H__
+#define __PKCS11_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * PKCS#11 Cryptoki API v2.40-errata01, See specification from:
+ * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/os/pkcs11-base-v2.40-errata01-os-complete.html
+ */
+
+typedef unsigned char		CK_BYTE;
+typedef unsigned long int	CK_ULONG;
+typedef long int		CK_LONG;
+
+typedef CK_BYTE			CK_CHAR;
+typedef CK_BYTE			CK_UTF8CHAR;
+
+typedef CK_BYTE *		CK_BYTE_PTR;
+typedef CK_ULONG *		CK_ULONG_PTR;
+
+typedef CK_CHAR *		CK_CHAR_PTR;
+typedef CK_UTF8CHAR *		CK_UTF8CHAR_PTR;
+
+typedef void *			CK_VOID_PTR;
+typedef CK_VOID_PTR *		CK_VOID_PTR_PTR;
+
+typedef CK_BYTE			CK_BBOOL;
+
+#define CK_TRUE			1
+#define CK_FALSE		0
+
+typedef CK_ULONG		CK_FLAGS;
+
+#define CK_UNAVAILABLE_INFORMATION	(~0UL)
+#define CK_EFFECTIVELY_INFINITE	0
+
+typedef CK_ULONG		CK_SESSION_HANDLE;
+typedef CK_SESSION_HANDLE *	CK_SESSION_HANDLE_PTR;
+typedef CK_ULONG		CK_OBJECT_HANDLE;
+typedef CK_OBJECT_HANDLE *	CK_OBJECT_HANDLE_PTR;
+
+#define CK_INVALID_HANDLE	0
+
+typedef CK_ULONG		CK_SLOT_ID;
+typedef CK_SLOT_ID *		CK_SLOT_ID_PTR;
+
+typedef struct CK_VERSION	CK_VERSION;
+typedef struct CK_VERSION *	CK_VERSION_PTR;
+
+struct CK_VERSION {
+	CK_BYTE		major;
+	CK_BYTE		minor;
+};
+
+typedef struct CK_DATE		CK_DATE;
+typedef struct CK_DATE *	CK_DATE_PTR;
+
+struct CK_DATE {
+	CK_CHAR		year[4];
+	CK_CHAR		month[2];
+	CK_CHAR		day[2];
+};
+
+/*
+ * PKCS#11 Objects attributes
+ */
+
+typedef CK_ULONG		CK_ATTRIBUTE_TYPE;
+
+typedef struct CK_ATTRIBUTE	CK_ATTRIBUTE;
+typedef struct CK_ATTRIBUTE *	CK_ATTRIBUTE_PTR;
+
+struct CK_ATTRIBUTE {
+	CK_ATTRIBUTE_TYPE	type;
+	CK_VOID_PTR		pValue;
+	CK_ULONG		ulValueLen;
+};
+
+/*
+ * Values for CK_ATTRIBUTE_TYPE
+ *
+ * This does not cover the full PKCS#11 IDs.
+ */
+#define CKF_ARRAY_ATTRIBUTE		(1U << 30)
+#define CKA_VENDOR_DEFINED		(1U << 31)
+#define CKA_CLASS			0x0000
+#define CKA_TOKEN			0x0001
+#define CKA_PRIVATE			0x0002
+#define CKA_LABEL			0x0003
+#define CKA_APPLICATION			0x0010
+#define CKA_VALUE			0x0011
+#define CKA_OBJECT_ID			0x0012
+#define CKA_CERTIFICATE_TYPE		0x0080
+#define CKA_ISSUER			0x0081
+#define CKA_SERIAL_NUMBER		0x0082
+#define CKA_AC_ISSUER			0x0083
+#define CKA_OWNER			0x0084
+#define CKA_ATTR_TYPES			0x0085
+#define CKA_TRUSTED			0x0086
+#define CKA_CERTIFICATE_CATEGORY	0x0087
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN	0x0088
+#define CKA_URL				0x0089
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY	0x008a
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY	0x008b
+#define CKA_NAME_HASH_ALGORITHM		0x008c
+#define CKA_CHECK_VALUE			0x0090
+#define CKA_KEY_TYPE			0x0100
+#define CKA_SUBJECT			0x0101
+#define CKA_ID				0x0102
+#define CKA_SENSITIVE			0x0103
+#define CKA_ENCRYPT			0x0104
+#define CKA_DECRYPT			0x0105
+#define CKA_WRAP			0x0106
+#define CKA_UNWRAP			0x0107
+#define CKA_SIGN			0x0108
+#define CKA_SIGN_RECOVER		0x0109
+#define CKA_VERIFY			0x010a
+#define CKA_VERIFY_RECOVER		0x010b
+#define CKA_DERIVE			0x010c
+#define CKA_START_DATE			0x0110
+#define CKA_END_DATE			0x0111
+#define CKA_MODULUS			0x0120
+#define CKA_MODULUS_BITS		0x0121
+#define CKA_PUBLIC_EXPONENT		0x0122
+#define CKA_PRIVATE_EXPONENT		0x0123
+#define CKA_PRIME_1			0x0124
+#define CKA_PRIME_2			0x0125
+#define CKA_EXPONENT_1			0x0126
+#define CKA_EXPONENT_2			0x0127
+#define CKA_COEFFICIENT			0x0128
+#define CKA_PUBLIC_KEY_INFO		0x0129
+#define CKA_PRIME			0x0130
+#define CKA_SUBPRIME			0x0131
+#define CKA_BASE			0x0132
+#define CKA_PRIME_BITS			0x0133
+#define CKA_SUBPRIME_BITS		0x0134
+#define CKA_VALUE_BITS			0x0160
+#define CKA_VALUE_LEN			0x0161
+#define CKA_EXTRACTABLE			0x0162
+#define CKA_LOCAL			0x0163
+#define CKA_NEVER_EXTRACTABLE		0x0164
+#define CKA_ALWAYS_SENSITIVE		0x0165
+#define CKA_KEY_GEN_MECHANISM		0x0166
+#define CKA_MODIFIABLE			0x0170
+#define CKA_COPYABLE			0x0171
+#define CKA_DESTROYABLE			0x0172
+#define CKA_EC_PARAMS			0x0180
+#define CKA_EC_POINT			0x0181
+#define CKA_ALWAYS_AUTHENTICATE		0x0202
+#define CKA_WRAP_WITH_TRUSTED		0x0210
+#define CKA_WRAP_TEMPLATE		(0x0211 | CKF_ARRAY_ATTRIBUTE)
+#define CKA_UNWRAP_TEMPLATE		(0x0212 | CKF_ARRAY_ATTRIBUTE)
+#define CKA_DERIVE_TEMPLATE		(0x0213 | CKF_ARRAY_ATTRIBUTE)
+#define CKA_OTP_FORMAT			0x0220
+#define CKA_OTP_LENGTH			0x0221
+#define CKA_OTP_TIME_INTERVAL		0x0222
+#define CKA_OTP_USER_FRIENDLY_MODE	0x0223
+#define CKA_OTP_CHALLENGE_REQUIREMENT	0x0224
+#define CKA_OTP_TIME_REQUIREMENT	0x0225
+#define CKA_OTP_COUNTER_REQUIREMENT	0x0226
+#define CKA_OTP_PIN_REQUIREMENT		0x0227
+#define CKA_OTP_COUNTER			0x022e
+#define CKA_OTP_TIME			0x022f
+#define CKA_OTP_USER_IDENTIFIER		0x022a
+#define CKA_OTP_SERVICE_IDENTIFIER	0x022b
+#define CKA_OTP_SERVICE_LOGO		0x022c
+#define CKA_OTP_SERVICE_LOGO_TYPE	0x022d
+#define CKA_GOSTR3410_PARAMS		0x0250
+#define CKA_GOSTR3411_PARAMS		0x0251
+#define CKA_GOST28147_PARAMS		0x0252
+#define CKA_HW_FEATURE_TYPE		0x0300
+#define CKA_RESET_ON_INIT		0x0301
+#define CKA_HAS_RESET			0x0302
+#define CKA_PIXEL_X			0x0400
+#define CKA_PIXEL_Y			0x0401
+#define CKA_RESOLUTION			0x0402
+#define CKA_CHAR_ROWS			0x0403
+#define CKA_CHAR_COLUMNS		0x0404
+#define CKA_COLOR			0x0405
+#define CKA_BITS_PER_PIXEL		0x0406
+#define CKA_CHAR_SETS			0x0480
+#define CKA_ENCODING_METHODS		0x0481
+#define CKA_MIME_TYPES			0x0482
+#define CKA_MECHANISM_TYPE		0x0500
+#define CKA_REQUIRED_CMS_ATTRIBUTES	0x0501
+#define CKA_DEFAULT_CMS_ATTRIBUTES	0x0502
+#define CKA_SUPPORTED_CMS_ATTRIBUTES	0x0503
+#define CKA_ALLOWED_MECHANISMS		(0x0600 | CKF_ARRAY_ATTRIBUTE)
+
+/* Attribute CKA_CLASS refers to a CK_OBJECT_CLASS typed value */
+typedef CK_ULONG		CK_OBJECT_CLASS;
+typedef CK_OBJECT_CLASS *	CK_OBJECT_CLASS_PTR;
+
+/* Values for type CK_OBJECT_CLASS */
+#define CKO_VENDOR_DEFINED		(1U << 31)
+#define CKO_DATA			0x0
+#define CKO_CERTIFICATE			0x1
+#define CKO_PUBLIC_KEY			0x2
+#define CKO_PRIVATE_KEY			0x3
+#define CKO_SECRET_KEY			0x4
+#define CKO_HW_FEATURE			0x5
+#define CKO_DOMAIN_PARAMETERS		0x6
+#define CKO_MECHANISM			0x7
+#define CKO_OTP_KEY			0x8
+
+/* Attribute CKA_KEY_TYPE refers to a CK_KEY_TYPE typed value */
+typedef CK_ULONG		CK_KEY_TYPE;
+typedef CK_KEY_TYPE *		CK_KEY_TYPE_PTR;
+
+/*
+ * Values for type CK_KEY_TYPE
+ *
+ * This does not cover the full PKCS#11 IDs.
+ */
+#define CKK_VENDOR_DEFINED		(1U << 31)
+#define CKK_RSA				0x000
+#define CKK_DSA				0x001
+#define CKK_DH				0x002
+#define CKK_ECDSA			0x003
+#define CKK_EC				0x003
+#define CKK_GENERIC_SECRET		0x010
+#define CKK_DES			0x013
+#define CKK_DES2			0x014
+#define CKK_DES3			0x015
+#define CKK_AES				0x01f
+#define CKK_HOTP			0x023
+#define CKK_MD5_HMAC			0x027
+#define CKK_SHA_1_HMAC			0x028
+#define CKK_SHA256_HMAC			0x02b
+#define CKK_SHA384_HMAC			0x02c
+#define CKK_SHA512_HMAC			0x02d
+#define CKK_SHA224_HMAC			0x02e
+
+/* Attribute CKA_CERTIFICATE_TYPE refers to a CK_CERTIFICATE_TYPE typed value */
+typedef CK_ULONG		CK_CERTIFICATE_TYPE;
+typedef CK_CERTIFICATE_TYPE *	CK_CERTIFICATE_TYPE_PTR;
+
+/*
+ * Values for type CK_CERTIFICATE_TYPE
+ */
+#define CKC_VENDOR_DEFINED		(1U << 31)
+#define CKC_X_509				0x000
+#define CKC_X_509_ATTR_CER			0x001
+#define CKC_WTLS				0x002
+
+/*
+ * Mechanisms
+ *
+ * Note: a mechanism can be referenced as object reference in some PKCS#11 API
+ * functions. In such case, the object hold attribute CKA_MECHANISM_TYPE which
+ * refers to a CK_MECHANISM_TYPE typed value that defines the target mechanism.
+ */
+
+typedef CK_ULONG		CK_MECHANISM_TYPE;
+typedef CK_MECHANISM_TYPE *	CK_MECHANISM_TYPE_PTR;
+
+/*
+ * Values for type CK_MECHANISM_TYPE
+ *
+ * This does not cover the full PKCS#11 IDs.
+ */
+#define CKM_VENDOR_DEFINED		(1U << 31)
+#define CKM_RSA_PKCS_KEY_PAIR_GEN	0x00000
+#define CKM_RSA_PKCS			0x00001
+#define CKM_RSA_9796			0x00002
+#define CKM_RSA_X_509			0x00003
+#define CKM_SHA1_RSA_PKCS		0x00006
+#define CKM_RSA_PKCS_OAEP		0x00009
+#define CKM_RSA_PKCS_PSS		0x0000d
+#define CKM_SHA1_RSA_PKCS_PSS		0x0000e
+#define CKM_SHA256_RSA_PKCS		0x00040
+#define CKM_SHA384_RSA_PKCS		0x00041
+#define CKM_SHA512_RSA_PKCS		0x00042
+#define CKM_SHA256_RSA_PKCS_PSS		0x00043
+#define CKM_SHA384_RSA_PKCS_PSS		0x00044
+#define CKM_SHA512_RSA_PKCS_PSS		0x00045
+#define CKM_SHA224_RSA_PKCS		0x00046
+#define CKM_SHA224_RSA_PKCS_PSS		0x00047
+#define CKM_SHA512_224			0x00048
+#define CKM_SHA512_224_HMAC		0x00049
+#define CKM_SHA512_224_HMAC_GENERAL	0x0004a
+#define CKM_SHA512_224_KEY_DERIVATION	0x0004b
+#define CKM_SHA512_256			0x0004c
+#define CKM_SHA512_256_HMAC		0x0004d
+#define CKM_SHA512_256_HMAC_GENERAL	0x0004e
+#define CKM_SHA512_256_KEY_DERIVATION	0x0004f
+#define CKM_DES_KEY_GEN		0x00120
+#define CKM_DES_ECB			0x00121
+#define CKM_DES_CBC			0x00122
+#define CKM_DES_MAC			0x00123
+#define CKM_DES_MAC_GENERAL		0x00124
+#define CKM_DES_CBC_PAD		0x00125
+#define CKM_DES3_ECB			0x00132
+#define CKM_DES3_CBC			0x00133
+#define CKM_DES3_MAC			0x00134
+#define CKM_DES3_MAC_GENERAL		0x00135
+#define CKM_DES3_CBC_PAD		0x00136
+#define CKM_DES3_CMAC_GENERAL		0x00137
+#define CKM_DES3_CMAC			0x00138
+#define CKM_MD5				0x00210
+#define CKM_MD5_HMAC			0x00211
+#define CKM_MD5_HMAC_GENERAL		0x00212
+#define CKM_SHA_1			0x00220
+#define CKM_SHA_1_HMAC			0x00221
+#define CKM_SHA_1_HMAC_GENERAL		0x00222
+#define CKM_SHA256			0x00250
+#define CKM_SHA256_HMAC			0x00251
+#define CKM_SHA256_HMAC_GENERAL		0x00252
+#define CKM_SHA224			0x00255
+#define CKM_SHA224_HMAC			0x00256
+#define CKM_SHA224_HMAC_GENERAL		0x00257
+#define CKM_SHA384			0x00260
+#define CKM_SHA384_HMAC			0x00261
+#define CKM_SHA384_HMAC_GENERAL		0x00262
+#define CKM_SHA512			0x00270
+#define CKM_SHA512_HMAC			0x00271
+#define CKM_SHA512_HMAC_GENERAL		0x00272
+#define CKM_HOTP_KEY_GEN		0x00290
+#define CKM_HOTP			0x00291
+#define CKM_GENERIC_SECRET_KEY_GEN	0x00350
+#define CKM_MD5_KEY_DERIVATION		0x00390
+#define CKM_MD2_KEY_DERIVATION		0x00391
+#define CKM_SHA1_KEY_DERIVATION		0x00392
+#define CKM_SHA256_KEY_DERIVATION	0x00393
+#define CKM_SHA384_KEY_DERIVATION	0x00394
+#define CKM_SHA512_KEY_DERIVATION	0x00395
+#define CKM_SHA224_KEY_DERIVATION	0x00396
+#define CKM_EC_KEY_PAIR_GEN		0x01040
+#define CKM_ECDSA			0x01041
+#define CKM_ECDSA_SHA1			0x01042
+#define CKM_ECDSA_SHA224		0x01043
+#define CKM_ECDSA_SHA256		0x01044
+#define CKM_ECDSA_SHA384		0x01045
+#define CKM_ECDSA_SHA512		0x01046
+#define CKM_ECDH1_DERIVE		0x01050
+#define CKM_ECDH1_COFACTOR_DERIVE	0x01051
+#define CKM_ECMQV_DERIVE		0x01052
+#define CKM_ECDH_AES_KEY_WRAP		0x01053
+#define CKM_RSA_AES_KEY_WRAP		0x01054
+#define CKM_AES_KEY_GEN			0x01080
+#define CKM_AES_ECB			0x01081
+#define CKM_AES_CBC			0x01082
+#define CKM_AES_MAC			0x01083
+#define CKM_AES_MAC_GENERAL		0x01084
+#define CKM_AES_CBC_PAD			0x01085
+#define CKM_AES_CTR			0x01086
+#define CKM_AES_GCM			0x01087
+#define CKM_AES_CCM			0x01088
+#define CKM_AES_CTS			0x01089
+#define CKM_AES_CMAC			0x0108a
+#define CKM_AES_CMAC_GENERAL		0x0108b
+#define CKM_AES_XCBC_MAC		0x0108c
+#define CKM_AES_XCBC_MAC_96		0x0108d
+#define CKM_AES_GMAC			0x0108e
+#define CKM_DES3_ECB_ENCRYPT_DATA	0x01102
+#define CKM_DES3_CBC_ENCRYPT_DATA	0x01103
+#define CKM_AES_ECB_ENCRYPT_DATA	0x01104
+#define CKM_AES_CBC_ENCRYPT_DATA	0x01105
+#define CKM_AES_KEY_WRAP		0x02109
+#define CKM_AES_KEY_WRAP_PAD		0x0210a
+#define CKM_EC_KEY_PAIR_IMPORT		0x03000
+#define CKM_DUMP_LOG			0x03100
+
+
+#define CKM_MTK_HSM_EXT			(CKM_VENDOR_DEFINED | (1U << 30))
+#define CKM_MTK_HSM_SHA1		(CKM_MTK_HSM_EXT | CKM_SHA_1)
+#define CKM_MTK_HSM_SHA224		(CKM_MTK_HSM_EXT | CKM_SHA224)
+#define CKM_MTK_HSM_SHA256		(CKM_MTK_HSM_EXT | CKM_SHA256)
+#define CKM_MTK_HSM_SHA384		(CKM_MTK_HSM_EXT | CKM_SHA384)
+#define CKM_MTK_HSM_SHA512		(CKM_MTK_HSM_EXT | CKM_SHA512)
+#define CKM_MTK_HSM_SHA256_HMAC		(CKM_MTK_HSM_EXT | CKM_SHA256_HMAC)
+#define CKM_MTK_HSM_SHA384_HMAC		(CKM_MTK_HSM_EXT | CKM_SHA384_HMAC)
+#define CKM_MTK_HSM_ECDSA		(CKM_MTK_HSM_EXT | CKM_ECDSA)
+#define CKM_MTK_HSM_ECDSA_SHA1		(CKM_MTK_HSM_EXT | CKM_ECDSA_SHA1)
+#define CKM_MTK_HSM_ECDSA_SHA224	(CKM_MTK_HSM_EXT | CKM_ECDSA_SHA224)
+#define CKM_MTK_HSM_ECDSA_SHA256	(CKM_MTK_HSM_EXT | CKM_ECDSA_SHA256)
+#define CKM_MTK_HSM_ECDSA_SHA384	(CKM_MTK_HSM_EXT | CKM_ECDSA_SHA384)
+#define CKM_MTK_HSM_ECDSA_SHA512	(CKM_MTK_HSM_EXT | CKM_ECDSA_SHA512)
+#define CKM_MTK_HSM_AES_ECB		(CKM_MTK_HSM_EXT | CKM_AES_ECB)
+#define CKM_MTK_HSM_AES_CBC		(CKM_MTK_HSM_EXT | CKM_AES_CBC)
+#define CKM_MTK_HSM_AES_CTR		(CKM_MTK_HSM_EXT | CKM_AES_CTR)
+#define CKM_MTK_HSM_AES_GCM		(CKM_MTK_HSM_EXT | CKM_AES_GCM)
+#define CKM_MTK_HSM_AES_CMAC		(CKM_MTK_HSM_EXT | CKM_AES_CMAC)
+#define CKM_MTK_HSM_AES_KEY_GEN		(CKM_MTK_HSM_EXT | CKM_AES_KEY_GEN)
+#define CKM_MTK_HSM_EC_KEY_PAIR_GEN	(CKM_MTK_HSM_EXT | CKM_EC_KEY_PAIR_GEN)
+#define CKM_MTK_HSM_EC_KEY_PAIR_IMPORT	(CKM_MTK_HSM_EXT | CKM_EC_KEY_PAIR_IMPORT)
+#define CKM_MTK_HSM_DUMP_LOG 		(CKM_MTK_HSM_EXT | CKM_DUMP_LOG)
+
+
+typedef struct CK_MECHANISM_INFO	CK_MECHANISM_INFO;
+typedef struct CK_MECHANISM_INFO *	CK_MECHANISM_INFO_PTR;
+
+struct CK_MECHANISM_INFO {
+	CK_ULONG		ulMinKeySize;
+	CK_ULONG		ulMaxKeySize;
+	CK_FLAGS		flags;
+};
+
+/* Flags for field flags of struct ck_mechanism_info */
+#define CKF_HW				(1U << 0)
+#define CKF_ENCRYPT			(1U << 8)
+#define CKF_DECRYPT			(1U << 9)
+#define CKF_DIGEST			(1U << 10)
+#define CKF_SIGN			(1U << 11)
+#define CKF_SIGN_RECOVER		(1U << 12)
+#define CKF_VERIFY			(1U << 13)
+#define CKF_VERIFY_RECOVER		(1U << 14)
+#define CKF_GENERATE			(1U << 15)
+#define CKF_GENERATE_KEY_PAIR		(1U << 16)
+#define CKF_WRAP			(1U << 17)
+#define CKF_UNWRAP			(1U << 18)
+#define CKF_DERIVE			(1U << 19)
+#define CKF_EC_F_P			(1U << 20)
+#define CKF_EC_F_2M			(1U << 21)
+#define CKF_EC_ECPARAMETERS		(1U << 22)
+#define CKF_EC_NAMEDCURVE		(1U << 23)
+#define CKF_EC_UNCOMPRESS		(1U << 24)
+#define CKF_EC_COMPRESS			(1U << 25)
+#define CKF_EXTENSION			(1U << 31)
+
+/*
+ * Mechanism parameter structures
+ *
+ * This does not cover the whole mechanism parameter structures defined by
+ * the PKCS#11. To be updated when needed.
+ */
+
+typedef struct CK_MECHANISM	CK_MECHANISM;
+typedef struct CK_MECHANISM *	CK_MECHANISM_PTR;
+
+struct CK_MECHANISM {
+	CK_MECHANISM_TYPE	mechanism;
+	CK_VOID_PTR		pParameter;
+	CK_ULONG		ulParameterLen;
+};
+
+/* Key diversification identifiers */
+typedef CK_ULONG		CK_EC_KDF_TYPE;
+
+/* Values for type CK_EC_KDF_TYPE */
+#define CKD_NULL			0x0001
+#define CKD_SHA1_KDF			0x0002
+#define CKD_SHA1_KDF_ASN1		0x0003
+#define CKD_SHA1_KDF_CONCATENATE	0x0004
+#define CKD_SHA224_KDF			0x0005
+#define CKD_SHA256_KDF			0x0006
+#define CKD_SHA384_KDF			0x0007
+#define CKD_SHA512_KDF			0x0008
+#define CKD_CPDIVERSIFY_KDF		0x0009
+
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+/* Values for type CK_RSA_PKCS_MGF_TYPE */
+#define CKG_MGF1_SHA1		0x0001UL
+#define CKG_MGF1_SHA224		0x0005UL
+#define CKG_MGF1_SHA256		0x0002UL
+#define CKG_MGF1_SHA384		0x0003UL
+#define CKG_MGF1_SHA512		0x0004UL
+
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+/* Values for type CK_RSA_PKCS_OAEP_SOURCE_TYPE */
+#define CKZ_DATA_SPECIFIED	0x0001UL
+
+/* MAC General parameters */
+typedef CK_ULONG			CK_MAC_GENERAL_PARAMS;
+typedef CK_MAC_GENERAL_PARAMS *		CK_MAC_GENERAL_PARAMS_PTR;
+
+/*
+ * AES derivation by ECB encryption parameters: uses the generic
+ * structure CK_KEY_DERIVATION_STRING_DATA.
+ */
+typedef struct CK_KEY_DERIVATION_STRING_DATA	CK_KEY_DERIVATION_STRING_DATA;
+typedef struct CK_KEY_DERIVATION_STRING_DATA *	\
+					CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+struct CK_KEY_DERIVATION_STRING_DATA {
+	CK_BYTE_PTR		pData;
+	CK_ULONG		ulLen;
+};
+
+/* AES derivation by CBC encryption parameters */
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS	CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS *
+					CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+	CK_BYTE			iv[16];
+	CK_BYTE_PTR		pData;
+	CK_ULONG		length;
+};
+
+/* AES CTR parameters */
+typedef struct CK_AES_CTR_PARAMS	CK_AES_CTR_PARAMS;
+typedef struct CK_AES_CTR_PARAMS *	CK_AES_CTR_PARAMS_PTR;
+
+struct CK_AES_CTR_PARAMS {
+	CK_ULONG		ulCounterBits;
+	CK_BYTE			cb[16];
+};
+
+/* AES GCM parameters */
+typedef struct CK_GCM_PARAMS		CK_GCM_PARAMS;
+typedef struct CK_GCM_PARAMS *		CK_GCM_PARAMS_PTR;
+
+struct CK_GCM_PARAMS {
+	CK_BYTE_PTR		pIv;
+	CK_ULONG		ulIvLen;
+	CK_ULONG		ulIvBits;
+	CK_BYTE_PTR		pAAD;
+	CK_ULONG		ulAADLen;
+	CK_ULONG		ulTagBits;
+};
+
+/* AES CCM parameters */
+typedef struct CK_CCM_PARAMS		CK_CCM_PARAMS;
+typedef struct CK_CCM_PARAMS *		CK_CCM_PARAMS_PTR;
+
+struct CK_CCM_PARAMS {
+	CK_ULONG		ulDataLen;
+	CK_BYTE_PTR		pNonce;
+	CK_ULONG		ulNonceLen;
+	CK_BYTE_PTR		pAAD;
+	CK_ULONG		ulAADLen;
+	CK_ULONG		ulMACLen;
+};
+
+/*
+ * Elliptic curve Diffie-Hellman key derivation
+ * Elliptic curve Diffie-Hellman cofactor key derivation parameters
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS		CK_ECDH1_DERIVE_PARAMS;
+typedef struct CK_ECDH1_DERIVE_PARAMS *		CK_ECDH1_DERIVE_PARAMS_PTR;
+
+struct CK_ECDH1_DERIVE_PARAMS {
+	CK_EC_KDF_TYPE		kdf;
+	CK_ULONG		ulSharedDataLen;
+	CK_BYTE_PTR		pSharedData;
+	CK_ULONG		ulPublicDataLen;
+	CK_BYTE_PTR		pPublicData;
+};
+
+/* Parameters for CKM_ECDH_AES_KEY_WRAP */
+typedef struct CK_ECDH_AES_KEY_WRAP_PARAMS	CK_ECDH_AES_KEY_WRAP_PARAMS;
+typedef struct CK_ECDH_AES_KEY_WRAP_PARAMS *	CK_ECDH_AES_KEY_WRAP_PARAMS_PTR;
+
+struct CK_ECDH_AES_KEY_WRAP_PARAMS {
+	CK_ULONG		ulAESKeyBits;
+	CK_EC_KDF_TYPE		kdf;
+	CK_ULONG		ulSharedDataLen;
+	CK_BYTE_PTR		pSharedData;
+};
+
+/* Parameters for CKM_RSA_PKCS_OAEP */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS		CK_RSA_PKCS_OAEP_PARAMS;
+typedef struct CK_RSA_PKCS_OAEP_PARAMS *	CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+struct CK_RSA_PKCS_OAEP_PARAMS {
+	CK_MECHANISM_TYPE	hashAlg;
+	CK_RSA_PKCS_MGF_TYPE	mgf;
+	CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+	CK_VOID_PTR		pSourceData;
+	CK_ULONG		ulSourceDataLen;
+};
+
+/* Parameters for CKM_RSA_PKCS_PSS */
+typedef struct CK_RSA_PKCS_PSS_PARAMS		CK_RSA_PKCS_PSS_PARAMS;
+typedef struct CK_RSA_PKCS_PSS_PARAMS *		CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+struct CK_RSA_PKCS_PSS_PARAMS {
+	CK_MECHANISM_TYPE	hashAlg;
+	CK_RSA_PKCS_MGF_TYPE	mgf;
+	CK_ULONG		sLen;
+};
+
+/* Parameters for CKM_RSA_AES_KEY_WRAP */
+typedef struct CK_RSA_AES_KEY_WRAP_PARAMS	CK_RSA_AES_KEY_WRAP_PARAMS;
+typedef struct CK_RSA_AES_KEY_WRAP_PARAMS *	CK_RSA_AES_KEY_WRAP_PARAMS_PTR;
+
+struct CK_RSA_AES_KEY_WRAP_PARAMS {
+	CK_ULONG		ulAESKeyBits;
+	CK_RSA_PKCS_OAEP_PARAMS_PTR pOAEPParams;
+};
+
+
+/*
+ * PKCS#11 return values
+ */
+typedef CK_ULONG			CK_RV;
+
+/* Values for type CK_RV */
+#define CKR_VENDOR_DEFINED			(1U << 31)
+#define CKR_OK					0x0000
+#define CKR_CANCEL				0x0001
+#define CKR_HOST_MEMORY				0x0002
+#define CKR_SLOT_ID_INVALID			0x0003
+#define CKR_GENERAL_ERROR			0x0005
+#define CKR_FUNCTION_FAILED			0x0006
+#define CKR_ARGUMENTS_BAD			0x0007
+#define CKR_NO_EVENT				0x0008
+#define CKR_NEED_TO_CREATE_THREADS		0x0009
+#define CKR_CANT_LOCK				0x000a
+#define CKR_ATTRIBUTE_READ_ONLY			0x0010
+#define CKR_ATTRIBUTE_SENSITIVE			0x0011
+#define CKR_ATTRIBUTE_TYPE_INVALID		0x0012
+#define CKR_ATTRIBUTE_VALUE_INVALID		0x0013
+#define CKR_ACTION_PROHIBITED			0x001b
+#define CKR_DATA_INVALID			0x0020
+#define CKR_DATA_LEN_RANGE			0x0021
+#define CKR_DEVICE_ERROR			0x0030
+#define CKR_DEVICE_MEMORY			0x0031
+#define CKR_DEVICE_REMOVED			0x0032
+#define CKR_ENCRYPTED_DATA_INVALID		0x0040
+#define CKR_ENCRYPTED_DATA_LEN_RANGE		0x0041
+#define CKR_FUNCTION_CANCELED			0x0050
+#define CKR_FUNCTION_NOT_PARALLEL		0x0051
+#define CKR_FUNCTION_NOT_SUPPORTED		0x0054
+#define CKR_KEY_HANDLE_INVALID			0x0060
+#define CKR_KEY_SIZE_RANGE			0x0062
+#define CKR_KEY_TYPE_INCONSISTENT		0x0063
+#define CKR_KEY_NOT_NEEDED			0x0064
+#define CKR_KEY_CHANGED				0x0065
+#define CKR_KEY_NEEDED				0x0066
+#define CKR_KEY_INDIGESTIBLE			0x0067
+#define CKR_KEY_FUNCTION_NOT_PERMITTED		0x0068
+#define CKR_KEY_NOT_WRAPPABLE			0x0069
+#define CKR_KEY_UNEXTRACTABLE			0x006a
+#define CKR_MECHANISM_INVALID			0x0070
+#define CKR_MECHANISM_PARAM_INVALID		0x0071
+#define CKR_OBJECT_HANDLE_INVALID		0x0082
+#define CKR_OPERATION_ACTIVE			0x0090
+#define CKR_OPERATION_NOT_INITIALIZED		0x0091
+#define CKR_PIN_INCORRECT			0x00a0
+#define CKR_PIN_INVALID				0x00a1
+#define CKR_PIN_LEN_RANGE			0x00a2
+#define CKR_PIN_EXPIRED				0x00a3
+#define CKR_PIN_LOCKED				0x00a4
+#define CKR_SESSION_CLOSED			0x00b0
+#define CKR_SESSION_COUNT			0x00b1
+#define CKR_SESSION_HANDLE_INVALID		0x00b3
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED	0x00b4
+#define CKR_SESSION_READ_ONLY			0x00b5
+#define CKR_SESSION_EXISTS			0x00b6
+#define CKR_SESSION_READ_ONLY_EXISTS		0x00b7
+#define CKR_SESSION_READ_WRITE_SO_EXISTS	0x00b8
+#define CKR_SIGNATURE_INVALID			0x00c0
+#define CKR_SIGNATURE_LEN_RANGE			0x00c1
+#define CKR_TEMPLATE_INCOMPLETE			0x00d0
+#define CKR_TEMPLATE_INCONSISTENT		0x00d1
+#define CKR_TOKEN_NOT_PRESENT			0x00e0
+#define CKR_TOKEN_NOT_RECOGNIZED		0x00e1
+#define CKR_TOKEN_WRITE_PROTECTED		0x00e2
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID	0x00f0
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE		0x00f1
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT	0x00f2
+#define CKR_USER_ALREADY_LOGGED_IN		0x0100
+#define CKR_USER_NOT_LOGGED_IN			0x0101
+#define CKR_USER_PIN_NOT_INITIALIZED		0x0102
+#define CKR_USER_TYPE_INVALID			0x0103
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN	0x0104
+#define CKR_USER_TOO_MANY_TYPES			0x0105
+#define CKR_WRAPPED_KEY_INVALID			0x0110
+#define CKR_WRAPPED_KEY_LEN_RANGE		0x0112
+#define CKR_WRAPPING_KEY_HANDLE_INVALID		0x0113
+#define CKR_WRAPPING_KEY_SIZE_RANGE		0x0114
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT	0x0115
+#define CKR_RANDOM_SEED_NOT_SUPPORTED		0x0120
+#define CKR_RANDOM_NO_RNG			0x0121
+#define CKR_DOMAIN_PARAMS_INVALID		0x0130
+#define CKR_CURVE_NOT_SUPPORTED			0x0140
+#define CKR_BUFFER_TOO_SMALL			0x0150
+#define CKR_SAVED_STATE_INVALID			0x0160
+#define CKR_INFORMATION_SENSITIVE		0x0170
+#define CKR_STATE_UNSAVEABLE			0x0180
+#define CKR_CRYPTOKI_NOT_INITIALIZED		0x0190
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED	0x0191
+#define CKR_MUTEX_BAD				0x01a0
+#define CKR_MUTEX_NOT_LOCKED			0x01a1
+#define CKR_NEW_PIN_MODE			0x01b0
+#define CKR_NEXT_OTP				0x01b1
+#define CKR_EXCEEDED_MAX_ITERATIONS		0x01b5
+#define CKR_FIPS_SELF_TEST_FAILED		0x01b6
+#define CKR_LIBRARY_LOAD_FAILED			0x01b7
+#define CKR_PIN_TOO_WEAK			0x01b8
+#define CKR_PUBLIC_KEY_INVALID			0x01b9
+#define CKR_FUNCTION_REJECTED			0x0200
+
+/*
+ * PKCS#11 API functions
+ */
+
+/* Argument for C_GetInfo */
+typedef struct CK_INFO		CK_INFO;
+typedef struct CK_INFO *	CK_INFO_PTR;
+
+struct CK_INFO {
+	CK_VERSION	cryptokiVersion;
+	CK_UTF8CHAR	manufacturerID[32];
+	CK_FLAGS	flags;
+	CK_UTF8CHAR	libraryDescription[32];
+	CK_VERSION	libraryVersion;
+};
+
+/* Argument for C_GetSlotInfo */
+typedef struct CK_SLOT_INFO	CK_SLOT_INFO;
+typedef struct CK_SLOT_INFO *	CK_SLOT_INFO_PTR;
+
+struct CK_SLOT_INFO {
+	CK_UTF8CHAR	slotDescription[64];
+	CK_UTF8CHAR	manufacturerID[32];
+	CK_FLAGS	flags;
+	CK_VERSION	hardwareVersion;
+	CK_VERSION	firmwareVersion;
+};
+
+/* Values for field flags of struct ck_slot_info */
+#define CKF_TOKEN_PRESENT	(1U << 0)
+#define CKF_REMOVABLE_DEVICE	(1U << 1)
+#define CKF_HW_SLOT		(1U << 2)
+
+/* Argument for C_GetTokenInfo */
+typedef struct CK_TOKEN_INFO	CK_TOKEN_INFO;
+typedef struct CK_TOKEN_INFO *	CK_TOKEN_INFO_PTR;
+
+struct CK_TOKEN_INFO {
+	CK_UTF8CHAR	label[32];
+	CK_UTF8CHAR	manufacturerID[32];
+	CK_UTF8CHAR	model[16];
+	CK_CHAR		serialNumber[16];
+	CK_FLAGS	flags;
+	CK_ULONG	ulMaxSessionCount;
+	CK_ULONG	ulSessionCount;
+	CK_ULONG	ulMaxRwSessionCount;
+	CK_ULONG	ulRwSessionCount;
+	CK_ULONG	ulMaxPinLen;
+	CK_ULONG	ulMinPinLen;
+	CK_ULONG	ulTotalPublicMemory;
+	CK_ULONG	ulFreePublicMemory;
+	CK_ULONG	ulTotalPrivateMemory;
+	CK_ULONG	ulFreePrivateMemory;
+	CK_VERSION	hardwareVersion;
+	CK_VERSION	firmwareVersion;
+	CK_CHAR		utcTime[16];
+};
+
+/* Values for field flags of struct ck_token_info */
+#define CKF_RNG					(1U << 0)
+#define CKF_WRITE_PROTECTED			(1U << 1)
+#define CKF_LOGIN_REQUIRED			(1U << 2)
+#define CKF_USER_PIN_INITIALIZED		(1U << 3)
+#define CKF_RESTORE_KEY_NOT_NEEDED		(1U << 5)
+#define CKF_CLOCK_ON_TOKEN			(1U << 6)
+#define CKF_PROTECTED_AUTHENTICATION_PATH	(1U << 8)
+#define CKF_DUAL_CRYPTO_OPERATIONS		(1U << 9)
+#define CKF_TOKEN_INITIALIZED			(1U << 10)
+#define CKF_SECONDARY_AUTHENTICATION		(1U << 11)
+#define CKF_USER_PIN_COUNT_LOW			(1U << 16)
+#define CKF_USER_PIN_FINAL_TRY			(1U << 17)
+#define CKF_USER_PIN_LOCKED			(1U << 18)
+#define CKF_USER_PIN_TO_BE_CHANGED		(1U << 19)
+#define CKF_SO_PIN_COUNT_LOW			(1U << 20)
+#define CKF_SO_PIN_FINAL_TRY			(1U << 21)
+#define CKF_SO_PIN_LOCKED			(1U << 22)
+#define CKF_SO_PIN_TO_BE_CHANGED		(1U << 23)
+#define CKF_ERROR_STATE				(1U << 24)
+
+/* Argument for C_GetSessionInfo */
+typedef struct CK_SESSION_INFO		CK_SESSION_INFO;
+typedef struct CK_SESSION_INFO *	CK_SESSION_INFO_PTR;
+
+typedef CK_ULONG			CK_STATE;
+
+/* Values for CK_STATE */
+#define CKS_RO_PUBLIC_SESSION		0
+#define CKS_RO_USER_FUNCTIONS		1
+#define CKS_RW_PUBLIC_SESSION		2
+#define CKS_RW_USER_FUNCTIONS		3
+#define CKS_RW_SO_FUNCTIONS		4
+
+struct CK_SESSION_INFO {
+	CK_SLOT_ID	slotID;
+	CK_STATE	state;
+	CK_FLAGS	flags;
+	CK_ULONG	ulDeviceError;
+};
+
+/* Values for field flags of struct ck_session_info */
+#define CKF_RW_SESSION			(1U << 1)
+#define CKF_SERIAL_SESSION		(1U << 2)
+
+/* Argument for C_Login */
+typedef CK_ULONG		CK_USER_TYPE;
+
+/* Values for CK_USER_TYPE */
+#define CKU_SO				0
+#define CKU_USER			1
+#define CKU_CONTEXT_SPECIFIC		2
+
+/* Values for argument flags of C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK			1
+
+/* Argument for CK_NOTIFY typed callback function */
+typedef CK_ULONG		CK_NOTIFICATION;
+
+/* Values for CK_NOTIFICATION */
+#define CKN_SURRENDER			0
+#define CKN_OTP_CHANGED			1
+
+/* Callback handler types */
+typedef CK_RV (* CK_NOTIFY)(CK_SESSION_HANDLE hSession,
+			    CK_NOTIFICATION event,
+			    CK_VOID_PTR pApplication);
+typedef CK_RV (* CK_CREATEMUTEX)(CK_VOID_PTR_PTR ppMutex);
+typedef CK_RV (* CK_DESTROYMUTEX)(CK_VOID_PTR pMutex);
+typedef CK_RV (* CK_LOCKMUTEX)(CK_VOID_PTR pMutex);
+typedef CK_RV (* CK_UNLOCKMUTEX)(CK_VOID_PTR pMutex);
+
+/* Argument for C_GetFunctionList */
+typedef struct CK_FUNCTION_LIST		CK_FUNCTION_LIST;
+typedef struct CK_FUNCTION_LIST *	CK_FUNCTION_LIST_PTR;
+typedef struct CK_FUNCTION_LIST **	CK_FUNCTION_LIST_PTR_PTR;
+
+struct CK_FUNCTION_LIST {
+	CK_VERSION version;
+	CK_RV (*C_Initialize)(
+			CK_VOID_PTR init_args);
+	CK_RV (*C_Finalize)(
+			CK_VOID_PTR res);
+	CK_RV (*C_GetInfo)(
+			CK_INFO_PTR info);
+	CK_RV (*C_GetFunctionList)(
+			CK_FUNCTION_LIST_PTR_PTR list);
+	CK_RV (*C_GetSlotList)(
+			CK_BBOOL token_present,
+			CK_SLOT_ID_PTR slots,
+			CK_ULONG_PTR count);
+	CK_RV (*C_GetSlotInfo)(
+			CK_SLOT_ID slot,
+			CK_SLOT_INFO_PTR info);
+	CK_RV (*C_GetTokenInfo)(
+			CK_SLOT_ID slot,
+			CK_TOKEN_INFO_PTR info);
+	CK_RV (*C_GetMechanismList)(
+			CK_SLOT_ID slot,
+			CK_MECHANISM_TYPE_PTR mechanisms,
+			CK_ULONG_PTR count);
+	CK_RV (*C_GetMechanismInfo)(
+			CK_SLOT_ID slot,
+			CK_MECHANISM_TYPE type,
+			CK_MECHANISM_INFO_PTR info);
+	CK_RV (*C_InitToken)(
+			CK_SLOT_ID slot,
+			CK_UTF8CHAR_PTR pin,
+			CK_ULONG pin_len,
+			CK_UTF8CHAR_PTR label);
+	CK_RV (*C_InitPIN)(
+			CK_SESSION_HANDLE session,
+			CK_UTF8CHAR_PTR pin,
+			CK_ULONG pin_len);
+	CK_RV (*C_SetPIN)(
+			CK_SESSION_HANDLE session,
+			CK_UTF8CHAR_PTR old,
+			CK_ULONG old_len,
+			CK_UTF8CHAR_PTR new,
+			CK_ULONG new_len);
+	CK_RV (*C_OpenSession)(CK_SLOT_ID slot,
+			CK_FLAGS flags,
+			CK_VOID_PTR cookie,
+			CK_NOTIFY callback,
+			CK_SESSION_HANDLE_PTR session);
+	CK_RV (*C_CloseSession)(
+			CK_SESSION_HANDLE session);
+	CK_RV (*C_CloseAllSessions)(
+			CK_SLOT_ID slot);
+	CK_RV (*C_GetSessionInfo)(
+			CK_SESSION_HANDLE session,
+			CK_SESSION_INFO_PTR info);
+	CK_RV (*C_GetOperationState)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR state,
+			CK_ULONG_PTR state_len);
+	CK_RV (*C_SetOperationState)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR state,
+			CK_ULONG state_len,
+			CK_OBJECT_HANDLE ciph_key,
+			CK_OBJECT_HANDLE auth_key);
+	CK_RV (*C_Login)(
+			CK_SESSION_HANDLE session,
+			CK_USER_TYPE user_type,
+			CK_UTF8CHAR_PTR pin,
+			CK_ULONG pin_len);
+	CK_RV (*C_Logout)(
+			CK_SESSION_HANDLE session);
+	CK_RV (*C_CreateObject)(
+			CK_SESSION_HANDLE session,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count,
+			CK_OBJECT_HANDLE_PTR obj);
+	CK_RV (*C_CopyObject)(
+			CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE obj,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count,
+			CK_OBJECT_HANDLE_PTR new_obj);
+	CK_RV (*C_DestroyObject)(
+			CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE obj);
+	CK_RV (*C_GetObjectSize)(
+			CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE obj,
+			CK_ULONG_PTR out_size);
+	CK_RV (*C_GetAttributeValue)(
+			CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE obj,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count);
+	CK_RV (*C_SetAttributeValue)(
+			CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE obj,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count);
+	CK_RV (*C_FindObjectsInit)(
+			CK_SESSION_HANDLE session,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count);
+	CK_RV (*C_FindObjects)(
+			CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE_PTR obj,
+			CK_ULONG max_count,
+			CK_ULONG_PTR count);
+	CK_RV (*C_FindObjectsFinal)(
+			CK_SESSION_HANDLE session);
+	CK_RV (*C_EncryptInit)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_OBJECT_HANDLE key);
+	CK_RV (*C_Encrypt)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_EncryptUpdate)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_EncryptFinal)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_DecryptInit)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR  mechanism,
+			CK_OBJECT_HANDLE  key);
+	CK_RV (*C_Decrypt)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_DecryptUpdate)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_DecryptFinal)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_DigestInit)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR  mechanism);
+	CK_RV (*C_Digest)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_DigestUpdate)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len);
+	CK_RV (*C_DigestKey)(
+			CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE  key);
+	CK_RV (*C_DigestFinal)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR digest,
+			CK_ULONG_PTR len);
+	CK_RV (*C_SignInit)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_OBJECT_HANDLE key);
+	CK_RV (*C_Sign)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_SignUpdate)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len);
+	CK_RV (*C_SignFinal)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_SignRecoverInit)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR  mechanism,
+			CK_OBJECT_HANDLE  key);
+	CK_RV (*C_SignRecover)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_VerifyInit)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_OBJECT_HANDLE key);
+	CK_RV (*C_Verify)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR sign,
+			CK_ULONG sign_len);
+	CK_RV (*C_VerifyUpdate)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len);
+	CK_RV (*C_VerifyFinal)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR sign,
+			CK_ULONG sign_len);
+	CK_RV (*C_VerifyRecoverInit)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_OBJECT_HANDLE key);
+	CK_RV (*C_VerifyRecover)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_DigestEncryptUpdate)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_DecryptDigestUpdate)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_SignEncryptUpdate)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_DecryptVerifyUpdate)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+	CK_RV (*C_GenerateKey)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count,
+			CK_OBJECT_HANDLE_PTR new_key);
+	CK_RV (*C_GenerateKeyPair)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_ATTRIBUTE_PTR pub_attribs,
+			CK_ULONG pub_count,
+			CK_ATTRIBUTE_PTR priv_attribs,
+			CK_ULONG priv_count,
+			CK_OBJECT_HANDLE_PTR pub_key,
+			CK_OBJECT_HANDLE_PTR priv_key);
+	CK_RV (*C_WrapKey)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_OBJECT_HANDLE wrap_key,
+			CK_OBJECT_HANDLE key,
+			CK_BYTE_PTR wrapped_key,
+			CK_ULONG_PTR wrapped_key_len);
+	CK_RV (*C_UnwrapKey)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_OBJECT_HANDLE unwrap_key,
+			CK_BYTE_PTR wrapped_key,
+			CK_ULONG wrapped_key_len,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count,
+			CK_OBJECT_HANDLE_PTR new_key);
+	CK_RV (*C_DeriveKey)(
+			CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_OBJECT_HANDLE derived_key,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count,
+			CK_OBJECT_HANDLE_PTR new_key);
+	CK_RV (*C_SeedRandom)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR seed,
+			CK_ULONG len);
+	CK_RV (*C_GenerateRandom)(
+			CK_SESSION_HANDLE session,
+			CK_BYTE_PTR out,
+			CK_ULONG len);
+	CK_RV (*C_GetFunctionStatus)(
+			CK_SESSION_HANDLE sessin);
+	CK_RV (*C_CancelFunction)(
+			CK_SESSION_HANDLE session);
+	CK_RV (*C_WaitForSlotEvent)(
+			CK_FLAGS flags,
+			CK_SLOT_ID_PTR slot,
+			CK_VOID_PTR rsv);
+};
+
+/* Optional init_args structure for C_Initialize */
+typedef struct CK_C_INITIALIZE_ARGS	CK_C_INITIALIZE_ARGS;
+typedef struct CK_C_INITIALIZE_ARGS *	CK_C_INITIALIZE_ARGS_PTR;
+
+struct CK_C_INITIALIZE_ARGS {
+	CK_CREATEMUTEX		CreateMutex;
+	CK_DESTROYMUTEX		DestroyMutex;
+	CK_LOCKMUTEX		LockMutex;
+	CK_UNLOCKMUTEX		UnlockMutex;
+	CK_FLAGS		flags;
+	CK_VOID_PTR		reserved;
+};
+
+/* Flags for field flags of struct ck_c_initialize_args */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS	(1U << 0)
+#define CKF_OS_LOCKING_OK			(1U << 1)
+
+CK_RV C_Initialize(
+		CK_VOID_PTR init_args);
+
+CK_RV C_Finalize(
+		CK_VOID_PTR res);
+
+CK_RV C_GetInfo(
+		CK_INFO_PTR info);
+
+CK_RV C_GetFunctionList(
+		CK_FUNCTION_LIST_PTR_PTR ppFunctionList);
+
+CK_RV C_GetSlotList(
+		CK_BBOOL token_present,
+		CK_SLOT_ID_PTR slots,
+		CK_ULONG_PTR count);
+
+CK_RV C_GetSlotInfo(
+		CK_SLOT_ID slot,
+		CK_SLOT_INFO_PTR info);
+
+CK_RV C_InitToken(
+		CK_SLOT_ID slot,
+		CK_UTF8CHAR_PTR pin,
+		CK_ULONG pin_len,
+		CK_UTF8CHAR_PTR label);
+
+CK_RV C_GetTokenInfo(
+		CK_SLOT_ID slot,
+		CK_TOKEN_INFO_PTR info);
+
+CK_RV C_GetMechanismList(
+		CK_SLOT_ID slot,
+		CK_MECHANISM_TYPE_PTR mechanisms,
+		CK_ULONG_PTR count);
+
+CK_RV C_GetMechanismInfo(
+		CK_SLOT_ID slot,
+		CK_MECHANISM_TYPE type,
+		CK_MECHANISM_INFO_PTR info);
+
+CK_RV C_OpenSession(
+		CK_SLOT_ID slot,
+		CK_FLAGS flags,
+		CK_VOID_PTR cookie,
+		CK_NOTIFY callback,
+		CK_SESSION_HANDLE_PTR session);
+
+CK_RV C_CloseSession(
+		CK_SESSION_HANDLE session);
+
+CK_RV C_CloseAllSessions(
+		CK_SLOT_ID slot);
+
+CK_RV C_GetSessionInfo(
+		CK_SESSION_HANDLE session,
+		CK_SESSION_INFO_PTR info);
+
+CK_RV C_InitPIN(
+		CK_SESSION_HANDLE session,
+		CK_UTF8CHAR_PTR pin,
+		CK_ULONG pin_len);
+
+CK_RV C_SetPIN(
+		CK_SESSION_HANDLE session,
+		CK_UTF8CHAR_PTR old,
+		CK_ULONG old_len,
+		CK_UTF8CHAR_PTR new,
+		CK_ULONG new_len);
+
+CK_RV C_Login(
+		CK_SESSION_HANDLE session,
+		CK_USER_TYPE user_type,
+		CK_UTF8CHAR_PTR pin,
+		CK_ULONG pin_len);
+
+CK_RV C_Logout(
+		CK_SESSION_HANDLE session);
+
+CK_RV C_GetOperationState(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR state,
+		CK_ULONG_PTR state_len);
+
+CK_RV C_SetOperationState(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR state,
+		CK_ULONG state_len,
+		CK_OBJECT_HANDLE ciph_key,
+		CK_OBJECT_HANDLE auth_key);
+
+CK_RV C_CreateObject(
+		CK_SESSION_HANDLE session,
+		CK_ATTRIBUTE_PTR attribs,
+		CK_ULONG count,
+		CK_OBJECT_HANDLE_PTR obj);
+
+CK_RV C_CopyObject(
+		CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE obj,
+		CK_ATTRIBUTE_PTR attribs,
+		CK_ULONG count,
+		CK_OBJECT_HANDLE_PTR new_obj);
+
+CK_RV C_DestroyObject(
+		CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE obj);
+
+CK_RV C_GetObjectSize(
+		CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE obj,
+		CK_ULONG_PTR out_size);
+
+CK_RV C_GetAttributeValue(
+		CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE obj,
+		CK_ATTRIBUTE_PTR attribs,
+		CK_ULONG count);
+
+CK_RV C_SetAttributeValue(
+		CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE obj,
+		CK_ATTRIBUTE_PTR attribs,
+		CK_ULONG count);
+
+CK_RV C_FindObjectsInit(
+		CK_SESSION_HANDLE session,
+		CK_ATTRIBUTE_PTR attribs,
+		CK_ULONG count);
+
+CK_RV C_FindObjects(
+		CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE_PTR obj,
+		CK_ULONG max_count,
+		CK_ULONG_PTR count);
+
+CK_RV C_FindObjectsFinal(
+		CK_SESSION_HANDLE session);
+
+CK_RV C_EncryptInit(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_OBJECT_HANDLE key);
+
+CK_RV C_Encrypt(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_EncryptUpdate(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_EncryptFinal(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_DecryptInit(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR  mechanism,
+		CK_OBJECT_HANDLE  key);
+
+CK_RV C_Decrypt(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_DecryptUpdate(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_DecryptFinal(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_DigestInit(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR  mechanism);
+
+CK_RV C_Digest(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_DigestUpdate(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len);
+
+CK_RV C_DigestKey(
+		CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE  key);
+
+CK_RV C_DigestFinal(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR digest,
+		CK_ULONG_PTR len);
+
+CK_RV C_SignInit(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_OBJECT_HANDLE key);
+
+CK_RV C_Sign(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_SignUpdate(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len);
+
+CK_RV C_SignFinal(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_SignRecoverInit(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR  mechanism,
+		CK_OBJECT_HANDLE  key);
+
+CK_RV C_SignRecover(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_VerifyInit(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_OBJECT_HANDLE key);
+
+CK_RV C_Verify(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR sign,
+		CK_ULONG sign_len);
+
+CK_RV C_VerifyUpdate(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len);
+
+CK_RV C_VerifyFinal(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR sign,
+		CK_ULONG sign_len);
+
+CK_RV C_VerifyRecoverInit(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_OBJECT_HANDLE key);
+
+CK_RV C_VerifyRecover(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_DigestEncryptUpdate(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_DecryptDigestUpdate(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_SignEncryptUpdate(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_DecryptVerifyUpdate(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+CK_RV C_GenerateKey(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_ATTRIBUTE_PTR attribs,
+		CK_ULONG count,
+		CK_OBJECT_HANDLE_PTR new_key);
+
+CK_RV C_GenerateKeyPair(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_ATTRIBUTE_PTR pub_attribs,
+		CK_ULONG pub_count,
+		CK_ATTRIBUTE_PTR priv_attribs,
+		CK_ULONG priv_count,
+		CK_OBJECT_HANDLE_PTR pub_key,
+		CK_OBJECT_HANDLE_PTR priv_key);
+
+CK_RV C_WrapKey(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_OBJECT_HANDLE wrap_key,
+		CK_OBJECT_HANDLE key,
+		CK_BYTE_PTR wrapped_key,
+		CK_ULONG_PTR wrapped_key_len);
+
+CK_RV C_UnwrapKey(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_OBJECT_HANDLE unwrap_key,
+		CK_BYTE_PTR wrapped_key,
+		CK_ULONG wrapped_key_len,
+		CK_ATTRIBUTE_PTR attribs,
+		CK_ULONG count,
+		CK_OBJECT_HANDLE_PTR new_key);
+
+CK_RV C_DeriveKey(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_OBJECT_HANDLE derived_key,
+		CK_ATTRIBUTE_PTR attribs,
+		CK_ULONG count,
+		CK_OBJECT_HANDLE_PTR new_key);
+
+CK_RV C_SeedRandom(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR seed,
+		CK_ULONG len);
+
+CK_RV C_GenerateRandom(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR out,
+		CK_ULONG len);
+
+CK_RV C_GetFunctionStatus(
+		CK_SESSION_HANDLE session);
+
+CK_RV C_CancelFunction(
+		CK_SESSION_HANDLE session);
+
+CK_RV C_WaitForSlotEvent(
+		CK_FLAGS flags,
+		CK_SLOT_ID_PTR slot,
+		CK_VOID_PTR rsv);
+
+CK_RV C_ImportKey(
+		CK_SESSION_HANDLE session,
+		CK_ATTRIBUTE_PTR attribs,
+		CK_ULONG count,
+		CK_BYTE_PTR keyblob,
+		CK_ULONG_PTR keyblob_length);
+
+CK_RV C_ImportKeyPair(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_ATTRIBUTE_PTR pub_attribs,
+		CK_ULONG pub_count,
+		CK_ATTRIBUTE_PTR priv_attribs,
+		CK_ULONG priv_count,
+		CK_BYTE_PTR keyblob,
+		CK_ULONG_PTR keyblob_length);
+
+CK_RV C_ExportKey(
+		CK_SESSION_HANDLE session,
+		CK_BYTE_PTR keyblob,
+		CK_ULONG keybloblength,
+		CK_BYTE_PTR pubkey,
+		CK_ULONG_PTR pubkeylength);
+
+CK_RV C_Utils(
+		CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__PKCS11_H__*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/sks_ck_debug.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/sks_ck_debug.h
new file mode 100644
index 0000000..68d49c0
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/sks_ck_debug.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SKS_CK_DEBUG_H
+#define __SKS_CK_DEBUG_H
+
+#include <pkcs11.h>
+
+/* Return a pointer to a string buffer of "CKA_xxx\0" attribute ID */
+const char *cka2str(CK_ATTRIBUTE_TYPE id);
+
+/* Return a pointer to a string buffer of "CKR_xxx\0" return value ID */
+const char *ckr2str(CK_RV id);
+
+/* Return a pointer to a string buffer of "CKM_xxx\0" mechanism ID */
+const char *ckm2str(CK_MECHANISM_TYPE id);
+
+/* Allocate and return a string descripbing the enabled flags */
+char *ck_slot_flag2str(CK_ULONG flags);
+char *ck_token_flag2str(CK_ULONG flags);
+char *ck_mecha_flag2str(CK_ULONG flags);
+
+const char *ckclass2str(CK_ULONG id);
+const char *cktype2str(CK_ULONG id, CK_ULONG class);
+
+const char *skscmd2str(unsigned int id);
+
+#endif /*__SKS_CK_DEBUG_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/sks_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/sks_ta.h
new file mode 120000
index 0000000..e5512c9
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/include/sks_ta.h
@@ -0,0 +1 @@
+../../ta/include/sks_ta.h
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_debug.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_debug.c
new file mode 100644
index 0000000..0637e12
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_debug.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sks_ta.h>
+#include <sks_ck_debug.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "local_utils.h"
+
+#define CK2STR_ENTRY(label)	{ .id = label, .string = #label }
+
+struct ck2str {
+	CK_ULONG id;
+	const char *string;
+};
+
+/*
+ * Return a pointer to a string buffer of "CKA_xxx\0" attribute ID
+ */
+static struct ck2str cka2str_table[] = {
+	/* OP-TEE SKS ID representing a not-yet defined value */
+	/* Standard CK attributes */
+	CK2STR_ENTRY(CKA_CLASS),
+	CK2STR_ENTRY(CKA_TOKEN),
+	CK2STR_ENTRY(CKA_PRIVATE),
+	CK2STR_ENTRY(CKA_LABEL),
+	CK2STR_ENTRY(CKA_APPLICATION),
+	CK2STR_ENTRY(CKA_VALUE),
+	CK2STR_ENTRY(CKA_OBJECT_ID),
+	CK2STR_ENTRY(CKA_CERTIFICATE_TYPE),
+	CK2STR_ENTRY(CKA_ISSUER),
+	CK2STR_ENTRY(CKA_SERIAL_NUMBER),
+	CK2STR_ENTRY(CKA_AC_ISSUER),
+	CK2STR_ENTRY(CKA_OWNER),
+	CK2STR_ENTRY(CKA_ATTR_TYPES),
+	CK2STR_ENTRY(CKA_TRUSTED),
+	CK2STR_ENTRY(CKA_CERTIFICATE_CATEGORY),
+	CK2STR_ENTRY(CKA_JAVA_MIDP_SECURITY_DOMAIN),
+	CK2STR_ENTRY(CKA_URL),
+	CK2STR_ENTRY(CKA_HASH_OF_SUBJECT_PUBLIC_KEY),
+	CK2STR_ENTRY(CKA_HASH_OF_ISSUER_PUBLIC_KEY),
+	CK2STR_ENTRY(CKA_NAME_HASH_ALGORITHM),
+	CK2STR_ENTRY(CKA_CHECK_VALUE),
+	CK2STR_ENTRY(CKA_KEY_TYPE),
+	CK2STR_ENTRY(CKA_SUBJECT),
+	CK2STR_ENTRY(CKA_ID),
+	CK2STR_ENTRY(CKA_SENSITIVE),
+	CK2STR_ENTRY(CKA_ENCRYPT),
+	CK2STR_ENTRY(CKA_DECRYPT),
+	CK2STR_ENTRY(CKA_WRAP),
+	CK2STR_ENTRY(CKA_UNWRAP),
+	CK2STR_ENTRY(CKA_SIGN),
+	CK2STR_ENTRY(CKA_SIGN_RECOVER),
+	CK2STR_ENTRY(CKA_VERIFY),
+	CK2STR_ENTRY(CKA_VERIFY_RECOVER),
+	CK2STR_ENTRY(CKA_DERIVE),
+	CK2STR_ENTRY(CKA_START_DATE),
+	CK2STR_ENTRY(CKA_END_DATE),
+	CK2STR_ENTRY(CKA_MODULUS),
+	CK2STR_ENTRY(CKA_MODULUS_BITS),
+	CK2STR_ENTRY(CKA_PUBLIC_EXPONENT),
+	CK2STR_ENTRY(CKA_PRIVATE_EXPONENT),
+	CK2STR_ENTRY(CKA_PRIME_1),
+	CK2STR_ENTRY(CKA_PRIME_2),
+	CK2STR_ENTRY(CKA_EXPONENT_1),
+	CK2STR_ENTRY(CKA_EXPONENT_2),
+	CK2STR_ENTRY(CKA_COEFFICIENT),
+	CK2STR_ENTRY(CKA_PUBLIC_KEY_INFO),
+	CK2STR_ENTRY(CKA_PRIME),
+	CK2STR_ENTRY(CKA_SUBPRIME),
+	CK2STR_ENTRY(CKA_BASE),
+	CK2STR_ENTRY(CKA_PRIME_BITS),
+	CK2STR_ENTRY(CKA_SUBPRIME_BITS),
+	CK2STR_ENTRY(CKA_VALUE_BITS),
+	CK2STR_ENTRY(CKA_VALUE_LEN),
+	CK2STR_ENTRY(CKA_EXTRACTABLE),
+	CK2STR_ENTRY(CKA_LOCAL),
+	CK2STR_ENTRY(CKA_NEVER_EXTRACTABLE),
+	CK2STR_ENTRY(CKA_ALWAYS_SENSITIVE),
+	CK2STR_ENTRY(CKA_KEY_GEN_MECHANISM),
+	CK2STR_ENTRY(CKA_MODIFIABLE),
+	CK2STR_ENTRY(CKA_COPYABLE),
+	CK2STR_ENTRY(CKA_DESTROYABLE),
+	CK2STR_ENTRY(CKA_EC_PARAMS),
+	CK2STR_ENTRY(CKA_EC_POINT),
+	CK2STR_ENTRY(CKA_ALWAYS_AUTHENTICATE),
+	CK2STR_ENTRY(CKA_WRAP_WITH_TRUSTED),
+	CK2STR_ENTRY(CKA_WRAP_TEMPLATE),
+	CK2STR_ENTRY(CKA_UNWRAP_TEMPLATE),
+	CK2STR_ENTRY(CKA_DERIVE_TEMPLATE),
+	CK2STR_ENTRY(CKA_OTP_FORMAT),
+	CK2STR_ENTRY(CKA_OTP_LENGTH),
+	CK2STR_ENTRY(CKA_OTP_TIME_INTERVAL),
+	CK2STR_ENTRY(CKA_OTP_USER_FRIENDLY_MODE),
+	CK2STR_ENTRY(CKA_OTP_CHALLENGE_REQUIREMENT),
+	CK2STR_ENTRY(CKA_OTP_TIME_REQUIREMENT),
+	CK2STR_ENTRY(CKA_OTP_COUNTER_REQUIREMENT),
+	CK2STR_ENTRY(CKA_OTP_PIN_REQUIREMENT),
+	CK2STR_ENTRY(CKA_OTP_COUNTER),
+	CK2STR_ENTRY(CKA_OTP_TIME),
+	CK2STR_ENTRY(CKA_OTP_USER_IDENTIFIER),
+	CK2STR_ENTRY(CKA_OTP_SERVICE_IDENTIFIER),
+	CK2STR_ENTRY(CKA_OTP_SERVICE_LOGO),
+	CK2STR_ENTRY(CKA_OTP_SERVICE_LOGO_TYPE),
+	CK2STR_ENTRY(CKA_GOSTR3410_PARAMS),
+	CK2STR_ENTRY(CKA_GOSTR3411_PARAMS),
+	CK2STR_ENTRY(CKA_GOST28147_PARAMS),
+	CK2STR_ENTRY(CKA_HW_FEATURE_TYPE),
+	CK2STR_ENTRY(CKA_RESET_ON_INIT),
+	CK2STR_ENTRY(CKA_HAS_RESET),
+	CK2STR_ENTRY(CKA_PIXEL_X),
+	CK2STR_ENTRY(CKA_PIXEL_Y),
+	CK2STR_ENTRY(CKA_RESOLUTION),
+	CK2STR_ENTRY(CKA_CHAR_ROWS),
+	CK2STR_ENTRY(CKA_CHAR_COLUMNS),
+	CK2STR_ENTRY(CKA_COLOR),
+	CK2STR_ENTRY(CKA_BITS_PER_PIXEL),
+	CK2STR_ENTRY(CKA_CHAR_SETS),
+	CK2STR_ENTRY(CKA_ENCODING_METHODS),
+	CK2STR_ENTRY(CKA_MIME_TYPES),
+	CK2STR_ENTRY(CKA_MECHANISM_TYPE),
+	CK2STR_ENTRY(CKA_REQUIRED_CMS_ATTRIBUTES),
+	CK2STR_ENTRY(CKA_DEFAULT_CMS_ATTRIBUTES),
+	CK2STR_ENTRY(CKA_SUPPORTED_CMS_ATTRIBUTES),
+	CK2STR_ENTRY(CKA_ALLOWED_MECHANISMS),
+	CK2STR_ENTRY(CKA_VENDOR_DEFINED),
+};
+
+const char *cka2str(CK_ATTRIBUTE_TYPE id)
+{
+	static const char vendor_range[] = "<unknwon-vendor-defined>";
+	static const char unknown[] = "<unknown-identifier>";
+	const int count = sizeof(cka2str_table) / sizeof(struct ck2str);
+	int n;
+
+	for (n = 0; n < count; n++) {
+		if (id == cka2str_table[n].id)
+			return cka2str_table[n].string;
+	}
+
+	if (id > CKA_VENDOR_DEFINED)
+		return vendor_range;
+
+	return unknown;
+}
+
+/*
+ * ckr2str - Return a pointer to a string buffer of "CKR_xxx\0" return value ID
+ */
+static struct ck2str ckr2str_table[] = {
+	CK2STR_ENTRY(CKR_OK),
+	CK2STR_ENTRY(CKR_CANCEL),
+	CK2STR_ENTRY(CKR_HOST_MEMORY),
+	CK2STR_ENTRY(CKR_SLOT_ID_INVALID),
+	CK2STR_ENTRY(CKR_GENERAL_ERROR),
+	CK2STR_ENTRY(CKR_FUNCTION_FAILED),
+	CK2STR_ENTRY(CKR_ARGUMENTS_BAD),
+	CK2STR_ENTRY(CKR_NO_EVENT),
+	CK2STR_ENTRY(CKR_NEED_TO_CREATE_THREADS),
+	CK2STR_ENTRY(CKR_CANT_LOCK),
+	CK2STR_ENTRY(CKR_ATTRIBUTE_READ_ONLY),
+	CK2STR_ENTRY(CKR_ATTRIBUTE_SENSITIVE),
+	CK2STR_ENTRY(CKR_ATTRIBUTE_TYPE_INVALID),
+	CK2STR_ENTRY(CKR_ATTRIBUTE_VALUE_INVALID),
+	CK2STR_ENTRY(CKR_ACTION_PROHIBITED),
+	CK2STR_ENTRY(CKR_DATA_INVALID),
+	CK2STR_ENTRY(CKR_DATA_LEN_RANGE),
+	CK2STR_ENTRY(CKR_DEVICE_ERROR),
+	CK2STR_ENTRY(CKR_DEVICE_MEMORY),
+	CK2STR_ENTRY(CKR_DEVICE_REMOVED),
+	CK2STR_ENTRY(CKR_ENCRYPTED_DATA_INVALID),
+	CK2STR_ENTRY(CKR_ENCRYPTED_DATA_LEN_RANGE),
+	CK2STR_ENTRY(CKR_FUNCTION_CANCELED),
+	CK2STR_ENTRY(CKR_FUNCTION_NOT_PARALLEL),
+	CK2STR_ENTRY(CKR_FUNCTION_NOT_SUPPORTED),
+	CK2STR_ENTRY(CKR_KEY_HANDLE_INVALID),
+	CK2STR_ENTRY(CKR_KEY_SIZE_RANGE),
+	CK2STR_ENTRY(CKR_KEY_TYPE_INCONSISTENT),
+	CK2STR_ENTRY(CKR_KEY_NOT_NEEDED),
+	CK2STR_ENTRY(CKR_KEY_CHANGED),
+	CK2STR_ENTRY(CKR_KEY_NEEDED),
+	CK2STR_ENTRY(CKR_KEY_INDIGESTIBLE),
+	CK2STR_ENTRY(CKR_KEY_FUNCTION_NOT_PERMITTED),
+	CK2STR_ENTRY(CKR_KEY_NOT_WRAPPABLE),
+	CK2STR_ENTRY(CKR_KEY_UNEXTRACTABLE),
+	CK2STR_ENTRY(CKR_MECHANISM_INVALID),
+	CK2STR_ENTRY(CKR_MECHANISM_PARAM_INVALID),
+	CK2STR_ENTRY(CKR_OBJECT_HANDLE_INVALID),
+	CK2STR_ENTRY(CKR_OPERATION_ACTIVE),
+	CK2STR_ENTRY(CKR_OPERATION_NOT_INITIALIZED),
+	CK2STR_ENTRY(CKR_PIN_INCORRECT),
+	CK2STR_ENTRY(CKR_PIN_INVALID),
+	CK2STR_ENTRY(CKR_PIN_LEN_RANGE),
+	CK2STR_ENTRY(CKR_PIN_EXPIRED),
+	CK2STR_ENTRY(CKR_PIN_LOCKED),
+	CK2STR_ENTRY(CKR_SESSION_CLOSED),
+	CK2STR_ENTRY(CKR_SESSION_COUNT),
+	CK2STR_ENTRY(CKR_SESSION_HANDLE_INVALID),
+	CK2STR_ENTRY(CKR_SESSION_PARALLEL_NOT_SUPPORTED),
+	CK2STR_ENTRY(CKR_SESSION_READ_ONLY),
+	CK2STR_ENTRY(CKR_SESSION_EXISTS),
+	CK2STR_ENTRY(CKR_SESSION_READ_ONLY_EXISTS),
+	CK2STR_ENTRY(CKR_SESSION_READ_WRITE_SO_EXISTS),
+	CK2STR_ENTRY(CKR_SIGNATURE_INVALID),
+	CK2STR_ENTRY(CKR_SIGNATURE_LEN_RANGE),
+	CK2STR_ENTRY(CKR_TEMPLATE_INCOMPLETE),
+	CK2STR_ENTRY(CKR_TEMPLATE_INCONSISTENT),
+	CK2STR_ENTRY(CKR_TOKEN_NOT_PRESENT),
+	CK2STR_ENTRY(CKR_TOKEN_NOT_RECOGNIZED),
+	CK2STR_ENTRY(CKR_TOKEN_WRITE_PROTECTED),
+	CK2STR_ENTRY(CKR_UNWRAPPING_KEY_HANDLE_INVALID),
+	CK2STR_ENTRY(CKR_UNWRAPPING_KEY_SIZE_RANGE),
+	CK2STR_ENTRY(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT),
+	CK2STR_ENTRY(CKR_USER_ALREADY_LOGGED_IN),
+	CK2STR_ENTRY(CKR_USER_NOT_LOGGED_IN),
+	CK2STR_ENTRY(CKR_USER_PIN_NOT_INITIALIZED),
+	CK2STR_ENTRY(CKR_USER_TYPE_INVALID),
+	CK2STR_ENTRY(CKR_USER_ANOTHER_ALREADY_LOGGED_IN),
+	CK2STR_ENTRY(CKR_USER_TOO_MANY_TYPES),
+	CK2STR_ENTRY(CKR_WRAPPED_KEY_INVALID),
+	CK2STR_ENTRY(CKR_WRAPPED_KEY_LEN_RANGE),
+	CK2STR_ENTRY(CKR_WRAPPING_KEY_HANDLE_INVALID),
+	CK2STR_ENTRY(CKR_WRAPPING_KEY_SIZE_RANGE),
+	CK2STR_ENTRY(CKR_WRAPPING_KEY_TYPE_INCONSISTENT),
+	CK2STR_ENTRY(CKR_RANDOM_SEED_NOT_SUPPORTED),
+	CK2STR_ENTRY(CKR_RANDOM_NO_RNG),
+	CK2STR_ENTRY(CKR_DOMAIN_PARAMS_INVALID),
+	CK2STR_ENTRY(CKR_CURVE_NOT_SUPPORTED),
+	CK2STR_ENTRY(CKR_BUFFER_TOO_SMALL),
+	CK2STR_ENTRY(CKR_SAVED_STATE_INVALID),
+	CK2STR_ENTRY(CKR_INFORMATION_SENSITIVE),
+	CK2STR_ENTRY(CKR_STATE_UNSAVEABLE),
+	CK2STR_ENTRY(CKR_CRYPTOKI_NOT_INITIALIZED),
+	CK2STR_ENTRY(CKR_CRYPTOKI_ALREADY_INITIALIZED),
+	CK2STR_ENTRY(CKR_MUTEX_BAD),
+	CK2STR_ENTRY(CKR_MUTEX_NOT_LOCKED),
+	CK2STR_ENTRY(CKR_NEW_PIN_MODE),
+	CK2STR_ENTRY(CKR_NEXT_OTP),
+	CK2STR_ENTRY(CKR_EXCEEDED_MAX_ITERATIONS),
+	CK2STR_ENTRY(CKR_FIPS_SELF_TEST_FAILED),
+	CK2STR_ENTRY(CKR_LIBRARY_LOAD_FAILED),
+	CK2STR_ENTRY(CKR_PIN_TOO_WEAK),
+	CK2STR_ENTRY(CKR_PUBLIC_KEY_INVALID),
+	CK2STR_ENTRY(CKR_FUNCTION_REJECTED),
+	CK2STR_ENTRY(CKR_VENDOR_DEFINED),
+};
+
+const char *ckr2str(CK_RV id)
+{
+	static const char vendor[] = "(vendor-defined)";
+	static const char unknown[] = "(unknown)";
+	const int count = sizeof(ckr2str_table) / sizeof(struct ck2str);
+	int n;
+
+	for (n = 0; n < count; n++) {
+		if (id == ckr2str_table[n].id)
+			return ckr2str_table[n].string;
+	}
+
+	if (id >= CKR_VENDOR_DEFINED)
+		return vendor;
+
+	return unknown;
+}
+
+/*
+ * ckr2str - Return a pointer to a string buffer of "CKM_xxx\0" mechanism ID
+ *
+ * This does not cover the whole IDs defined by the PKCS#11. To be updated
+ * when needed.
+ */
+static struct ck2str ckm2str_table[] = {
+	CK2STR_ENTRY(CKM_RSA_PKCS_KEY_PAIR_GEN),
+	CK2STR_ENTRY(CKM_RSA_PKCS),
+	CK2STR_ENTRY(CKM_RSA_9796),
+	CK2STR_ENTRY(CKM_RSA_X_509),
+	CK2STR_ENTRY(CKM_SHA1_RSA_PKCS),
+	CK2STR_ENTRY(CKM_RSA_PKCS_OAEP),
+	CK2STR_ENTRY(CKM_RSA_PKCS_PSS),
+	CK2STR_ENTRY(CKM_SHA1_RSA_PKCS_PSS),
+	CK2STR_ENTRY(CKM_SHA256_RSA_PKCS),
+	CK2STR_ENTRY(CKM_SHA384_RSA_PKCS),
+	CK2STR_ENTRY(CKM_SHA512_RSA_PKCS),
+	CK2STR_ENTRY(CKM_SHA256_RSA_PKCS_PSS),
+	CK2STR_ENTRY(CKM_SHA384_RSA_PKCS_PSS),
+	CK2STR_ENTRY(CKM_SHA512_RSA_PKCS_PSS),
+	CK2STR_ENTRY(CKM_SHA224_RSA_PKCS),
+	CK2STR_ENTRY(CKM_SHA224_RSA_PKCS_PSS),
+	CK2STR_ENTRY(CKM_SHA512_224),
+	CK2STR_ENTRY(CKM_SHA512_224_HMAC),
+	CK2STR_ENTRY(CKM_SHA512_224_HMAC_GENERAL),
+	CK2STR_ENTRY(CKM_SHA512_224_KEY_DERIVATION),
+	CK2STR_ENTRY(CKM_SHA512_256),
+	CK2STR_ENTRY(CKM_SHA512_256_HMAC),
+	CK2STR_ENTRY(CKM_SHA512_256_HMAC_GENERAL),
+	CK2STR_ENTRY(CKM_SHA512_256_KEY_DERIVATION),
+	CK2STR_ENTRY(CKM_MD5_HMAC),
+	CK2STR_ENTRY(CKM_MD5_HMAC_GENERAL),
+	CK2STR_ENTRY(CKM_SHA_1),
+	CK2STR_ENTRY(CKM_SHA_1_HMAC),
+	CK2STR_ENTRY(CKM_SHA_1_HMAC_GENERAL),
+	CK2STR_ENTRY(CKM_SHA256),
+	CK2STR_ENTRY(CKM_SHA256_HMAC),
+	CK2STR_ENTRY(CKM_SHA256_HMAC_GENERAL),
+	CK2STR_ENTRY(CKM_SHA224),
+	CK2STR_ENTRY(CKM_SHA224_HMAC),
+	CK2STR_ENTRY(CKM_SHA224_HMAC_GENERAL),
+	CK2STR_ENTRY(CKM_SHA384),
+	CK2STR_ENTRY(CKM_SHA384_HMAC),
+	CK2STR_ENTRY(CKM_SHA384_HMAC_GENERAL),
+	CK2STR_ENTRY(CKM_SHA512),
+	CK2STR_ENTRY(CKM_SHA512_HMAC),
+	CK2STR_ENTRY(CKM_SHA512_HMAC_GENERAL),
+	CK2STR_ENTRY(CKM_HOTP_KEY_GEN),
+	CK2STR_ENTRY(CKM_HOTP),
+	CK2STR_ENTRY(CKM_GENERIC_SECRET_KEY_GEN),
+	CK2STR_ENTRY(CKM_SHA1_KEY_DERIVATION),
+	CK2STR_ENTRY(CKM_SHA256_KEY_DERIVATION),
+	CK2STR_ENTRY(CKM_SHA384_KEY_DERIVATION),
+	CK2STR_ENTRY(CKM_SHA512_KEY_DERIVATION),
+	CK2STR_ENTRY(CKM_SHA224_KEY_DERIVATION),
+	CK2STR_ENTRY(CKM_EC_KEY_PAIR_GEN),
+	CK2STR_ENTRY(CKM_ECDSA),
+	CK2STR_ENTRY(CKM_ECDSA_SHA1),
+	CK2STR_ENTRY(CKM_ECDSA_SHA224),
+	CK2STR_ENTRY(CKM_ECDSA_SHA256),
+	CK2STR_ENTRY(CKM_ECDSA_SHA384),
+	CK2STR_ENTRY(CKM_ECDSA_SHA512),
+	CK2STR_ENTRY(CKM_ECDH1_DERIVE),
+	CK2STR_ENTRY(CKM_ECDH1_COFACTOR_DERIVE),
+	CK2STR_ENTRY(CKM_ECMQV_DERIVE),
+	CK2STR_ENTRY(CKM_ECDH_AES_KEY_WRAP),
+	CK2STR_ENTRY(CKM_RSA_AES_KEY_WRAP),
+	CK2STR_ENTRY(CKM_AES_KEY_GEN),
+	CK2STR_ENTRY(CKM_AES_ECB),
+	CK2STR_ENTRY(CKM_AES_CBC),
+	CK2STR_ENTRY(CKM_AES_MAC),
+	CK2STR_ENTRY(CKM_AES_MAC_GENERAL),
+	CK2STR_ENTRY(CKM_AES_CBC_PAD),
+	CK2STR_ENTRY(CKM_AES_CTR),
+	CK2STR_ENTRY(CKM_AES_GCM),
+	CK2STR_ENTRY(CKM_AES_CCM),
+	CK2STR_ENTRY(CKM_AES_CTS),
+	CK2STR_ENTRY(CKM_AES_CMAC),
+	CK2STR_ENTRY(CKM_AES_CMAC_GENERAL),
+	CK2STR_ENTRY(CKM_AES_XCBC_MAC),
+	CK2STR_ENTRY(CKM_AES_XCBC_MAC_96),
+	CK2STR_ENTRY(CKM_AES_GMAC),
+	CK2STR_ENTRY(CKM_DES3_ECB_ENCRYPT_DATA),
+	CK2STR_ENTRY(CKM_DES3_CBC_ENCRYPT_DATA),
+	CK2STR_ENTRY(CKM_AES_ECB_ENCRYPT_DATA),
+	CK2STR_ENTRY(CKM_AES_CBC_ENCRYPT_DATA),
+	CK2STR_ENTRY(CKM_AES_KEY_WRAP),
+	CK2STR_ENTRY(CKM_AES_KEY_WRAP_PAD),
+	CK2STR_ENTRY(CKM_MD5),
+	CK2STR_ENTRY(CKM_SHA_1),
+	CK2STR_ENTRY(CKM_SHA224),
+	CK2STR_ENTRY(CKM_SHA256),
+	CK2STR_ENTRY(CKM_SHA384),
+	CK2STR_ENTRY(CKM_SHA512),
+	CK2STR_ENTRY(CKM_DES_KEY_GEN),
+	CK2STR_ENTRY(CKM_DES_ECB),
+	CK2STR_ENTRY(CKM_DES_CBC),
+	CK2STR_ENTRY(CKM_DES_MAC),
+	CK2STR_ENTRY(CKM_DES_MAC_GENERAL),
+	CK2STR_ENTRY(CKM_DES_CBC_PAD),
+	CK2STR_ENTRY(CKM_VENDOR_DEFINED),
+};
+
+const char *ckm2str(CK_MECHANISM_TYPE id)
+{
+	static const char vendor[] = "(vendor-defined)";
+	static const char unknown[] = "(unknown)";
+	const int count = sizeof(ckm2str_table) / sizeof(struct ck2str);
+	int n;
+
+	for (n = 0; n < count; n++) {
+		if (id == ckm2str_table[n].id)
+			return ckm2str_table[n].string;
+	}
+
+	if (id >= CKM_VENDOR_DEFINED)
+		return vendor;
+
+	return unknown;
+}
+
+static struct ck2str skscmd2str_table[] = {
+	CK2STR_ENTRY(SKS_CMD_PING),
+	CK2STR_ENTRY(SKS_CMD_CK_SLOT_LIST),
+	CK2STR_ENTRY(SKS_CMD_CK_SLOT_INFO),
+	CK2STR_ENTRY(SKS_CMD_CK_TOKEN_INFO),
+	CK2STR_ENTRY(SKS_CMD_CK_MECHANISM_IDS),
+	CK2STR_ENTRY(SKS_CMD_CK_MECHANISM_INFO),
+	CK2STR_ENTRY(SKS_CMD_CK_INIT_TOKEN),
+	CK2STR_ENTRY(SKS_CMD_CK_INIT_PIN),
+	CK2STR_ENTRY(SKS_CMD_CK_SET_PIN),
+	CK2STR_ENTRY(SKS_CMD_CK_OPEN_RO_SESSION),
+	CK2STR_ENTRY(SKS_CMD_CK_OPEN_RW_SESSION),
+	CK2STR_ENTRY(SKS_CMD_CK_CLOSE_SESSION),
+	CK2STR_ENTRY(SKS_CMD_CK_SESSION_INFO),
+	CK2STR_ENTRY(SKS_CMD_IMPORT_OBJECT),
+	CK2STR_ENTRY(SKS_CMD_DESTROY_OBJECT),
+	CK2STR_ENTRY(SKS_CMD_ENCRYPT_INIT),
+	CK2STR_ENTRY(SKS_CMD_DECRYPT_INIT),
+	CK2STR_ENTRY(SKS_CMD_ENCRYPT_UPDATE),
+	CK2STR_ENTRY(SKS_CMD_DECRYPT_UPDATE),
+	CK2STR_ENTRY(SKS_CMD_DECRYPT_FINAL),
+	CK2STR_ENTRY(SKS_CMD_ENCRYPT_FINAL),
+};
+
+const char *skscmd2str(unsigned int id)
+{
+	static const char unknown[] = "<invalid-command-id>";
+	const int count = sizeof(skscmd2str_table) / sizeof(struct ck2str);
+	int n;
+
+	for (n = 0; n < count; n++) {
+		if (id == skscmd2str_table[n].id)
+			return skscmd2str_table[n].string;
+	}
+
+	return unknown;
+}
+
+static struct ck2str slotflag2str_table[] = {
+	CK2STR_ENTRY(CKF_TOKEN_PRESENT),
+	CK2STR_ENTRY(CKF_REMOVABLE_DEVICE),
+	CK2STR_ENTRY(CKF_HW_SLOT),
+};
+
+static const char *slot_flags2str(CK_ULONG flags)
+{
+	const int count = sizeof(slotflag2str_table) / sizeof(struct ck2str);
+	int n;
+
+	for (n = 0; n < count; n++) {
+		if (flags & slotflag2str_table[n].id)
+			return slotflag2str_table[n].string;
+	}
+
+	return NULL;
+}
+
+static struct ck2str tokenflag2str_table[] = {
+	CK2STR_ENTRY(CKF_RNG),
+	CK2STR_ENTRY(CKF_WRITE_PROTECTED),
+	CK2STR_ENTRY(CKF_LOGIN_REQUIRED),
+	CK2STR_ENTRY(CKF_USER_PIN_INITIALIZED),
+	CK2STR_ENTRY(CKF_RESTORE_KEY_NOT_NEEDED),
+	CK2STR_ENTRY(CKF_CLOCK_ON_TOKEN),
+	CK2STR_ENTRY(CKF_PROTECTED_AUTHENTICATION_PATH),
+	CK2STR_ENTRY(CKF_DUAL_CRYPTO_OPERATIONS),
+	CK2STR_ENTRY(CKF_TOKEN_INITIALIZED),
+	CK2STR_ENTRY(CKF_SECONDARY_AUTHENTICATION),
+	CK2STR_ENTRY(CKF_USER_PIN_COUNT_LOW),
+	CK2STR_ENTRY(CKF_USER_PIN_FINAL_TRY),
+	CK2STR_ENTRY(CKF_USER_PIN_LOCKED),
+	CK2STR_ENTRY(CKF_USER_PIN_TO_BE_CHANGED),
+	CK2STR_ENTRY(CKF_SO_PIN_COUNT_LOW),
+	CK2STR_ENTRY(CKF_SO_PIN_FINAL_TRY),
+	CK2STR_ENTRY(CKF_SO_PIN_LOCKED),
+	CK2STR_ENTRY(CKF_SO_PIN_TO_BE_CHANGED),
+	CK2STR_ENTRY(CKF_ERROR_STATE),
+};
+
+static const char *token_flags2str(CK_ULONG flags)
+{
+	const int count = sizeof(tokenflag2str_table) / sizeof(struct ck2str);
+	int n;
+
+	for (n = 0; n < count; n++) {
+		if (flags & tokenflag2str_table[n].id)
+			return tokenflag2str_table[n].string;
+	}
+
+	return NULL;
+}
+
+static struct ck2str mechaflag2str_table[] = {
+	CK2STR_ENTRY(CKF_HW),
+	CK2STR_ENTRY(CKF_ENCRYPT),
+	CK2STR_ENTRY(CKF_DECRYPT),
+	CK2STR_ENTRY(CKF_DIGEST),
+	CK2STR_ENTRY(CKF_SIGN),
+	CK2STR_ENTRY(CKF_SIGN_RECOVER),
+	CK2STR_ENTRY(CKF_VERIFY),
+	CK2STR_ENTRY(CKF_VERIFY_RECOVER),
+	CK2STR_ENTRY(CKF_GENERATE),
+	CK2STR_ENTRY(CKF_GENERATE_KEY_PAIR),
+	CK2STR_ENTRY(CKF_WRAP),
+	CK2STR_ENTRY(CKF_UNWRAP),
+	CK2STR_ENTRY(CKF_DERIVE),
+	CK2STR_ENTRY(CKF_EC_F_P),
+	CK2STR_ENTRY(CKF_EC_F_2M),
+	CK2STR_ENTRY(CKF_EC_ECPARAMETERS),
+	CK2STR_ENTRY(CKF_EC_NAMEDCURVE),
+	CK2STR_ENTRY(CKF_EC_UNCOMPRESS),
+	CK2STR_ENTRY(CKF_EC_COMPRESS),
+	CK2STR_ENTRY(CKF_EXTENSION),
+};
+
+static const char *mecha_flags2str(CK_ULONG flags)
+{
+	const int count = sizeof(mechaflag2str_table) / sizeof(struct ck2str);
+	int n;
+
+	for (n = 0; n < count; n++) {
+		if (flags & mechaflag2str_table[n].id)
+			return mechaflag2str_table[n].string;
+	}
+
+	return NULL;
+}
+
+enum ck_debug_flag_type {
+	CKDBG_SLOT,
+	CKDBG_TOKEN,
+	CKDBG_KEY,
+	CKDBG_CERTIF,
+	CKDBG_MECHA,
+};
+
+static char *__flag2str(CK_ULONG flags, enum ck_debug_flag_type type)
+{
+	char *str = NULL;
+	size_t size = 0;
+	int mask = 1;
+
+	for (mask = 1; flags && mask; flags &= ~mask, mask = mask << 1) {
+		char const *label = NULL;
+		size_t label_size;
+		char *nstr;
+
+		if (!(flags & mask))
+			continue;
+
+		switch(type) {
+		case CKDBG_SLOT:
+			label = slot_flags2str(mask);
+			break;
+		case CKDBG_TOKEN:
+			label = token_flags2str(mask);
+			break;
+		case CKDBG_MECHA:
+			label = mecha_flags2str(mask);
+			break;
+		default:
+			return NULL;
+		}
+
+		if (!label)
+			continue;
+
+		/* 4 digit prefix "CKF_" is not dumped */
+		if (!memcmp(label, "CKF_", 4))
+			label += 4;
+
+		/* Extra space digit */
+		label_size = strlen(label) + 1;
+
+		/* Always allocate 1 more digit for terminal '\0' */
+		nstr = realloc(str, size + label_size + 1);
+		if (!nstr) {
+			free(str);
+			return NULL;
+		}
+
+		snprintf(nstr + size, label_size + 1, "%s ", label);
+		str = nstr;
+		size += label_size;
+	}
+
+	return str;
+}
+
+char *ck_slot_flag2str(CK_ULONG flags)
+{
+	return __flag2str(flags, CKDBG_SLOT);
+}
+
+char *ck_token_flag2str(CK_ULONG flags)
+{
+	return __flag2str(flags, CKDBG_TOKEN);
+}
+
+char *ck_mecha_flag2str(CK_ULONG flags)
+{
+	return __flag2str(flags, CKDBG_MECHA);
+}
+
+static struct ck2str class2str_table[] = {
+	CK2STR_ENTRY(CKO_DATA),
+	CK2STR_ENTRY(CKO_CERTIFICATE),
+	CK2STR_ENTRY(CKO_PUBLIC_KEY),
+	CK2STR_ENTRY(CKO_PRIVATE_KEY),
+	CK2STR_ENTRY(CKO_SECRET_KEY),
+	CK2STR_ENTRY(CKO_HW_FEATURE),
+	CK2STR_ENTRY(CKO_DOMAIN_PARAMETERS),
+	CK2STR_ENTRY(CKO_MECHANISM),
+	CK2STR_ENTRY(CKO_OTP_KEY),
+	CK2STR_ENTRY(CKO_VENDOR_DEFINED),
+};
+
+const char *ckclass2str(CK_ULONG id)
+{
+	const int count = sizeof(class2str_table) / sizeof(struct ck2str);
+	int n;
+
+	for (n = 0; n < count; n++)
+		if (id == class2str_table[n].id)
+			return class2str_table[n].string;
+
+	return NULL;
+}
+
+static struct ck2str symkey2str_table[] = {
+	CK2STR_ENTRY(CKK_RSA),
+	CK2STR_ENTRY(CKK_DSA),
+	CK2STR_ENTRY(CKK_DH),
+	CK2STR_ENTRY(CKK_ECDSA),
+	CK2STR_ENTRY(CKK_EC),
+	CK2STR_ENTRY(CKK_GENERIC_SECRET),
+	CK2STR_ENTRY(CKK_DES),
+	CK2STR_ENTRY(CKK_DES2),
+	CK2STR_ENTRY(CKK_DES3),
+	CK2STR_ENTRY(CKK_AES),
+	CK2STR_ENTRY(CKK_HOTP),
+	CK2STR_ENTRY(CKK_MD5_HMAC),
+	CK2STR_ENTRY(CKK_SHA_1_HMAC),
+	CK2STR_ENTRY(CKK_SHA256_HMAC),
+	CK2STR_ENTRY(CKK_SHA384_HMAC),
+	CK2STR_ENTRY(CKK_SHA512_HMAC),
+	CK2STR_ENTRY(CKK_SHA224_HMAC),
+	CK2STR_ENTRY(CKK_VENDOR_DEFINED),
+};
+
+const char *cktype2str(CK_ULONG id, CK_ULONG class)
+{
+	int count;
+	struct ck2str *table;
+	int n;
+
+	switch (class) {
+	case CKO_DATA:
+		/* No type for data object */
+		return NULL;
+	case CKO_SECRET_KEY:
+		count = sizeof(symkey2str_table);
+		table = symkey2str_table;
+		break;
+	case CKO_MECHANISM:
+		return ckm2str(id);
+	case CKO_CERTIFICATE:
+	case CKO_DOMAIN_PARAMETERS:
+	case CKO_HW_FEATURE:
+	case CKO_PUBLIC_KEY:
+	case CKO_PRIVATE_KEY:
+	case CKO_OTP_KEY:
+		/* Not supported */
+		return NULL;
+	default:
+		/* Unknwon */
+		return NULL;
+	}
+
+	count /= sizeof(struct ck2str);
+	for (n = 0; n < count; n++)
+		if (id == table[n].id)
+			return table[n].string;
+
+	return NULL;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.c
new file mode 100644
index 0000000..212793f
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.c
@@ -0,0 +1,903 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "ck_helpers.h"
+#include "local_utils.h"
+
+/*
+ * SKS TA returns Cryptoki like information structure.
+ * These routine convert the SKS format structure and bit flags
+ * from/into Cryptoki format structures and bit flags.
+ */
+#define MEMCPY_FIELD(_dst, _src, _f) \
+	do { \
+		memcpy((_dst)->_f, (_src)->_f, sizeof((_dst)->_f)); \
+		if (sizeof((_dst)->_f) != sizeof((_src)->_f)) \
+			return CKR_GENERAL_ERROR; \
+	} while (0)
+
+#define MEMCPY_VERSION(_dst, _src, _f) \
+	do { \
+		memcpy(&(_dst)->_f, (_src)->_f, sizeof(CK_VERSION)); \
+		if (sizeof(CK_VERSION) != sizeof((_src)->_f)) \
+			return CKR_GENERAL_ERROR; \
+	} while (0)
+
+static CK_RV sks2ck_all_slot_flags(CK_SLOT_INFO_PTR ck_info,
+				   struct sks_slot_info *sks_info)
+{
+	CK_FLAGS ck_flag;
+	uint32_t sks_mask;
+
+	ck_info->flags = 0;
+	for (sks_mask = 1; sks_mask; sks_mask <<= 1) {
+
+		/* Skip sks token flags without a CK equilavent */
+		if (sks2ck_slot_flag(&ck_flag, sks_mask))
+			continue;
+
+		if (sks_info->flags & sks_mask)
+			ck_info->flags |= ck_flag;
+	}
+
+	return CKR_OK;
+}
+
+CK_RV sks2ck_slot_info(CK_SLOT_INFO_PTR ck_info,
+			struct sks_slot_info *sks_info)
+{
+	CK_RV rv;
+
+	MEMCPY_FIELD(ck_info, sks_info, slotDescription);
+	MEMCPY_FIELD(ck_info, sks_info, manufacturerID);
+
+	rv = sks2ck_all_slot_flags(ck_info, sks_info);
+	if (rv)
+		return rv;
+
+	MEMCPY_VERSION(ck_info, sks_info, hardwareVersion);
+	MEMCPY_VERSION(ck_info, sks_info, firmwareVersion);
+
+	return CKR_OK;
+}
+
+static CK_RV sks2ck_all_token_flags(CK_TOKEN_INFO_PTR ck_info,
+				struct sks_token_info *sks_info)
+{
+	CK_FLAGS ck_flag;
+	uint32_t sks_mask;
+
+	ck_info->flags = 0;
+	for (sks_mask = 1; sks_mask; sks_mask <<= 1) {
+
+		/* Skip sks token flags without a CK equilavent */
+		if (sks2ck_token_flag(&ck_flag, sks_mask))
+			continue;
+
+		if (sks_info->flags & sks_mask)
+			ck_info->flags |= ck_flag;
+	}
+
+	return CKR_OK;
+}
+
+CK_RV sks2ck_token_info(CK_TOKEN_INFO_PTR ck_info,
+			struct sks_token_info *sks_info)
+{
+	CK_RV rv;
+
+	MEMCPY_FIELD(ck_info, sks_info, label);
+	MEMCPY_FIELD(ck_info, sks_info, manufacturerID);
+	MEMCPY_FIELD(ck_info, sks_info, model);
+	MEMCPY_FIELD(ck_info, sks_info, serialNumber);
+
+	rv = sks2ck_all_token_flags(ck_info, sks_info);
+	if (rv)
+		return rv;
+
+	ck_info->ulMaxSessionCount = sks_info->ulMaxSessionCount;
+	ck_info->ulSessionCount = sks_info->ulSessionCount;
+	ck_info->ulMaxRwSessionCount = sks_info->ulMaxRwSessionCount;
+	ck_info->ulRwSessionCount = sks_info->ulRwSessionCount;
+	ck_info->ulMaxPinLen = sks_info->ulMaxPinLen;
+	ck_info->ulMinPinLen = sks_info->ulMinPinLen;
+	ck_info->ulTotalPublicMemory = sks_info->ulTotalPublicMemory;
+	ck_info->ulFreePublicMemory = sks_info->ulFreePublicMemory;
+	ck_info->ulTotalPrivateMemory = sks_info->ulTotalPrivateMemory;
+	ck_info->ulFreePrivateMemory = sks_info->ulFreePrivateMemory;
+	MEMCPY_VERSION(ck_info, sks_info, hardwareVersion);
+	MEMCPY_VERSION(ck_info, sks_info, firmwareVersion);
+	MEMCPY_FIELD(ck_info, sks_info, utcTime);
+
+	return CKR_OK;
+}
+
+CK_RV sks2ck_session_info(CK_SESSION_INFO_PTR ck_info,
+			   struct sks_session_info *sks_info)
+{
+	ck_info->slotID = sks_info->slot_id;
+	ck_info->state = sks_info->state;
+	ck_info->flags = sks_info->flags;
+	ck_info->ulDeviceError = sks_info->error_code;
+
+	return CKR_OK;
+}
+
+/*
+ * Helpers for CK/SKS conversions: tables of identifiers
+ *
+ * Define conversion tables between Cryptoki IDs and SKS 32bit IDs.
+ * By convention, Cryptoki variable types CK_<XYZ> (i.e CK_ATTRIBUTE_TYPE)
+ * are registered through DECLARE_CK2SKS_FUNCTIONS(<xyz>); in ck_helpers.h
+ * and locally through DEFINE_CK2SKS_FUNCTIONS(<xyz>) in this source file.
+ *
+ * In the above description, <xyz> is the lower case equivalent of <XYZ>
+ * in Cryptoki variable type definition label. I.e, for type CK_ATTRIBUTE_TYPE:
+ *
+ * In header file:
+ *	DECLARE_CK2SKS_FUNCTIONS(attribute_type);
+ * In source file:
+ *	static const struct ck2sks attribute_type[] = {
+ *		CK2SKS_ID_BRACE(CKA_CLASS, SKS_CKA_CLASS),
+ *		CK2SKS_ID_BRACE(CKA_TOKEN, SKS_CKA_TOKEN),
+ *		...
+ *	};
+ *	DEFINE_CK2SKS_FUNCTIONS(attribute_type, CK_ATTRIBUTE_TYPE)
+ *
+ * The above code snipet declares and defines functions ck2sks_attribute_type()
+ * and sks2ck_attribute_type() using ID conversion array attribute type
+ * defines in the source file.
+ *
+ * Some Cryptoki variables types have mutliple ID enumerations that would
+ * conflict if merged into a single ID valid list. For exmaple the flag type
+ * CK_FLAGS is used by Cryptoki to enumerate mechanism flags, token flags and
+ * more. This implementation defines specific tables per ID scope.
+ * I.e:
+ *	mechanism_flags for CKF_<FOO> related to mechanism flags.
+ *	token_flags for  CKF_<FOO> related to token flags.
+ */
+struct ck2sks {
+	CK_ULONG ck;
+	uint32_t sks;
+	// TODO: string for both IDs
+};
+
+/*
+ * Macros to define the SKS identifier relate to a Cryptoki identifier.
+ * Use CK2SKS_ID() when SKS identifier label is SKS_<CK-label>.
+ * Use CK2SKS_BRACE() when specific SKS identifier regarding Cryptoki CK label.
+ */
+#define CK2SKS_ID(ck_id)		{ .ck = ck_id, .sks = SKS_ ## ck_id }
+#define CK2SKS_ID_BRACE(ck_id, sks_id)	{ .ck = ck_id, .sks = sks_id }
+
+#define SKS2CK(out, in, conv)		sks2ck(out, in, conv, ARRAY_SIZE(conv))
+#define CK2SKS(out, in, conv)		ck2sks(out, in, conv, ARRAY_SIZE(conv))
+
+#define DEFINE_CK2SKS_FUNCTIONS(_conv_table, _ck_typeof)	\
+	uint32_t ck2sks_ ## _conv_table(_ck_typeof ck)		\
+	{							\
+		uint32_t id;					\
+								\
+		if (CK2SKS(&id, ck, _conv_table))		\
+			return SKS_UNDEFINED_ID;		\
+								\
+		return id;					\
+	}							\
+	CK_RV sks2ck_ ## _conv_table(_ck_typeof *ck, uint32_t sks)	\
+	{							\
+		if (SKS2CK(ck, sks, _conv_table))		\
+			return CKR_GENERAL_ERROR;		\
+								\
+		return CKR_OK;					\
+	}
+
+static int sks2ck(CK_ULONG *out, uint32_t id,
+		  const struct ck2sks *conv, size_t count)
+{
+	size_t n;
+
+	for (n = 0; n < count; n++) {
+		if (id == conv[n].sks) {
+			*out = conv[n].ck;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static int ck2sks(uint32_t *out, CK_ULONG id,
+		  const struct ck2sks *conv, size_t count)
+{
+	size_t n;
+
+	for (n = 0; n < count; n++) {
+		if (id == conv[n].ck) {
+			*out = conv[n].sks;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+/*
+ * Identifiers conversion tables and related functions definitions.
+ * Generic way goes:
+ *
+ * static const struct ck2sks <foo>[] = {
+ *		CK2SKS_ID_BRACE(CK[<X>]_<Y>),
+ *		CK2SKS_ID_BRACE(CK[<X>]_<Y>, SKS_<Z>),
+ * };
+ *
+ * DEFINE_CK2SKS_FUNCTIONS(<foo>, CK_<related-type-label>)
+ */
+static const struct ck2sks slot_flag[] = {
+	CK2SKS_ID_BRACE(CKF_TOKEN_PRESENT, SKS_CKFS_TOKEN_PRESENT),
+	CK2SKS_ID_BRACE(CKF_REMOVABLE_DEVICE, SKS_CKFS_REMOVABLE_DEVICE),
+	CK2SKS_ID_BRACE(CKF_HW_SLOT, SKS_CKFS_HW_SLOT),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(slot_flag, CK_FLAGS)
+
+static const struct ck2sks token_flag[] = {
+	CK2SKS_ID_BRACE(CKF_RNG,
+			SKS_CKFT_RNG),
+	CK2SKS_ID_BRACE(CKF_WRITE_PROTECTED,
+			SKS_CKFT_WRITE_PROTECTED),
+	CK2SKS_ID_BRACE(CKF_LOGIN_REQUIRED,
+			SKS_CKFT_LOGIN_REQUIRED),
+	CK2SKS_ID_BRACE(CKF_USER_PIN_INITIALIZED,
+			SKS_CKFT_USER_PIN_INITIALIZED),
+	CK2SKS_ID_BRACE(CKF_RESTORE_KEY_NOT_NEEDED,
+			SKS_CKFT_RESTORE_KEY_NOT_NEEDED),
+	CK2SKS_ID_BRACE(CKF_CLOCK_ON_TOKEN,
+			SKS_CKFT_CLOCK_ON_TOKEN),
+	CK2SKS_ID_BRACE(CKF_PROTECTED_AUTHENTICATION_PATH,
+			SKS_CKFT_PROTECTED_AUTHENTICATION_PATH),
+	CK2SKS_ID_BRACE(CKF_DUAL_CRYPTO_OPERATIONS,
+			SKS_CKFT_DUAL_CRYPTO_OPERATIONS),
+	CK2SKS_ID_BRACE(CKF_TOKEN_INITIALIZED,
+			SKS_CKFT_TOKEN_INITIALIZED),
+	CK2SKS_ID_BRACE(CKF_USER_PIN_COUNT_LOW,
+			SKS_CKFT_USER_PIN_COUNT_LOW),
+	CK2SKS_ID_BRACE(CKF_USER_PIN_FINAL_TRY,
+			SKS_CKFT_USER_PIN_FINAL_TRY),
+	CK2SKS_ID_BRACE(CKF_USER_PIN_LOCKED,
+			SKS_CKFT_USER_PIN_LOCKED),
+	CK2SKS_ID_BRACE(CKF_USER_PIN_TO_BE_CHANGED,
+			SKS_CKFT_USER_PIN_TO_BE_CHANGED),
+	CK2SKS_ID_BRACE(CKF_SO_PIN_COUNT_LOW,
+			SKS_CKFT_SO_PIN_COUNT_LOW),
+	CK2SKS_ID_BRACE(CKF_SO_PIN_FINAL_TRY,
+			SKS_CKFT_SO_PIN_FINAL_TRY),
+	CK2SKS_ID_BRACE(CKF_SO_PIN_LOCKED,
+			SKS_CKFT_SO_PIN_LOCKED),
+	CK2SKS_ID_BRACE(CKF_SO_PIN_TO_BE_CHANGED,
+			SKS_CKFT_SO_PIN_TO_BE_CHANGED),
+	CK2SKS_ID_BRACE(CKF_ERROR_STATE,
+			SKS_CKFT_ERROR_STATE),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(token_flag, CK_FLAGS)
+
+static const struct ck2sks attribute_type[] = {
+	CK2SKS_ID(CKA_CLASS),
+	CK2SKS_ID(CKA_KEY_TYPE),
+	CK2SKS_ID(CKA_VALUE),
+	CK2SKS_ID(CKA_VALUE_LEN),
+	CK2SKS_ID(CKA_LABEL),
+	CK2SKS_ID(CKA_WRAP_TEMPLATE),
+	CK2SKS_ID(CKA_UNWRAP_TEMPLATE),
+	CK2SKS_ID(CKA_DERIVE_TEMPLATE),
+	CK2SKS_ID(CKA_START_DATE),
+	CK2SKS_ID(CKA_END_DATE),
+	CK2SKS_ID(CKA_OBJECT_ID),
+	CK2SKS_ID(CKA_APPLICATION),
+	CK2SKS_ID(CKA_MECHANISM_TYPE),
+	CK2SKS_ID(CKA_ID),
+	CK2SKS_ID(CKA_ALLOWED_MECHANISMS),
+	CK2SKS_ID(CKA_EC_PARAMS),
+	CK2SKS_ID(CKA_EC_POINT),
+	CK2SKS_ID(CKA_MODULUS),
+	CK2SKS_ID(CKA_MODULUS_BITS),
+	CK2SKS_ID(CKA_PUBLIC_EXPONENT),
+	CK2SKS_ID(CKA_PRIVATE_EXPONENT),
+	CK2SKS_ID(CKA_PRIME_1),
+	CK2SKS_ID(CKA_PRIME_2),
+	CK2SKS_ID(CKA_EXPONENT_1),
+	CK2SKS_ID(CKA_EXPONENT_2),
+	CK2SKS_ID(CKA_COEFFICIENT),
+	CK2SKS_ID(CKA_SUBJECT),
+	CK2SKS_ID(CKA_PUBLIC_KEY_INFO),
+	CK2SKS_ID(CKA_CERTIFICATE_TYPE),
+	CK2SKS_ID(CKA_CERTIFICATE_CATEGORY),
+	CK2SKS_ID(CKA_ISSUER),
+	CK2SKS_ID(CKA_SERIAL_NUMBER),
+	CK2SKS_ID(CKA_URL),
+	CK2SKS_ID(CKA_HASH_OF_SUBJECT_PUBLIC_KEY),
+	CK2SKS_ID(CKA_HASH_OF_ISSUER_PUBLIC_KEY),
+	CK2SKS_ID(CKA_NAME_HASH_ALGORITHM),
+	CK2SKS_ID(CKA_KEY_GEN_MECHANISM),
+	/* Below are boolean attributes */
+	CK2SKS_ID(CKA_TOKEN),
+	CK2SKS_ID(CKA_PRIVATE),
+	CK2SKS_ID(CKA_TRUSTED),
+	CK2SKS_ID(CKA_SENSITIVE),
+	CK2SKS_ID(CKA_ENCRYPT),
+	CK2SKS_ID(CKA_DECRYPT),
+	CK2SKS_ID(CKA_WRAP),
+	CK2SKS_ID(CKA_UNWRAP),
+	CK2SKS_ID(CKA_SIGN),
+	CK2SKS_ID(CKA_SIGN_RECOVER),
+	CK2SKS_ID(CKA_VERIFY),
+	CK2SKS_ID(CKA_VERIFY_RECOVER),
+	CK2SKS_ID(CKA_DERIVE),
+	CK2SKS_ID(CKA_EXTRACTABLE),
+	CK2SKS_ID(CKA_LOCAL),
+	CK2SKS_ID(CKA_NEVER_EXTRACTABLE),
+	CK2SKS_ID(CKA_ALWAYS_SENSITIVE),
+	CK2SKS_ID(CKA_MODIFIABLE),
+	CK2SKS_ID(CKA_COPYABLE),
+	CK2SKS_ID(CKA_DESTROYABLE),
+	CK2SKS_ID(CKA_ALWAYS_AUTHENTICATE),
+	CK2SKS_ID(CKA_WRAP_WITH_TRUSTED),
+	/* Specifc SKS attribute IDs */
+	CK2SKS_ID_BRACE(CK_VENDOR_INVALID_ID, SKS_UNDEFINED_ID),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(attribute_type, CK_ATTRIBUTE_TYPE)
+
+static const struct ck2sks mechanism_type[] = {
+	CK2SKS_ID(CKM_MD5),
+	CK2SKS_ID(CKM_SHA_1),
+	CK2SKS_ID(CKM_SHA224),
+	CK2SKS_ID(CKM_SHA256),
+	CK2SKS_ID(CKM_SHA384),
+	CK2SKS_ID(CKM_SHA512),
+
+	CK2SKS_ID(CKM_AES_ECB),
+	CK2SKS_ID(CKM_AES_CBC),
+	CK2SKS_ID(CKM_AES_CBC_PAD),
+	CK2SKS_ID(CKM_AES_CTR),
+	CK2SKS_ID(CKM_AES_GCM),
+	CK2SKS_ID(CKM_AES_CCM),
+	CK2SKS_ID(CKM_AES_CTS),
+	CK2SKS_ID(CKM_AES_GMAC),
+	CK2SKS_ID(CKM_AES_CMAC),
+	CK2SKS_ID(CKM_AES_CMAC_GENERAL),
+	CK2SKS_ID(CKM_AES_ECB_ENCRYPT_DATA),
+	CK2SKS_ID(CKM_AES_CBC_ENCRYPT_DATA),
+	CK2SKS_ID(CKM_AES_KEY_GEN),
+	CK2SKS_ID(CKM_AES_XCBC_MAC),
+
+	CK2SKS_ID(CKM_GENERIC_SECRET_KEY_GEN),
+
+	CK2SKS_ID(CKM_MD5_HMAC),
+	CK2SKS_ID(CKM_SHA_1_HMAC),
+	CK2SKS_ID(CKM_SHA224_HMAC),
+	CK2SKS_ID(CKM_SHA256_HMAC),
+	CK2SKS_ID(CKM_SHA384_HMAC),
+	CK2SKS_ID(CKM_SHA512_HMAC),
+
+	CK2SKS_ID(CKM_EC_KEY_PAIR_GEN),
+	CK2SKS_ID(CKM_ECDSA),
+	CK2SKS_ID(CKM_ECDSA_SHA1),
+	CK2SKS_ID(CKM_ECDSA_SHA224),
+	CK2SKS_ID(CKM_ECDSA_SHA256),
+	CK2SKS_ID(CKM_ECDSA_SHA384),
+	CK2SKS_ID(CKM_ECDSA_SHA512),
+	CK2SKS_ID(CKM_ECDH1_DERIVE),
+	CK2SKS_ID(CKM_ECDH1_COFACTOR_DERIVE),
+	CK2SKS_ID(CKM_ECMQV_DERIVE),
+	CK2SKS_ID(CKM_ECDH_AES_KEY_WRAP),
+
+	CK2SKS_ID(CKM_RSA_PKCS_KEY_PAIR_GEN),
+	CK2SKS_ID(CKM_RSA_PKCS),
+	CK2SKS_ID(CKM_RSA_9796),
+	CK2SKS_ID(CKM_RSA_X_509),
+	CK2SKS_ID(CKM_SHA1_RSA_PKCS),
+	CK2SKS_ID(CKM_RSA_PKCS_OAEP),
+	CK2SKS_ID(CKM_RSA_PKCS_PSS),
+	CK2SKS_ID(CKM_SHA1_RSA_PKCS_PSS),
+	CK2SKS_ID(CKM_SHA256_RSA_PKCS),
+	CK2SKS_ID(CKM_SHA384_RSA_PKCS),
+	CK2SKS_ID(CKM_SHA512_RSA_PKCS),
+	CK2SKS_ID(CKM_SHA256_RSA_PKCS_PSS),
+	CK2SKS_ID(CKM_SHA384_RSA_PKCS_PSS),
+	CK2SKS_ID(CKM_SHA512_RSA_PKCS_PSS),
+	CK2SKS_ID(CKM_SHA224_RSA_PKCS),
+	CK2SKS_ID(CKM_SHA224_RSA_PKCS_PSS),
+	CK2SKS_ID(CKM_RSA_AES_KEY_WRAP),
+
+	CK2SKS_ID(CKM_DES_KEY_GEN),
+	CK2SKS_ID(CKM_DES_ECB),
+	CK2SKS_ID(CKM_DES_CBC),
+	CK2SKS_ID(CKM_DES_MAC),
+	CK2SKS_ID(CKM_DES_MAC_GENERAL),
+	CK2SKS_ID(CKM_DES_CBC_PAD),
+
+	CK2SKS_ID(CKM_MTK_HSM_AES_ECB),
+	CK2SKS_ID(CKM_MTK_HSM_AES_CBC),
+	CK2SKS_ID(CKM_MTK_HSM_AES_CTR),
+	CK2SKS_ID(CKM_MTK_HSM_AES_GCM),
+	CK2SKS_ID(CKM_MTK_HSM_AES_CMAC),
+	CK2SKS_ID(CKM_MTK_HSM_SHA256_HMAC),
+	CK2SKS_ID(CKM_MTK_HSM_SHA384_HMAC),
+	CK2SKS_ID(CKM_MTK_HSM_ECDSA),
+	CK2SKS_ID(CKM_MTK_HSM_ECDSA_SHA1),
+	CK2SKS_ID(CKM_MTK_HSM_ECDSA_SHA224),
+	CK2SKS_ID(CKM_MTK_HSM_ECDSA_SHA256),
+	CK2SKS_ID(CKM_MTK_HSM_ECDSA_SHA384),
+	CK2SKS_ID(CKM_MTK_HSM_ECDSA_SHA512),
+	CK2SKS_ID(CKM_MTK_HSM_SHA1),
+	CK2SKS_ID(CKM_MTK_HSM_SHA224),
+	CK2SKS_ID(CKM_MTK_HSM_SHA256),
+	CK2SKS_ID(CKM_MTK_HSM_SHA384),
+	CK2SKS_ID(CKM_MTK_HSM_SHA512),
+	CK2SKS_ID(CKM_MTK_HSM_AES_KEY_GEN),
+	CK2SKS_ID(CKM_MTK_HSM_EC_KEY_PAIR_GEN),
+	CK2SKS_ID(CKM_MTK_HSM_EC_KEY_PAIR_IMPORT),
+	CK2SKS_ID(CKM_MTK_HSM_DUMP_LOG),
+
+	CK2SKS_ID_BRACE(CK_VENDOR_INVALID_ID, SKS_UNDEFINED_ID),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(mechanism_type, CK_MECHANISM_TYPE)
+
+static const struct ck2sks mechanism_flag[] = {
+	CK2SKS_ID_BRACE(CKF_HW, SKS_CKFM_HW),
+	CK2SKS_ID_BRACE(CKF_ENCRYPT, SKS_CKFM_ENCRYPT),
+	CK2SKS_ID_BRACE(CKF_DECRYPT, SKS_CKFM_DECRYPT),
+	CK2SKS_ID_BRACE(CKF_DIGEST, SKS_CKFM_DIGEST),
+	CK2SKS_ID_BRACE(CKF_SIGN, SKS_CKFM_SIGN),
+	CK2SKS_ID_BRACE(CKF_SIGN_RECOVER, SKS_CKFM_SIGN_RECOVER),
+	CK2SKS_ID_BRACE(CKF_VERIFY, SKS_CKFM_VERIFY),
+	CK2SKS_ID_BRACE(CKF_VERIFY_RECOVER, SKS_CKFM_VERIFY_RECOVER),
+	CK2SKS_ID_BRACE(CKF_GENERATE, SKS_CKFM_GENERATE),
+	CK2SKS_ID_BRACE(CKF_GENERATE_KEY_PAIR, SKS_CKFM_GENERATE_PAIR),
+	CK2SKS_ID_BRACE(CKF_WRAP, SKS_CKFM_WRAP),
+	CK2SKS_ID_BRACE(CKF_UNWRAP, SKS_CKFM_UNWRAP),
+	CK2SKS_ID_BRACE(CKF_DERIVE, SKS_CKFM_DERIVE),
+	CK2SKS_ID_BRACE(CKF_EC_F_P, SKS_CKFM_EC_F_P),
+	CK2SKS_ID_BRACE(CKF_EC_F_2M, SKS_CKFM_EC_F_2M),
+	CK2SKS_ID_BRACE(CKF_EC_ECPARAMETERS, SKS_CKFM_EC_ECPARAMETERS),
+	CK2SKS_ID_BRACE(CKF_EC_NAMEDCURVE, SKS_CKFM_EC_NAMEDCURVE),
+	CK2SKS_ID_BRACE(CKF_EC_UNCOMPRESS, SKS_CKFM_EC_UNCOMPRESS),
+	CK2SKS_ID_BRACE(CKF_EC_COMPRESS, SKS_CKFM_EC_COMPRESS),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(mechanism_flag, CK_FLAGS)
+
+static const struct ck2sks object_class[] = {
+	CK2SKS_ID(CKO_SECRET_KEY),
+	CK2SKS_ID(CKO_PUBLIC_KEY),
+	CK2SKS_ID(CKO_PRIVATE_KEY),
+	CK2SKS_ID(CKO_OTP_KEY),
+	CK2SKS_ID(CKO_CERTIFICATE),
+	CK2SKS_ID(CKO_DATA),
+	CK2SKS_ID(CKO_DOMAIN_PARAMETERS),
+	CK2SKS_ID(CKO_HW_FEATURE),
+	CK2SKS_ID(CKO_MECHANISM),
+	CK2SKS_ID_BRACE(CK_VENDOR_INVALID_ID, SKS_UNDEFINED_ID),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(object_class, CK_OBJECT_CLASS)
+
+static const struct ck2sks key_type[] = {
+	CK2SKS_ID(CKK_AES),
+	CK2SKS_ID(CKK_GENERIC_SECRET),
+	CK2SKS_ID(CKK_MD5_HMAC),
+	CK2SKS_ID(CKK_SHA_1_HMAC),
+	CK2SKS_ID(CKK_SHA224_HMAC),
+	CK2SKS_ID(CKK_SHA256_HMAC),
+	CK2SKS_ID(CKK_SHA384_HMAC),
+	CK2SKS_ID(CKK_SHA512_HMAC),
+	CK2SKS_ID(CKK_RSA),
+	CK2SKS_ID(CKK_EC),
+	CK2SKS_ID(CKK_DSA),
+	CK2SKS_ID(CKK_DH),
+	CK2SKS_ID(CKK_DES),
+	CK2SKS_ID(CKK_DES2),
+	CK2SKS_ID(CKK_DES3),
+	CK2SKS_ID_BRACE(CK_VENDOR_INVALID_ID, SKS_UNDEFINED_ID),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(key_type, CK_KEY_TYPE)
+
+static const struct ck2sks certificate_type[] = {
+	CK2SKS_ID(CKC_X_509),
+	CK2SKS_ID(CKC_X_509_ATTR_CER),
+	CK2SKS_ID(CKC_WTLS),
+	CK2SKS_ID_BRACE(CK_VENDOR_INVALID_ID, SKS_UNDEFINED_ID),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(certificate_type, CK_CERTIFICATE_TYPE)
+
+static const struct ck2sks ec_kdf_type[] = {
+	CK2SKS_ID(CKD_NULL),
+	CK2SKS_ID(CKD_SHA1_KDF),
+	CK2SKS_ID(CKD_SHA1_KDF_ASN1),
+	CK2SKS_ID(CKD_SHA1_KDF_CONCATENATE),
+	CK2SKS_ID(CKD_SHA224_KDF),
+	CK2SKS_ID(CKD_SHA256_KDF),
+	CK2SKS_ID(CKD_SHA384_KDF),
+	CK2SKS_ID(CKD_SHA512_KDF),
+	CK2SKS_ID(CKD_CPDIVERSIFY_KDF),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(ec_kdf_type, CK_EC_KDF_TYPE)
+
+static const struct ck2sks rsa_pkcs_mgf_type[] = {
+	CK2SKS_ID(CKG_MGF1_SHA1),
+	CK2SKS_ID(CKG_MGF1_SHA224),
+	CK2SKS_ID(CKG_MGF1_SHA256),
+	CK2SKS_ID(CKG_MGF1_SHA384),
+	CK2SKS_ID(CKG_MGF1_SHA512),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(rsa_pkcs_mgf_type, CK_RSA_PKCS_MGF_TYPE)
+
+static const struct ck2sks rsa_pkcs_oaep_source_type[] = {
+	CK2SKS_ID(CKZ_DATA_SPECIFIED),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(rsa_pkcs_oaep_source_type, CK_RSA_PKCS_OAEP_SOURCE_TYPE)
+
+static const struct ck2sks user_type[] = {
+	CK2SKS_ID(CKU_SO),
+	CK2SKS_ID(CKU_USER),
+	CK2SKS_ID(CKU_CONTEXT_SPECIFIC),
+};
+
+DEFINE_CK2SKS_FUNCTIONS(user_type, CK_USER_TYPE)
+
+static const struct ck2sks error_code[] = {
+	CK2SKS_ID(CKR_OK),
+	CK2SKS_ID(CKR_GENERAL_ERROR),
+	CK2SKS_ID(CKR_DEVICE_MEMORY),
+	CK2SKS_ID(CKR_ARGUMENTS_BAD),
+	CK2SKS_ID(CKR_BUFFER_TOO_SMALL),
+	CK2SKS_ID(CKR_FUNCTION_FAILED),
+	CK2SKS_ID(CKR_ATTRIBUTE_TYPE_INVALID),
+	CK2SKS_ID(CKR_ATTRIBUTE_VALUE_INVALID),
+	CK2SKS_ID(CKR_OBJECT_HANDLE_INVALID),
+	CK2SKS_ID(CKR_KEY_HANDLE_INVALID),
+	CK2SKS_ID(CKR_MECHANISM_INVALID),
+	CK2SKS_ID(CKR_SLOT_ID_INVALID),
+	CK2SKS_ID(CKR_SESSION_HANDLE_INVALID),
+	CK2SKS_ID(CKR_PIN_INCORRECT),
+	CK2SKS_ID(CKR_PIN_LOCKED),
+	CK2SKS_ID(CKR_PIN_EXPIRED),
+	CK2SKS_ID(CKR_PIN_INVALID),
+	CK2SKS_ID(CKR_OPERATION_ACTIVE),
+	CK2SKS_ID(CKR_KEY_FUNCTION_NOT_PERMITTED),
+	CK2SKS_ID(CKR_KEY_TYPE_INCONSISTENT),
+	CK2SKS_ID(CKR_OPERATION_NOT_INITIALIZED),
+	CK2SKS_ID(CKR_SESSION_READ_ONLY),
+	CK2SKS_ID(CKR_MECHANISM_PARAM_INVALID),
+	CK2SKS_ID(CKR_TOKEN_WRITE_PROTECTED),
+	CK2SKS_ID(CKR_TOKEN_NOT_PRESENT),
+	CK2SKS_ID(CKR_TOKEN_NOT_RECOGNIZED),
+	CK2SKS_ID(CKR_ACTION_PROHIBITED),
+	CK2SKS_ID(CKR_ATTRIBUTE_READ_ONLY),
+	CK2SKS_ID(CKR_PIN_TOO_WEAK),
+	CK2SKS_ID(CKR_CURVE_NOT_SUPPORTED),
+	CK2SKS_ID(CKR_DOMAIN_PARAMS_INVALID),
+	CK2SKS_ID(CKR_USER_ALREADY_LOGGED_IN),
+	CK2SKS_ID(CKR_USER_ANOTHER_ALREADY_LOGGED_IN),
+	CK2SKS_ID(CKR_USER_NOT_LOGGED_IN),
+	CK2SKS_ID(CKR_USER_PIN_NOT_INITIALIZED),
+	CK2SKS_ID(CKR_USER_TOO_MANY_TYPES),
+	CK2SKS_ID(CKR_USER_TYPE_INVALID),
+	CK2SKS_ID(CKR_SESSION_READ_ONLY_EXISTS),
+	CK2SKS_ID(CKR_SESSION_READ_WRITE_SO_EXISTS),
+	CK2SKS_ID(CKR_SESSION_EXISTS),
+	CK2SKS_ID(CKR_TEMPLATE_INCOMPLETE),
+	CK2SKS_ID(CKR_TEMPLATE_INCONSISTENT),
+	CK2SKS_ID(CKR_SIGNATURE_INVALID),
+	CK2SKS_ID(CKR_ATTRIBUTE_SENSITIVE),
+	CK2SKS_ID(CKR_SIGNATURE_LEN_RANGE),
+	CK2SKS_ID(CKR_DATA_LEN_RANGE),
+	CK2SKS_ID(CKR_ENCRYPTED_DATA_LEN_RANGE),
+	CK2SKS_ID_BRACE(CK_VENDOR_INVALID_ID, SKS_UNDEFINED_ID),
+};
+
+CK_RV sks2ck_rv(uint32_t sks)
+{
+	CK_ULONG rv;
+
+	if (SKS2CK(&rv, sks, error_code))
+		return CKR_GENERAL_ERROR;
+
+	return (CK_RV)rv;
+}
+
+CK_RV teec2ck_rv(TEEC_Result res)
+{
+	switch (res) {
+	case TEEC_SUCCESS:
+		return CKR_OK;
+	case TEEC_ERROR_OUT_OF_MEMORY:
+		return CKR_DEVICE_MEMORY;
+	case TEEC_ERROR_BAD_PARAMETERS:
+		return CKR_ARGUMENTS_BAD;
+	case TEEC_ERROR_SHORT_BUFFER:
+		return CKR_BUFFER_TOO_SMALL;
+	default:
+		return CKR_FUNCTION_FAILED;
+	}
+}
+/* Convert a array of mechanism type from sks into CK_MECHANIMS_TYPE */
+CK_RV sks2ck_mechanism_type_list(CK_MECHANISM_TYPE *dst,
+				 void *src, size_t count)
+{
+	CK_MECHANISM_TYPE *ck = dst;
+	char *sks = src;
+	size_t n;
+	uint32_t proc;
+
+	for (n = 0; n < count; n++, sks += sizeof(uint32_t), ck++) {
+		memcpy(&proc, sks, sizeof(proc));
+		if (sks2ck_mechanism_type(ck, proc))
+			return CKR_MECHANISM_INVALID;
+	}
+
+	return CKR_OK;
+}
+
+/* Convert structure CK_MECHANIMS_INFO from sks to ck (3 ulong fields) */
+CK_RV sks2ck_mechanism_info(CK_MECHANISM_INFO *info, void *src)
+{
+	struct sks_mechanism_info sks;
+	CK_FLAGS ck_flag;
+	uint32_t mask;
+	CK_RV rv;
+
+	memcpy(&sks, src, sizeof(sks));
+
+	info->ulMinKeySize = sks.min_key_size;
+	info->ulMaxKeySize = sks.max_key_size;
+
+	info->flags = 0;
+	for (mask = 1; mask; mask <<= 1) {
+		if (!(sks.flags & mask))
+			continue;
+
+		rv = sks2ck_mechanism_flag(&ck_flag, mask);
+		if (rv)
+			return rv;
+
+		info->flags |= ck_flag;
+	}
+
+	return CKR_OK;
+}
+
+/*
+ * Helper functions to analyse CK fields
+ */
+size_t ck_attr_is_class(uint32_t id)
+{
+	if (id == CKA_CLASS)
+		return sizeof(CK_ULONG);
+	else
+		return 0;
+}
+
+size_t ck_attr_is_type(uint32_t id)
+{
+	switch (id) {
+	case CKA_CERTIFICATE_TYPE:
+	case CKA_KEY_TYPE:
+	case CKA_HW_FEATURE_TYPE:
+	case CKA_MECHANISM_TYPE:
+	case CKA_KEY_GEN_MECHANISM:
+		return sizeof(CK_ULONG);
+	default:
+		return 0;
+	}
+}
+int sks_object_has_boolprop(uint32_t class)
+{
+	switch (class) {
+	case SKS_CKO_DATA:
+	case SKS_CKO_CERTIFICATE:
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+	case SKS_CKO_SECRET_KEY:
+	case SKS_CKO_DOMAIN_PARAMETERS:
+		return 1;
+	default:
+		return 0;
+	}
+}
+int sks_class_has_type(uint32_t class)
+{
+	switch (class) {
+	case SKS_CKO_CERTIFICATE:
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+	case SKS_CKO_SECRET_KEY:
+	case SKS_CKO_MECHANISM:
+	case SKS_CKO_HW_FEATURE:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+uint32_t ck2sks_type_in_class(CK_ULONG ck, CK_ULONG class)
+{
+	switch (class) {
+	case CKO_DATA:
+		return 0;
+	case CKO_SECRET_KEY:
+	case CKO_PUBLIC_KEY:
+	case CKO_PRIVATE_KEY:
+	case CKO_OTP_KEY:
+		return ck2sks_key_type(ck);
+	case CKO_MECHANISM:
+		return ck2sks_mechanism_type(ck);
+	case CKO_CERTIFICATE:
+		return ck2sks_certificate_type(ck);
+	default:
+		return SKS_UNDEFINED_ID;
+	}
+}
+
+CK_RV sks2ck_type_in_class(CK_ULONG *ck, uint32_t sks, CK_ULONG class)
+{
+	switch (class) {
+	case SKS_CKO_DATA:
+		return CKR_NO_EVENT;
+	case SKS_CKO_SECRET_KEY:
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+	case SKS_CKO_OTP_KEY:
+		return sks2ck_key_type(ck, sks);
+	case SKS_CKO_MECHANISM:
+		return sks2ck_mechanism_type(ck, sks);
+	case SKS_CKO_CERTIFICATE:
+		return sks2ck_certificate_type(ck, sks);
+	default:
+		return CKR_GENERAL_ERROR;
+	}
+}
+
+CK_RV ck_add_object_class(CK_ATTRIBUTE_PTR attrs, CK_ULONG_PTR count,
+			CK_ATTRIBUTE_PTR *attrs_new_p,CK_OBJECT_CLASS cka_class)
+{
+	size_t n;
+	CK_ULONG count_new = *count;
+	CK_ATTRIBUTE_PTR attrs_new = NULL;
+	CK_OBJECT_CLASS_PTR object_class_p = NULL;
+	int object_class_present = 0;
+	CK_RV rv;
+
+	for (n = 0; n < *count; n++) {
+		if (attrs[n].type == CKA_CLASS) {
+			object_class_present = 1;
+			break;
+		}
+	}
+	if (!object_class_present)
+		count_new++;
+
+	attrs_new = malloc(count_new * sizeof(CK_ATTRIBUTE));
+	if (attrs_new == NULL)
+		return CKR_HOST_MEMORY;
+
+	memcpy(attrs_new, attrs, (*count) * sizeof(CK_ATTRIBUTE));
+
+	if (object_class_present) {
+		rv = CKR_OK;
+		goto bail;
+	}
+
+	object_class_p = malloc(sizeof(CK_OBJECT_CLASS));
+	if (object_class_p == NULL) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	*object_class_p = cka_class;
+	attrs_new[count_new - 1].type = CKA_CLASS;
+	attrs_new[count_new - 1].pValue = object_class_p;
+	attrs_new[count_new - 1].ulValueLen = sizeof(CK_OBJECT_CLASS);
+	rv = CKR_OK;
+
+bail:
+	if (rv == CKR_OK) {
+		if(*attrs_new_p == attrs)
+			free(attrs);
+		*attrs_new_p = attrs_new;
+		*count = count_new;
+	} else {
+		if (attrs_new)
+			free(attrs_new);
+		if (object_class_p)
+			free(object_class_p);
+	}
+
+	return rv;
+}
+
+CK_RV ck_guess_key_type(CK_MECHANISM_PTR mecha,
+			CK_ATTRIBUTE_PTR attrs, CK_ULONG_PTR count,
+			CK_ATTRIBUTE_PTR *attrs_new_p)
+{
+	size_t n;
+	CK_ULONG count_new = *count;
+	CK_ATTRIBUTE_PTR attrs_new = NULL;
+	CK_KEY_TYPE_PTR key_type_p = NULL;
+	int key_type_present = 0;
+	CK_RV rv;
+
+	for (n = 0; n < *count; n++) {
+		if (attrs[n].type == CKA_KEY_TYPE) {
+			key_type_present = 1;
+			break;
+		}
+	}
+	if (!key_type_present)
+		count_new++;
+
+	attrs_new = malloc(count_new * sizeof(CK_ATTRIBUTE));
+	if (attrs_new == NULL)
+		return CKR_HOST_MEMORY;
+
+	memcpy(attrs_new, attrs, (*count) * sizeof(CK_ATTRIBUTE));
+
+	if (key_type_present) {
+		rv = CKR_OK;
+		goto bail;
+	}
+
+	key_type_p = malloc(sizeof(CK_KEY_TYPE));
+	if (key_type_p == NULL) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	switch (mecha->mechanism) {
+	case CKM_RSA_PKCS_KEY_PAIR_GEN:
+		*key_type_p = CKK_RSA;
+		attrs_new[count_new - 1].type = CKA_KEY_TYPE;
+		attrs_new[count_new - 1].pValue = key_type_p;
+		attrs_new[count_new - 1].ulValueLen = sizeof(CK_KEY_TYPE);
+		rv = CKR_OK;
+		break;
+	case CKM_EC_KEY_PAIR_GEN:
+	case CKM_MTK_HSM_EC_KEY_PAIR_GEN:
+	case CKM_MTK_HSM_EC_KEY_PAIR_IMPORT:
+		*key_type_p = CKK_EC;
+		attrs_new[count_new - 1].type = CKA_KEY_TYPE;
+		attrs_new[count_new - 1].pValue = key_type_p;
+		attrs_new[count_new - 1].ulValueLen = sizeof(CK_KEY_TYPE);
+		rv = CKR_OK;
+		break;
+	default:
+		rv = CKR_TEMPLATE_INCOMPLETE;
+		break;
+	}
+
+bail:
+	if (rv == CKR_OK) {
+		*attrs_new_p = attrs_new;
+		*count = count_new;
+	} else {
+		if (attrs_new)
+			free(attrs_new);
+		if (key_type_p)
+			free(key_type_p);
+	}
+
+	return rv;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.h
new file mode 100644
index 0000000..1695c3c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/ck_helpers.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __HELPERS_CK_H
+#define __HELPERS_CK_H
+
+#include <pkcs11.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <sks_ta.h>
+#include <tee_client_api.h>
+
+/*
+ * SKS reserves vendor ID 0xffffffff to represent an invalid ID
+ * (attribute class, type, ...)
+ */
+#define CK_VENDOR_INVALID_ID		0xffffffffUL
+#define SKS_CK_VENDOR_INVALID_ID	0xffffffffUL
+
+/* Helper for sks2ck_xxx() and ck2sks_xxx() helper declaration */
+#define DECLARE_CK2SKS_FUNCTIONS(_label, _ck_typeof)		\
+	uint32_t ck2sks_ ## _label(_ck_typeof ck);	\
+	CK_RV sks2ck_ ## _label(_ck_typeof *ck, uint32_t sks)
+
+DECLARE_CK2SKS_FUNCTIONS(slot_flag, CK_FLAGS);
+DECLARE_CK2SKS_FUNCTIONS(token_flag, CK_FLAGS);
+DECLARE_CK2SKS_FUNCTIONS(user_type, CK_USER_TYPE);
+DECLARE_CK2SKS_FUNCTIONS(attribute_type, CK_ATTRIBUTE_TYPE);
+DECLARE_CK2SKS_FUNCTIONS(mechanism_type, CK_MECHANISM_TYPE);
+DECLARE_CK2SKS_FUNCTIONS(mechanism_flag, CK_FLAGS);
+DECLARE_CK2SKS_FUNCTIONS(object_class, CK_OBJECT_CLASS);
+DECLARE_CK2SKS_FUNCTIONS(key_type, CK_KEY_TYPE);
+DECLARE_CK2SKS_FUNCTIONS(ec_kdf_type, CK_EC_KDF_TYPE);
+DECLARE_CK2SKS_FUNCTIONS(rsa_pkcs_mgf_type, CK_RSA_PKCS_MGF_TYPE);
+DECLARE_CK2SKS_FUNCTIONS(rsa_pkcs_oaep_source_type,
+			 CK_RSA_PKCS_OAEP_SOURCE_TYPE);
+DECLARE_CK2SKS_FUNCTIONS(certificate_type, CK_CERTIFICATE_TYPE);
+
+/*
+ * Convert structure struct sks_token_info retreived from TA into a
+ * cryptoki API compliant CK_TOKEN_INFO structure.
+ *
+ * struct sks_token_info is defined in the SKS TA API.
+ */
+CK_RV sks2ck_token_info(CK_TOKEN_INFO_PTR ck_info,
+			struct sks_token_info *sks_info);
+CK_RV sks2ck_slot_info(CK_SLOT_INFO_PTR ck_info,
+			struct sks_slot_info *sks_info);
+CK_RV sks2ck_session_info(CK_SESSION_INFO_PTR ck_info,
+			struct sks_session_info *sks_info);
+
+/* Backward compat on deprecated functions */
+static inline CK_RV sks2ck_attribute_id(CK_ATTRIBUTE_TYPE *ck, uint32_t sks)
+{
+	return sks2ck_attribute_type(ck, sks);
+}
+
+static inline uint32_t ck2sks_attribute_id(CK_ATTRIBUTE_TYPE ck)
+{
+	return ck2sks_attribute_type(ck);
+}
+
+static inline CK_RV sks2ck_class(CK_OBJECT_CLASS *ck, uint32_t sks)
+{
+	return sks2ck_object_class(ck, sks);
+}
+
+static inline uint32_t ck2sks_class(CK_OBJECT_CLASS ck)
+{
+	return ck2sks_object_class(ck);
+}
+
+CK_RV sks2ck_mechanism_type_list(CK_MECHANISM_TYPE *dst, void *sks,
+				 size_t count);
+CK_RV sks2ck_mechanism_info(CK_MECHANISM_INFO *info, void *sks);
+
+uint32_t ck2sks_type_in_class(CK_ULONG ck, CK_ULONG class);
+CK_RV sks2ck_type_in_class(CK_ULONG *ck, uint32_t sks, CK_ULONG class);
+
+int sks_attr2boolprop_shift(CK_ULONG attr);
+
+CK_RV sks2ck_rv(uint32_t sks);
+CK_RV teec2ck_rv(TEEC_Result res);
+
+/*
+ * Helper functions to analyse CK fields
+ */
+size_t ck_attr_is_class(uint32_t attribute_id);
+size_t ck_attr_is_type(uint32_t attribute_id);
+int ck_attr2boolprop_shift(CK_ULONG attr);
+
+int sks_object_has_boolprop(uint32_t class);
+int sks_class_has_type(uint32_t class);
+
+/*
+ * Try to guess key type if mechanism is key generation
+ *
+ * @mech: Referecn to mechanism
+ * @attrs; Reference to input object attributes
+ * @count: number of attributes for the object, output value may be incremented
+ * @attrs_new_p: Referenece to output attributes, always defines the key type
+ *
+ * This may be needed because some tools (e.g.: pkcs11-tool) may not specify
+ * some attributes as key type when these can be assumed from the mechanism
+ * type.
+ *
+ * The function allocates memory for a copy of the attributes since it could
+ * be increased when adding the missing attribute. Caller is responsible from
+ * freeing the output attribute references.
+ */
+CK_RV ck_guess_key_type(CK_MECHANISM_PTR mecha,
+		       CK_ATTRIBUTE_PTR attrs, CK_ULONG_PTR count,
+		       CK_ATTRIBUTE_PTR *attrs_new_p);
+
+CK_RV ck_add_object_class(CK_ATTRIBUTE_PTR attrs, CK_ULONG_PTR count,
+			CK_ATTRIBUTE_PTR *attrs_new_p,CK_OBJECT_CLASS cka_class);
+
+#endif /*__HELPERS_CK_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/invoke_ta.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/invoke_ta.c
new file mode 100644
index 0000000..9bace12
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/invoke_ta.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <pkcs11.h>
+#include <sks_ta.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ck_helpers.h"
+#include "invoke_ta.h"
+#include "local_utils.h"
+
+/*
+ * All requests (invocation of the SKS) currently go through a
+ * single GPD TEE session toward the SKS TA.
+ */
+struct sks_primary_context {
+	TEEC_Context context;
+	TEEC_Session session;
+};
+
+static struct sks_primary_context primary_ctx;
+static struct sks_invoke primary_invoke;
+
+static int open_primary_context(void)
+{
+	TEEC_UUID uuid = TA_SKS_UUID;
+	uint32_t origin;
+	TEEC_Result res;
+
+	/* TODO: mutex */
+	if (primary_invoke.session)
+		return 0;
+
+	res = TEEC_InitializeContext(NULL, &primary_ctx.context);
+	if (res != TEEC_SUCCESS) {
+		LOG_ERROR("TEEC init context failed\n");
+		return -1;
+	}
+
+	/* TODO: application could provide a knwon login ID */
+	res = TEEC_OpenSession(&primary_ctx.context, &primary_ctx.session,
+				&uuid, TEEC_LOGIN_PUBLIC, NULL, NULL, &origin);
+	if (res != TEEC_SUCCESS) {
+		LOG_ERROR("TEEC open session failed %x from %d\n", res, origin);
+		TEEC_FinalizeContext(&primary_ctx.context);
+		return -1;
+	}
+
+	primary_invoke.context = &primary_ctx.context;
+	primary_invoke.session = &primary_ctx.session;
+
+	return 0;
+}
+
+static void close_primary_context(void)
+{
+	/*  TODO: mutex */
+	if (!primary_invoke.session)
+		return;
+
+	TEEC_CloseSession(&primary_ctx.session);
+	TEEC_FinalizeContext(&primary_ctx.context);
+	primary_invoke.context = NULL;
+	primary_invoke.session = NULL;
+}
+
+static struct sks_invoke *get_invoke_context(struct sks_invoke *sks_ctx)
+{
+	struct sks_invoke *ctx = sks_ctx;
+
+	if (open_primary_context())
+		return NULL;
+
+	if (!ctx)
+		return &primary_invoke;
+
+	if (!ctx->context)
+		ctx->context = primary_invoke.context;
+	if (!ctx->session)
+		ctx->session = primary_invoke.session;
+
+	return ctx;
+}
+
+static TEEC_Context *teec_ctx(struct sks_invoke *sks_ctx)
+{
+	return (TEEC_Context *)sks_ctx->context;
+}
+
+static TEEC_Session *teec_sess(struct sks_invoke *sks_ctx)
+{
+	return (TEEC_Session *)sks_ctx->session;
+}
+
+TEEC_SharedMemory *sks_alloc_shm(struct sks_invoke *sks_ctx,
+				 size_t size, int in, int out)
+{
+	struct sks_invoke *ctx = get_invoke_context(sks_ctx);
+	TEEC_SharedMemory *shm;
+
+	if (!ctx || (!in && !out))
+		return NULL;
+
+	shm = calloc(1, sizeof(TEEC_SharedMemory));
+	if (!shm)
+		return NULL;
+
+	shm->size = size;
+
+	if (in)
+		shm->flags |= TEEC_MEM_INPUT;
+	if (out)
+		shm->flags |= TEEC_MEM_OUTPUT;
+
+	if (TEEC_AllocateSharedMemory(teec_ctx(ctx), shm)) {
+		free(shm);
+		return NULL;
+	}
+
+	return shm;
+}
+
+TEEC_SharedMemory *sks_register_shm(struct sks_invoke *sks_ctx,
+				    void *buf, size_t size, int in, int out)
+{
+	struct sks_invoke *ctx = get_invoke_context(sks_ctx);
+	TEEC_SharedMemory *shm;
+
+	if (!ctx || (!in && !out))
+		return NULL;
+
+	shm = calloc(1, sizeof(TEEC_SharedMemory));
+	if (!shm)
+		return NULL;
+
+	shm->buffer = buf;
+	shm->size = size;
+
+	if (in)
+		shm->flags |= TEEC_MEM_INPUT;
+	if (out)
+		shm->flags |= TEEC_MEM_OUTPUT;
+
+	if (TEEC_RegisterSharedMemory(teec_ctx(ctx), shm)) {
+		free(shm);
+		return NULL;
+	}
+
+	return shm;
+}
+
+void sks_free_shm(TEEC_SharedMemory *shm)
+{
+	TEEC_ReleaseSharedMemory(shm);
+	free(shm);
+}
+
+#define DIR_IN			1
+#define DIR_OUT			0
+#define DIR_NONE		-1
+
+static CK_RV invoke_ta(struct sks_invoke *sks_ctx, unsigned long cmd,
+			void *ctrl, size_t ctrl_sz,
+			void *io1, size_t *io1_sz, int io1_dir,
+			void *io2, size_t *io2_sz, int io2_dir)
+{
+	struct sks_invoke *ctx = get_invoke_context(sks_ctx);
+	uint32_t command = (uint32_t)cmd;
+	TEEC_Operation op;
+	uint32_t origin;
+	TEEC_Result res;
+	TEEC_SharedMemory *ctrl_shm = ctrl;
+	TEEC_SharedMemory *io1_shm = io1;
+	TEEC_SharedMemory *io2_shm = io2;
+	uint32_t sks_rc;
+
+	memset(&op, 0, sizeof(op));
+
+	/*
+	 * Command control field: TEE invocation parameter #0
+	 */
+	if (ctrl && ctrl_sz) {
+		op.params[0].tmpref.buffer = ctrl;
+		op.params[0].tmpref.size = ctrl_sz;
+		op.paramTypes |= TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INOUT,
+						  0, 0, 0);
+	}
+	if (ctrl && !ctrl_sz) {
+		op.params[0].memref.parent = ctrl_shm;
+		op.paramTypes |= TEEC_PARAM_TYPES(TEEC_MEMREF_WHOLE, 0, 0, 0);
+	}
+
+	/*
+	 * IO data TEE invocation parameter #1
+	 */
+	if (io1_sz && (io1_dir == DIR_OUT || (io1_dir == DIR_IN && *io1_sz))) {
+		op.params[1].tmpref.buffer = io1;
+		op.params[1].tmpref.size = *io1_sz;
+		op.paramTypes |= TEEC_PARAM_TYPES(0, io1_dir == DIR_IN ?
+						  TEEC_MEMREF_TEMP_INPUT :
+						  TEEC_MEMREF_TEMP_OUTPUT,
+						  0, 0);
+	}
+	if (io1_dir != DIR_NONE && !io1_sz && io1) {
+		op.params[1].memref.parent = io1_shm;
+		op.paramTypes |= TEEC_PARAM_TYPES(0, TEEC_MEMREF_WHOLE, 0, 0);
+	}
+
+	/*
+	 * IO data TEE invocation parameter #2
+	 */
+	if (io2_sz && (io2_dir == DIR_OUT || (io2_dir == DIR_IN && *io2_sz))) {
+		op.params[2].tmpref.buffer = io2;
+		op.params[2].tmpref.size = *io2_sz;
+		op.paramTypes |= TEEC_PARAM_TYPES(0, 0, io2_dir == DIR_IN ?
+						  TEEC_MEMREF_TEMP_INPUT :
+						  TEEC_MEMREF_TEMP_OUTPUT,
+						  0);
+	}
+	if (io2_dir != DIR_NONE && !io2_sz && io2) {
+		op.params[2].memref.parent = io2_shm;
+		op.paramTypes |= TEEC_PARAM_TYPES(0, 0, TEEC_MEMREF_WHOLE, 0);
+	}
+
+
+	/*
+	 * Invoke the TEE and update output buffer size on exit.
+	 * Too short buffers are treated as positive errors.
+	 */
+	res = TEEC_InvokeCommand(teec_sess(ctx), command, &op, &origin);
+	if (res) {
+		if (res == TEEC_ERROR_SHORT_BUFFER) {
+			if (io1_dir == DIR_OUT && io1_sz)
+				*io1_sz = op.params[1].tmpref.size;
+			if (io2_dir == DIR_OUT && io2_sz)
+				*io2_sz = op.params[2].tmpref.size;
+		}
+
+		return teec2ck_rv(res);
+	}
+
+	/* Get SKS return value from ctrl buffer, if none we expect success */
+	if (ctrl &&
+	    ((ctrl_sz && op.params[0].tmpref.size == sizeof(uint32_t)) ||
+	    (!ctrl_sz && op.params[0].memref.size == sizeof(uint32_t)))) {
+		memcpy(&sks_rc, ctrl, sizeof(uint32_t));
+	} else {
+		sks_rc = SKS_CKR_OK;
+	}
+
+	if (sks_rc == SKS_CKR_OK || sks_rc == SKS_CKR_BUFFER_TOO_SMALL) {
+		if (io1_dir == DIR_OUT && io1_sz)
+			*io1_sz = op.params[1].tmpref.size;
+		if (io2_dir == DIR_OUT && io2_sz)
+			*io2_sz = op.params[2].tmpref.size;
+	}
+
+	return sks2ck_rv(sks_rc);
+}
+
+CK_RV ck_invoke_ta(struct sks_invoke *sks_ctx,
+		   unsigned long cmd,
+		   void *ctrl, size_t ctrl_sz)
+{
+	return invoke_ta(sks_ctx, cmd, ctrl, ctrl_sz,
+			 NULL, NULL, DIR_NONE,
+			 NULL, NULL, DIR_NONE);
+}
+
+CK_RV ck_invoke_ta_in(struct sks_invoke *sks_ctx,
+		      unsigned long cmd,
+		      void *ctrl, size_t ctrl_sz,
+		      void *in, size_t in_sz)
+{
+	return invoke_ta(sks_ctx, cmd, ctrl, ctrl_sz,
+			 in, &in_sz, DIR_IN,
+			 NULL, NULL, DIR_NONE);
+}
+
+
+CK_RV ck_invoke_ta_in_out(struct sks_invoke *sks_ctx,
+		   unsigned long cmd,
+		   void *ctrl, size_t ctrl_sz,
+		   void *in, size_t in_sz,
+		   void *out, size_t *out_sz)
+{
+	return invoke_ta(sks_ctx, cmd, ctrl, ctrl_sz,
+			 in, &in_sz, DIR_IN,
+			 out, out_sz, DIR_OUT);
+}
+
+CK_RV ck_invoke_ta_in_in(struct sks_invoke *sks_ctx,
+		   unsigned long cmd,
+		   void *ctrl, size_t ctrl_sz,
+		   void *in, size_t in_sz,
+		   void *in2, size_t in2_sz)
+{
+	return invoke_ta(sks_ctx, cmd, ctrl, ctrl_sz,
+			 in, &in_sz, DIR_IN,
+			 in2, &in2_sz, DIR_IN);
+}
+
+void sks_invoke_terminate(void)
+{
+	close_primary_context();
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/invoke_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/invoke_ta.h
new file mode 100644
index 0000000..42d5d88
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/invoke_ta.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __INVOKE_TA_H
+#define __INVOKE_TA_H
+
+#include <pkcs11.h>
+#include <tee_client_api.h>
+
+/*
+ * structure stored in CK session so it calls through the right
+ * GPD TEE session. TEEC type as abstract through void pointers
+ * to prevent CK messing with TEEC API.
+ *
+ * The structure must be reset to zero prior being used.
+ */
+struct sks_invoke {
+	void *context;
+	void *session;
+};
+
+/**
+ * alloc_shm - Allocate memory in the TEE SHM (in, out or in/out)
+ *
+ * @owner - Supplied TEE session or NULL
+ * @size - allocated size in byte
+ *
+ * Return a shm reference or NULL on failure.
+ *
+ * Allocate input SHM on behalf of supplied TEE context.
+ * If the supplied context is not initialized, init it through
+ * the primary TEE context.
+ * If there is no supplied context (ctx is NULL), allocate
+ * on behalf of the primary TEE session context.
+ */
+TEEC_SharedMemory *sks_alloc_shm(struct sks_invoke *ctx,
+				 size_t size, int in, int out);
+
+static inline TEEC_SharedMemory *sks_alloc_shm_in(struct sks_invoke *ctx,
+						  size_t size)
+{
+	return sks_alloc_shm(ctx, size, 1, 0);
+}
+static inline TEEC_SharedMemory *sks_alloc_shm_out(struct sks_invoke *ctx,
+						   size_t size)
+{
+	return sks_alloc_shm(ctx, size, 0, 1);
+}
+static inline TEEC_SharedMemory *sks_alloc_shm_inout(struct sks_invoke *ctx,
+						     size_t size)
+{
+	return sks_alloc_shm(ctx, size, 1, 1);
+}
+
+/**
+ * register_shm - Register buffer as TEE SHM memory (in, out or in/out)
+ *
+ * @owner - Supplied TEE session or NULL
+ * @buffer - pointer to the buffer to be registered
+ * @size - allocated size in byte
+ *
+ * Return a shm reference or NULL on failure.
+ *
+ * Allocate input SHM on behalf of supplied TEE context.
+ * If the supplied context is not initialized, init it through
+ * the primary TEE context.
+ * If there is no supplied context (ctx is NULL), allocate
+ * on behalf of the primary TEE session context.
+ */
+TEEC_SharedMemory *sks_register_shm(struct sks_invoke *ctx, void *buf,
+				    size_t size, int in, int out);
+
+static inline TEEC_SharedMemory *sks_register_shm_in(struct sks_invoke *ctx,
+						     void *buf, size_t size)
+{
+	return sks_register_shm(ctx, buf, size, 1, 0);
+}
+static inline TEEC_SharedMemory *sks_register_shm_out(struct sks_invoke *ctx,
+						      void *buf, size_t size)
+{
+	return sks_register_shm(ctx, buf, size, 0, 1);
+}
+static inline TEEC_SharedMemory *sks_register_shm_inout(struct sks_invoke *ctx,
+							void *buf, size_t size)
+{
+	return sks_register_shm(ctx, buf, size, 1, 1);
+}
+
+/**
+ * free_shm - Release allocated or registered emory in the TEE SHM
+ *
+ * @shm - memory reference
+ */
+void sks_free_shm(TEEC_SharedMemory *shm);
+
+/**
+ * ck_invoke_ta*() - Invoke a SKS request to the TEE
+ * ck_invoke_ta_in() - Invoke a SKS request to the TEE
+ * ck_invoke_ta_in_out() - Invoke a SKS request to the TEE
+ * ck_invoke_ta_in_in() - Invoke a SKS request to the TEE
+ *
+ * @ctx - supplied TEE session context
+ * @cmd - SKS TA command ID
+ * @ctrl - command serialized input arguments. Shm, buffer or NULL pointer.
+ * @ctrl_sz - byte size of ctrl if ctrl is a buffer pointer
+ * @in - input to-be-processed data. Shm, buffer or NULL pointer.
+ * @in_sz - byte size of @in if @in is a buffer pointer
+ * @in_in - 1 if input, 0 if output, meaningless if @in is a Shm reference
+ * @out - output data. Shm, buffer or NULL pointer.
+ * @out_sz - byte size of @out if @out is a buffer pointer
+ * @out_in - 1 if input, 0 if output, meaningless if @out is a Shm reference
+ * @in2 - secondary input to-be-processed data. Shm, buffer or NULL pointer.
+ * @in2_sz - byte size of @in2 if @in2 is a buffer pointer
+ * @in2_in - 1 if input, 0 if output, meaningless if @in2 is a Shm reference
+ *
+ * Return a CK_RV return value.
+ *
+ * Allocate input SHM on behalf of supplied TEE context.
+ * If the supplied context is not initialized, init it through
+ * the primary TEE context.
+ * If there is no supplied context (ctx is NULL), allocate
+ * on behalf of the primary TEE session context.
+ *
+ * ctrl, in and out can be NULL pointer (no related data), buffer pointer
+ * (related data are stored in a memory buffer not registered as TEE SHM)
+ * or a SHM reference (related data are stored in a buffer registered as
+ * TEE SHM).
+ * ctrl_sz, in_sz and out_sz are null if the related reference is a SHM buffer
+ * and are not null if the related reference is a non SHM buffer. Note that
+ * out_sz is a pointer.
+ */
+
+CK_RV ck_invoke_ta(struct sks_invoke *sks_ctx,
+		   unsigned long cmd,
+		   void *ctrl, size_t ctrl_sz);
+
+CK_RV ck_invoke_ta_in(struct sks_invoke *sks_ctx,
+		      unsigned long cmd,
+		      void *ctrl, size_t ctrl_sz,
+		      void *in, size_t in_sz);
+
+CK_RV ck_invoke_ta_in_out(struct sks_invoke *sks_ctx,
+		   unsigned long cmd,
+		   void *ctrl, size_t ctrl_sz,
+		   void *in, size_t in_sz,
+		   void *out, size_t *out_sz);
+
+CK_RV ck_invoke_ta_in_in(struct sks_invoke *sks_ctx,
+		   unsigned long cmd,
+		   void *ctrl, size_t ctrl_sz,
+		   void *in, size_t in_sz,
+		   void *in2, size_t in2_sz);
+
+/* sks_invoke_terminate - Release all allocated invocation resources */
+void sks_invoke_terminate(void);
+
+#endif /*__INVOKE_TA_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/local_utils.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/local_utils.h
new file mode 100644
index 0000000..2242959
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/local_utils.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#ifndef __LOCAL_UTILS_H
+#define __LOCAL_UTILS_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define LOG_ERROR(...)	printf(__VA_ARGS__)
+#define LOG_INFO(...)	printf(__VA_ARGS__)
+#define LOG_DEBUG(...)	printf(__VA_ARGS__)
+
+#define ARRAY_SIZE(array)	(sizeof(array) / sizeof(array[0]))
+
+#endif /*__LOCAL_UTILS_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_api.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_api.c
new file mode 100644
index 0000000..20e8008
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_api.c
@@ -0,0 +1,2346 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#include <assert.h>
+#include <pkcs11.h>
+#include <stdlib.h>
+
+#include "invoke_ta.h"
+#include "local_utils.h"
+#include "pkcs11_processing.h"
+#include "pkcs11_token.h"
+#include "ck_helpers.h"
+
+static int lib_inited;
+
+#define REGISTER_CK_FUNCTION(_function)		._function = _function
+#define DO_NOT_REGISTER_CK_FUNCTION(_function)	._function = NULL
+
+static const CK_FUNCTION_LIST libsks_function_list = {
+	.version = {
+		.major = 2,
+		.minor = 40,
+	},
+	REGISTER_CK_FUNCTION(C_Initialize),
+	REGISTER_CK_FUNCTION(C_Finalize),
+	REGISTER_CK_FUNCTION(C_GetInfo),
+	REGISTER_CK_FUNCTION(C_GetFunctionList),
+	REGISTER_CK_FUNCTION(C_GetSlotList),
+	REGISTER_CK_FUNCTION(C_GetSlotInfo),
+	REGISTER_CK_FUNCTION(C_GetTokenInfo),
+	REGISTER_CK_FUNCTION(C_GetMechanismList),
+	REGISTER_CK_FUNCTION(C_GetMechanismInfo),
+	REGISTER_CK_FUNCTION(C_InitToken),
+	REGISTER_CK_FUNCTION(C_InitPIN),
+	REGISTER_CK_FUNCTION(C_SetPIN),
+	REGISTER_CK_FUNCTION(C_OpenSession),
+	REGISTER_CK_FUNCTION(C_CloseSession),
+	REGISTER_CK_FUNCTION(C_CloseAllSessions),
+	REGISTER_CK_FUNCTION(C_GetSessionInfo),
+	REGISTER_CK_FUNCTION(C_GetOperationState),
+	REGISTER_CK_FUNCTION(C_SetOperationState),
+	REGISTER_CK_FUNCTION(C_Login),
+	REGISTER_CK_FUNCTION(C_Logout),
+	REGISTER_CK_FUNCTION(C_CreateObject),
+	REGISTER_CK_FUNCTION(C_CopyObject),
+	REGISTER_CK_FUNCTION(C_DestroyObject),
+	REGISTER_CK_FUNCTION(C_GetObjectSize),
+	REGISTER_CK_FUNCTION(C_GetAttributeValue),
+	REGISTER_CK_FUNCTION(C_SetAttributeValue),
+	REGISTER_CK_FUNCTION(C_FindObjectsInit),
+	REGISTER_CK_FUNCTION(C_FindObjects),
+	REGISTER_CK_FUNCTION(C_FindObjectsFinal),
+	REGISTER_CK_FUNCTION(C_EncryptInit),
+	REGISTER_CK_FUNCTION(C_Encrypt),
+	REGISTER_CK_FUNCTION(C_EncryptUpdate),
+	REGISTER_CK_FUNCTION(C_EncryptFinal),
+	REGISTER_CK_FUNCTION(C_DecryptInit),
+	REGISTER_CK_FUNCTION(C_Decrypt),
+	REGISTER_CK_FUNCTION(C_DecryptUpdate),
+	REGISTER_CK_FUNCTION(C_DecryptFinal),
+	REGISTER_CK_FUNCTION(C_DigestInit),
+	REGISTER_CK_FUNCTION(C_Digest),
+	REGISTER_CK_FUNCTION(C_DigestUpdate),
+	REGISTER_CK_FUNCTION(C_DigestKey),
+	REGISTER_CK_FUNCTION(C_DigestFinal),
+	REGISTER_CK_FUNCTION(C_SignInit),
+	REGISTER_CK_FUNCTION(C_Sign),
+	REGISTER_CK_FUNCTION(C_SignUpdate),
+	REGISTER_CK_FUNCTION(C_SignFinal),
+	REGISTER_CK_FUNCTION(C_SignRecoverInit),
+	REGISTER_CK_FUNCTION(C_SignRecover),
+	REGISTER_CK_FUNCTION(C_VerifyInit),
+	REGISTER_CK_FUNCTION(C_Verify),
+	REGISTER_CK_FUNCTION(C_VerifyUpdate),
+	REGISTER_CK_FUNCTION(C_VerifyFinal),
+	REGISTER_CK_FUNCTION(C_VerifyRecoverInit),
+	REGISTER_CK_FUNCTION(C_VerifyRecover),
+	REGISTER_CK_FUNCTION(C_DigestEncryptUpdate),
+	REGISTER_CK_FUNCTION(C_DecryptDigestUpdate),
+	REGISTER_CK_FUNCTION(C_SignEncryptUpdate),
+	REGISTER_CK_FUNCTION(C_DecryptVerifyUpdate),
+	REGISTER_CK_FUNCTION(C_GenerateKey),
+	REGISTER_CK_FUNCTION(C_GenerateKeyPair),
+	REGISTER_CK_FUNCTION(C_WrapKey),
+	REGISTER_CK_FUNCTION(C_UnwrapKey),
+	REGISTER_CK_FUNCTION(C_DeriveKey),
+	REGISTER_CK_FUNCTION(C_SeedRandom),
+	REGISTER_CK_FUNCTION(C_GenerateRandom),
+	REGISTER_CK_FUNCTION(C_GetFunctionStatus),
+	REGISTER_CK_FUNCTION(C_CancelFunction),
+	REGISTER_CK_FUNCTION(C_WaitForSlotEvent),
+};
+
+/*
+ * List of all PKCS#11 cryptoki API functions implemented
+ */
+
+CK_RV C_Initialize(CK_VOID_PTR init_args)
+{
+	(void)init_args;
+	CK_C_INITIALIZE_ARGS_PTR args = NULL;
+
+	if (init_args) {
+		args = (CK_C_INITIALIZE_ARGS_PTR)init_args;
+		/* Reserved must be set to NULL in this version of PKCS#11 */
+		if (args->reserved)
+			return CKR_ARGUMENTS_BAD;
+	}
+
+	if (lib_inited)
+		return CKR_CRYPTOKI_ALREADY_INITIALIZED;
+
+	lib_inited = 1;
+	return CKR_OK;
+}
+
+CK_RV C_Finalize(CK_VOID_PTR res)
+{
+	(void)res;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	/* Reserved must be set to NULL in this version of PKCS#11 */
+	if (res)
+		return CKR_ARGUMENTS_BAD;
+
+	sks_invoke_terminate();
+
+	lib_inited = 0;
+
+	return CKR_OK;
+}
+
+CK_RV C_GetInfo(CK_INFO_PTR info)
+{
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	if (!info)
+		return CKR_ARGUMENTS_BAD;
+
+	return sks_ck_get_info(info);
+}
+
+CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
+{
+	if (!ppFunctionList)
+		return CKR_ARGUMENTS_BAD;
+
+	/* Discard the const attribute when exporting the list address */
+	*ppFunctionList = (void *)&libsks_function_list;
+
+	return CKR_OK;
+}
+
+CK_RV C_GetSlotList(CK_BBOOL token_present,
+		    CK_SLOT_ID_PTR slots,
+		    CK_ULONG_PTR count)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_slot_get_list(token_present, slots, count);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_GetSlotInfo(CK_SLOT_ID slot,
+		    CK_SLOT_INFO_PTR info)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_slot_get_info(slot, info);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_SLOT_ID_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_InitToken(CK_SLOT_ID slot,
+		  CK_UTF8CHAR_PTR pin,
+		  CK_ULONG pin_len,
+		  CK_UTF8CHAR_PTR label)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_init_token(slot, pin, pin_len, label);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_PIN_INCORRECT:
+	case CKR_PIN_LOCKED:
+	case CKR_SESSION_EXISTS:
+	case CKR_SLOT_ID_INVALID:
+	case CKR_TOKEN_NOT_PRESENT:
+	case CKR_TOKEN_NOT_RECOGNIZED:
+	case CKR_TOKEN_WRITE_PROTECTED:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_GetTokenInfo(CK_SLOT_ID slot,
+		     CK_TOKEN_INFO_PTR info)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_token_get_info(slot, info);
+
+	switch (rv) {
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_SLOT_ID_INVALID:
+	case CKR_TOKEN_NOT_PRESENT:
+	case CKR_TOKEN_NOT_RECOGNIZED:
+	case CKR_ARGUMENTS_BAD:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_GetMechanismList(CK_SLOT_ID slot,
+			 CK_MECHANISM_TYPE_PTR mechanisms,
+			 CK_ULONG_PTR count)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_token_mechanism_ids(slot, mechanisms, count);
+
+	switch (rv) {
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_SLOT_ID_INVALID:
+	case CKR_TOKEN_NOT_PRESENT:
+	case CKR_TOKEN_NOT_RECOGNIZED:
+	case CKR_ARGUMENTS_BAD:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_GetMechanismInfo(CK_SLOT_ID slot,
+			 CK_MECHANISM_TYPE type,
+			 CK_MECHANISM_INFO_PTR info)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_token_mechanism_info(slot, type, info);
+
+	switch (rv) {
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_MECHANISM_INVALID:
+	case CKR_OK:
+	case CKR_SLOT_ID_INVALID:
+	case CKR_TOKEN_NOT_PRESENT:
+	case CKR_TOKEN_NOT_RECOGNIZED:
+	case CKR_ARGUMENTS_BAD:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_OpenSession(CK_SLOT_ID slot,
+		    CK_FLAGS flags,
+		    CK_VOID_PTR cookie,
+		    CK_NOTIFY callback,
+		    CK_SESSION_HANDLE_PTR session)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	if (flags & ~(CKF_RW_SESSION | CKF_SERIAL_SESSION))
+		return CKR_ARGUMENTS_BAD;
+
+	/* Specific mandated flag */
+	if (!(flags & CKF_SERIAL_SESSION))
+		return CKR_SESSION_PARALLEL_NOT_SUPPORTED;
+
+	rv = sks_ck_open_session(slot, flags, cookie, callback, session);
+
+	switch (rv) {
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_SESSION_COUNT:
+	case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
+	case CKR_SESSION_READ_WRITE_SO_EXISTS:
+	case CKR_SLOT_ID_INVALID:
+	case CKR_TOKEN_NOT_PRESENT:
+	case CKR_TOKEN_NOT_RECOGNIZED:
+	case CKR_TOKEN_WRITE_PROTECTED:
+	case CKR_ARGUMENTS_BAD:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_CloseSession(CK_SESSION_HANDLE session)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_close_session(session);
+
+	switch (rv) {
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_CloseAllSessions(CK_SLOT_ID slot)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_close_all_sessions(slot);
+
+	switch (rv) {
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_SLOT_ID_INVALID:
+	case CKR_TOKEN_NOT_PRESENT:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_GetSessionInfo(CK_SESSION_HANDLE session,
+		       CK_SESSION_INFO_PTR info)
+{
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return sks_ck_get_session_info(session, info);
+}
+
+CK_RV C_InitPIN(CK_SESSION_HANDLE session,
+		CK_UTF8CHAR_PTR pin,
+		CK_ULONG pin_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_init_pin(session, pin, pin_len);
+
+	switch (rv) {
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_PIN_INVALID:
+	case CKR_PIN_LEN_RANGE:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_READ_ONLY:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_TOKEN_WRITE_PROTECTED:
+	case CKR_USER_NOT_LOGGED_IN:
+	case CKR_ARGUMENTS_BAD:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_SetPIN(CK_SESSION_HANDLE session,
+	       CK_UTF8CHAR_PTR old,
+	       CK_ULONG old_len,
+	       CK_UTF8CHAR_PTR new,
+	       CK_ULONG new_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_set_pin(session, old, old_len, new, new_len);
+
+	switch (rv) {
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_MECHANISM_INVALID:
+	case CKR_OK:
+	case CKR_PIN_INCORRECT:
+	case CKR_PIN_INVALID:
+	case CKR_PIN_LEN_RANGE:
+	case CKR_PIN_LOCKED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_READ_ONLY:
+	case CKR_TOKEN_WRITE_PROTECTED:
+	case CKR_ARGUMENTS_BAD:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_Login(CK_SESSION_HANDLE session,
+	      CK_USER_TYPE user_type,
+	      CK_UTF8CHAR_PTR pin,
+	      CK_ULONG pin_len)
+
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_login(session, user_type, pin, pin_len);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_PIN_INCORRECT:
+	case CKR_PIN_LOCKED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_READ_ONLY_EXISTS:
+	case CKR_USER_ALREADY_LOGGED_IN:
+	case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
+	case CKR_USER_PIN_NOT_INITIALIZED:
+	case CKR_USER_TOO_MANY_TYPES:
+	case CKR_USER_TYPE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_Logout(CK_SESSION_HANDLE session)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = sks_ck_logout(session);
+
+	switch (rv) {
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_GetOperationState(CK_SESSION_HANDLE session,
+			  CK_BYTE_PTR state,
+			  CK_ULONG_PTR state_len)
+{
+	(void)session;
+	(void)state;
+	(void)state_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_SetOperationState(CK_SESSION_HANDLE session,
+			  CK_BYTE_PTR state,
+			  CK_ULONG state_len,
+			  CK_OBJECT_HANDLE ciph_key,
+			  CK_OBJECT_HANDLE auth_key)
+{
+	(void)session;
+	(void)state;
+	(void)state_len;
+	(void)ciph_key;
+	(void)auth_key;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_CreateObject(CK_SESSION_HANDLE session,
+		     CK_ATTRIBUTE_PTR attribs,
+		     CK_ULONG count,
+		     CK_OBJECT_HANDLE_PTR phObject)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_create_object(session, attribs, count, phObject);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_ATTRIBUTE_READ_ONLY:
+	case CKR_ATTRIBUTE_TYPE_INVALID:
+	case CKR_ATTRIBUTE_VALUE_INVALID:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_CURVE_NOT_SUPPORTED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_DOMAIN_PARAMS_INVALID:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_READ_ONLY:
+	case CKR_TEMPLATE_INCOMPLETE:
+	case CKR_TEMPLATE_INCONSISTENT:
+	case CKR_TOKEN_WRITE_PROTECTED:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_CopyObject(CK_SESSION_HANDLE session,
+		   CK_OBJECT_HANDLE obj,
+		   CK_ATTRIBUTE_PTR attribs,
+		   CK_ULONG count,
+		   CK_OBJECT_HANDLE_PTR new_obj)
+{
+	(void)session;
+	(void)obj;
+	(void)attribs;
+	(void)count;
+	(void)new_obj;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_DestroyObject(CK_SESSION_HANDLE session,
+		      CK_OBJECT_HANDLE obj)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_destroy_object(session, obj);
+
+	switch (rv) {
+	case CKR_ACTION_PROHIBITED:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OBJECT_HANDLE_INVALID:
+	case CKR_OK:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_READ_ONLY:
+	case CKR_TOKEN_WRITE_PROTECTED:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_GetObjectSize(CK_SESSION_HANDLE session,
+		      CK_OBJECT_HANDLE obj,
+		      CK_ULONG_PTR out_size)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_get_object_size(session, obj, out_size);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_INFORMATION_SENSITIVE:
+	case CKR_OBJECT_HANDLE_INVALID:
+	case CKR_OK:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_GetAttributeValue(CK_SESSION_HANDLE session,
+			  CK_OBJECT_HANDLE obj,
+			  CK_ATTRIBUTE_PTR attribs,
+			  CK_ULONG count)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_get_attribute_value(session, obj, attribs, count);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_ATTRIBUTE_SENSITIVE:
+	case CKR_ATTRIBUTE_TYPE_INVALID:
+	case CKR_ATTRIBUTE_VALUE_INVALID:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_OBJECT_HANDLE_INVALID:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_SetAttributeValue(CK_SESSION_HANDLE session,
+			  CK_OBJECT_HANDLE obj,
+			  CK_ATTRIBUTE_PTR attribs,
+			  CK_ULONG count)
+{
+	(void)session;
+	(void)obj;
+	(void)attribs;
+	(void)count;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_FindObjectsInit(CK_SESSION_HANDLE session,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_find_objects_init(session, attribs, count);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_ATTRIBUTE_TYPE_INVALID:
+	case CKR_ATTRIBUTE_VALUE_INVALID:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_FindObjects(CK_SESSION_HANDLE session,
+		    CK_OBJECT_HANDLE_PTR obj,
+		    CK_ULONG max_count,
+		    CK_ULONG_PTR count)
+
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_find_objects(session, obj, max_count, count);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE session)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_find_objects_final(session);
+
+	switch (rv) {
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_EncryptInit(CK_SESSION_HANDLE session,
+		    CK_MECHANISM_PTR mechanism,
+		    CK_OBJECT_HANDLE key)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_encdecrypt_init(session, mechanism, key, CK_FALSE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_KEY_FUNCTION_NOT_PERMITTED:
+	case CKR_KEY_HANDLE_INVALID:
+	case CKR_KEY_SIZE_RANGE:
+	case CKR_KEY_TYPE_INCONSISTENT:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_Encrypt(CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_encdecrypt_oneshot(session, in, in_len, out, out_len, CK_FALSE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DATA_LEN_RANGE:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_EncryptUpdate(CK_SESSION_HANDLE session,
+		      CK_BYTE_PTR in,
+		      CK_ULONG in_len,
+		      CK_BYTE_PTR out,
+		      CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_encdecrypt_update(session, in, in_len, out, out_len, CK_FALSE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DATA_LEN_RANGE:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_EncryptFinal(CK_SESSION_HANDLE session,
+		     CK_BYTE_PTR out,
+		     CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_encdecrypt_final(session, out, out_len, CK_FALSE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DATA_LEN_RANGE:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_DecryptInit(CK_SESSION_HANDLE session,
+		    CK_MECHANISM_PTR  mechanism,
+		    CK_OBJECT_HANDLE  key)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_encdecrypt_init(session, mechanism, key, CK_TRUE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_KEY_FUNCTION_NOT_PERMITTED:
+	case CKR_KEY_HANDLE_INVALID:
+	case CKR_KEY_SIZE_RANGE:
+	case CKR_KEY_TYPE_INCONSISTENT:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_Decrypt(CK_SESSION_HANDLE session,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_encdecrypt_oneshot(session, in, in_len, out, out_len, CK_TRUE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_ENCRYPTED_DATA_INVALID:
+	case CKR_ENCRYPTED_DATA_LEN_RANGE:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_DecryptUpdate(CK_SESSION_HANDLE session,
+		      CK_BYTE_PTR in,
+		      CK_ULONG in_len,
+		      CK_BYTE_PTR out,
+		      CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_encdecrypt_update(session, in, in_len, out, out_len, CK_TRUE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_ENCRYPTED_DATA_INVALID:
+	case CKR_ENCRYPTED_DATA_LEN_RANGE:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_DecryptFinal(CK_SESSION_HANDLE session,
+		     CK_BYTE_PTR out,
+		     CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_encdecrypt_final(session, out, out_len, CK_TRUE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_ENCRYPTED_DATA_INVALID:
+	case CKR_ENCRYPTED_DATA_LEN_RANGE:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+
+CK_RV C_DigestInit(CK_SESSION_HANDLE session,
+		   CK_MECHANISM_PTR  mechanism)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_digest_init(session, mechanism);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_KEY_FUNCTION_NOT_PERMITTED:
+	case CKR_KEY_HANDLE_INVALID:
+	case CKR_KEY_SIZE_RANGE:
+	case CKR_KEY_TYPE_INCONSISTENT:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_Digest(CK_SESSION_HANDLE session,
+	       CK_BYTE_PTR in,
+	       CK_ULONG in_len,
+	       CK_BYTE_PTR out,
+	       CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_digest_oneshot(session, in, in_len, out, out_len);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_KEY_FUNCTION_NOT_PERMITTED:
+	case CKR_KEY_HANDLE_INVALID:
+	case CKR_KEY_SIZE_RANGE:
+	case CKR_KEY_TYPE_INCONSISTENT:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_DigestUpdate(CK_SESSION_HANDLE session,
+  		      CK_BYTE_PTR in,
+		      CK_ULONG in_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_digest_update(session, in, in_len);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_KEY_FUNCTION_NOT_PERMITTED:
+	case CKR_KEY_HANDLE_INVALID:
+	case CKR_KEY_SIZE_RANGE:
+	case CKR_KEY_TYPE_INCONSISTENT:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_DigestKey(CK_SESSION_HANDLE session,
+		  CK_OBJECT_HANDLE  key)
+{
+	(void)session;
+	(void)key;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_DigestFinal(CK_SESSION_HANDLE session,
+		    CK_BYTE_PTR digest,
+		    CK_ULONG_PTR len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_digest_final(session, digest, len);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_KEY_FUNCTION_NOT_PERMITTED:
+	case CKR_KEY_HANDLE_INVALID:
+	case CKR_KEY_SIZE_RANGE:
+	case CKR_KEY_TYPE_INCONSISTENT:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_SignInit(CK_SESSION_HANDLE session,
+		 CK_MECHANISM_PTR mechanism,
+		 CK_OBJECT_HANDLE key)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_signverify_init(session, mechanism, key, CK_TRUE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_KEY_FUNCTION_NOT_PERMITTED:
+	case CKR_KEY_HANDLE_INVALID:
+	case CKR_KEY_SIZE_RANGE:
+	case CKR_KEY_TYPE_INCONSISTENT:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_Sign(CK_SESSION_HANDLE session,
+	     CK_BYTE_PTR       in,
+	     CK_ULONG          in_len,
+	     CK_BYTE_PTR       out,
+	     CK_ULONG_PTR      out_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_signverify_oneshot(session, in, in_len, out, out_len, CK_TRUE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DATA_INVALID:
+	case CKR_DATA_LEN_RANGE:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+	case CKR_FUNCTION_REJECTED:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_SignUpdate(CK_SESSION_HANDLE session,
+		   CK_BYTE_PTR in,
+		   CK_ULONG in_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_signverify_update(session, in, in_len, CK_TRUE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DATA_LEN_RANGE:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_SignFinal(CK_SESSION_HANDLE session,
+		  CK_BYTE_PTR out,
+		  CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_signverify_final(session, out, out_len, CK_TRUE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_BUFFER_TOO_SMALL:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DATA_LEN_RANGE:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+	case CKR_FUNCTION_REJECTED:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_SignRecoverInit(CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR  mechanism,
+			CK_OBJECT_HANDLE  key)
+{
+	(void)session;
+	(void)mechanism;
+	(void)key;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_SignRecover(CK_SESSION_HANDLE session,
+		    CK_BYTE_PTR in,
+		    CK_ULONG in_len,
+		    CK_BYTE_PTR out,
+		    CK_ULONG_PTR out_len)
+{
+	(void)session;
+	(void)in;
+	(void)in_len;
+	(void)out;
+	(void)out_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_VerifyInit(CK_SESSION_HANDLE session,
+		   CK_MECHANISM_PTR  mechanism,
+		   CK_OBJECT_HANDLE  key)
+{
+	CK_RV rv;
+
+	rv = ck_signverify_init(session, mechanism, key, CK_FALSE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_KEY_FUNCTION_NOT_PERMITTED:
+	case CKR_KEY_HANDLE_INVALID:
+	case CKR_KEY_SIZE_RANGE:
+	case CKR_KEY_TYPE_INCONSISTENT:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_Verify(CK_SESSION_HANDLE session,
+	       CK_BYTE_PTR in,
+	       CK_ULONG in_len,
+	       CK_BYTE_PTR out,
+	       CK_ULONG out_len)
+{
+	CK_RV rv;
+	CK_ULONG out_size = out_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_signverify_oneshot(session, in, in_len, out, &out_size,
+				   CK_FALSE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DATA_INVALID:
+	case CKR_DATA_LEN_RANGE:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SIGNATURE_INVALID:
+	case CKR_SIGNATURE_LEN_RANGE:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_VerifyUpdate(CK_SESSION_HANDLE session,
+		     CK_BYTE_PTR in,
+		     CK_ULONG in_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_signverify_update(session, in, in_len, CK_FALSE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DATA_LEN_RANGE:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_VerifyFinal(CK_SESSION_HANDLE session,
+		    CK_BYTE_PTR sign,
+		    CK_ULONG sign_len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_signverify_final(session, sign, &sign_len, CK_FALSE);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_DATA_LEN_RANGE:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_OPERATION_NOT_INITIALIZED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SIGNATURE_INVALID:
+	case CKR_SIGNATURE_LEN_RANGE:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE session,
+			  CK_MECHANISM_PTR mechanism,
+			  CK_OBJECT_HANDLE key)
+{
+	(void)session;
+	(void)mechanism;
+	(void)key;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_VerifyRecover(CK_SESSION_HANDLE session,
+		      CK_BYTE_PTR in,
+		      CK_ULONG in_len,
+		      CK_BYTE_PTR out,
+		      CK_ULONG_PTR out_len)
+{
+	(void)session;
+	(void)in;
+	(void)in_len;
+	(void)out;
+	(void)out_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE session,
+			    CK_BYTE_PTR in,
+			    CK_ULONG in_len,
+			    CK_BYTE_PTR out,
+			    CK_ULONG_PTR out_len)
+{
+	(void)session;
+	(void)in;
+	(void)in_len;
+	(void)out;
+	(void)out_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE session,
+			    CK_BYTE_PTR in,
+			    CK_ULONG in_len,
+			    CK_BYTE_PTR out,
+			    CK_ULONG_PTR out_len)
+{
+	(void)session;
+	(void)in;
+	(void)in_len;
+	(void)out;
+	(void)out_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+
+CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE session,
+			  CK_BYTE_PTR in,
+			  CK_ULONG in_len,
+			  CK_BYTE_PTR out,
+			  CK_ULONG_PTR out_len)
+{
+	(void)session;
+	(void)in;
+	(void)in_len;
+	(void)out;
+	(void)out_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE session,
+			    CK_BYTE_PTR in,
+			    CK_ULONG in_len,
+			    CK_BYTE_PTR out,
+			    CK_ULONG_PTR out_len)
+{
+	(void)session;
+	(void)in;
+	(void)in_len;
+	(void)out;
+	(void)out_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_GenerateKey(CK_SESSION_HANDLE session,
+		    CK_MECHANISM_PTR mechanism,
+		    CK_ATTRIBUTE_PTR attribs,
+		    CK_ULONG count,
+		    CK_OBJECT_HANDLE_PTR handle)
+{
+	CK_RV rv;
+	CK_ATTRIBUTE_PTR attribs_n = NULL;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_add_object_class(attribs, &count,
+			&attribs_n, CKO_SECRET_KEY);
+	if (rv != CKR_OK) {
+		if (attribs_n)
+			free(attribs_n);
+		return rv;
+	}
+
+	rv = ck_generate_key(session, mechanism, attribs_n, count, handle);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_ATTRIBUTE_READ_ONLY:
+	case CKR_ATTRIBUTE_TYPE_INVALID:
+	case CKR_ATTRIBUTE_VALUE_INVALID:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_CURVE_NOT_SUPPORTED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_READ_ONLY:
+	case CKR_TEMPLATE_INCOMPLETE:
+	case CKR_TEMPLATE_INCONSISTENT:
+	case CKR_TOKEN_WRITE_PROTECTED:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	if (attribs_n)
+		free(attribs_n);
+	return rv;
+}
+
+CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_ATTRIBUTE_PTR pub_attribs,
+			CK_ULONG pub_count,
+			CK_ATTRIBUTE_PTR priv_attribs,
+			CK_ULONG priv_count,
+			CK_OBJECT_HANDLE_PTR pub_key,
+			CK_OBJECT_HANDLE_PTR priv_key)
+{
+	CK_RV rv;
+	CK_ATTRIBUTE_PTR pub_attribs_n = NULL;
+	CK_ATTRIBUTE_PTR priv_attribs_n = NULL;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	if (!mechanism || !pub_key || !priv_key)
+		return CKR_ARGUMENTS_BAD;
+
+	if (pub_count && !pub_attribs)
+		return CKR_ARGUMENTS_BAD;
+
+	if (priv_count && !priv_attribs)
+		return CKR_ARGUMENTS_BAD;
+
+
+	rv = ck_guess_key_type(mechanism, pub_attribs, &pub_count,
+			       &pub_attribs_n);
+	if (rv != CKR_OK)
+		goto bail;
+
+	rv = ck_add_object_class(pub_attribs_n, &pub_count,
+				   &pub_attribs_n, CKO_PUBLIC_KEY);
+	if (rv != CKR_OK)
+		goto bail;
+
+	rv = ck_guess_key_type(mechanism, priv_attribs, &priv_count,
+				   &priv_attribs_n);
+	if (rv != CKR_OK)
+		goto bail;
+
+	rv = ck_add_object_class(priv_attribs_n, &priv_count,
+				   &priv_attribs_n, CKO_PRIVATE_KEY);
+	if (rv != CKR_OK)
+		goto bail;
+
+	rv = ck_generate_key_pair(session, mechanism, pub_attribs_n, pub_count,
+				  priv_attribs_n, priv_count, pub_key, priv_key);
+
+bail:
+	if (pub_attribs_n)
+		free(pub_attribs_n);
+	if (priv_attribs_n)
+		free(priv_attribs_n);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_ATTRIBUTE_READ_ONLY:
+	case CKR_ATTRIBUTE_TYPE_INVALID:
+	case CKR_ATTRIBUTE_VALUE_INVALID:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_CURVE_NOT_SUPPORTED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_DOMAIN_PARAMS_INVALID:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_READ_ONLY:
+	case CKR_TEMPLATE_INCOMPLETE:
+	case CKR_TEMPLATE_INCONSISTENT:
+	case CKR_TOKEN_WRITE_PROTECTED:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_WrapKey(CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR  mechanism,
+		CK_OBJECT_HANDLE wrap_key,
+		CK_OBJECT_HANDLE key,
+		CK_BYTE_PTR wrapped_key,
+		CK_ULONG_PTR wrapped_key_len)
+{
+	(void)session;
+	(void)mechanism;
+	(void)wrap_key;
+	(void)key;
+	(void)wrapped_key;
+	(void)wrapped_key_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_UnwrapKey(CK_SESSION_HANDLE session,
+		  CK_MECHANISM_PTR mechanism,
+		  CK_OBJECT_HANDLE unwrap_key,
+		  CK_BYTE_PTR wrapped_key,
+		  CK_ULONG wrapped_key_len,
+		  CK_ATTRIBUTE_PTR attribs,
+		  CK_ULONG count,
+		  CK_OBJECT_HANDLE_PTR new_key)
+{
+	(void)session;
+	(void)mechanism;
+	(void)unwrap_key;
+	(void)wrapped_key;
+	(void)wrapped_key_len;
+	(void)attribs;
+	(void)count;
+	(void)new_key;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_DeriveKey(CK_SESSION_HANDLE session,
+		  CK_MECHANISM_PTR mechanism,
+		  CK_OBJECT_HANDLE derived_key,
+		  CK_ATTRIBUTE_PTR attribs,
+		  CK_ULONG count,
+		  CK_OBJECT_HANDLE_PTR key_handle)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_derive_key(session, mechanism, derived_key, attribs, count,
+			   key_handle);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_ATTRIBUTE_READ_ONLY:
+	case CKR_ATTRIBUTE_TYPE_INVALID:
+	case CKR_ATTRIBUTE_VALUE_INVALID:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_CURVE_NOT_SUPPORTED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_DOMAIN_PARAMS_INVALID:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_KEY_HANDLE_INVALID:
+	case CKR_KEY_SIZE_RANGE:
+	case CKR_KEY_TYPE_INCONSISTENT:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_READ_ONLY:
+	case CKR_TEMPLATE_INCOMPLETE:
+	case CKR_TEMPLATE_INCONSISTENT:
+	case CKR_TOKEN_WRITE_PROTECTED:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_SeedRandom(CK_SESSION_HANDLE session,
+		   CK_BYTE_PTR seed,
+		   CK_ULONG len)
+{
+	(void)session;
+	(void)seed;
+	(void)len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+CK_RV C_GenerateRandom(CK_SESSION_HANDLE session,
+		       CK_BYTE_PTR out,
+		       CK_ULONG len)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_generate_random(session, out, len);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_ATTRIBUTE_READ_ONLY:
+	case CKR_ATTRIBUTE_TYPE_INVALID:
+	case CKR_ATTRIBUTE_VALUE_INVALID:
+	case CKR_GENERAL_ERROR:
+	case CKR_OK:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE session)
+{
+	(void)session;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_PARALLEL;
+}
+
+CK_RV C_CancelFunction(CK_SESSION_HANDLE session)
+{
+	(void)session;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_PARALLEL;
+}
+
+
+CK_RV C_WaitForSlotEvent(CK_FLAGS flags,
+			 CK_SLOT_ID_PTR slot,
+			 CK_VOID_PTR rsv)
+{
+	(void)flags;
+	(void)slot;
+	(void)rsv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+
+CK_RV C_ImportKey(CK_SESSION_HANDLE session,
+				CK_ATTRIBUTE_PTR attribs,
+				CK_ULONG count,
+				CK_BYTE_PTR keyblob,
+				CK_ULONG_PTR keyblob_length)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_import_key(session, attribs, count, keyblob, keyblob_length);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_ATTRIBUTE_READ_ONLY:
+	case CKR_ATTRIBUTE_TYPE_INVALID:
+	case CKR_ATTRIBUTE_VALUE_INVALID:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_CURVE_NOT_SUPPORTED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_DOMAIN_PARAMS_INVALID:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_OK:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_READ_ONLY:
+	case CKR_TEMPLATE_INCOMPLETE:
+	case CKR_TEMPLATE_INCONSISTENT:
+	case CKR_TOKEN_WRITE_PROTECTED:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_ImportKeyPair(CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_ATTRIBUTE_PTR pub_attribs,
+			CK_ULONG pub_count,
+			CK_ATTRIBUTE_PTR priv_attribs,
+			CK_ULONG priv_count,
+			CK_BYTE_PTR keyblob,
+			CK_ULONG_PTR keyblob_length)
+{
+	CK_RV rv;
+	CK_ATTRIBUTE_PTR pub_attribs_n = NULL;
+	CK_ATTRIBUTE_PTR priv_attribs_n = NULL;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	if (!mechanism)
+		return CKR_ARGUMENTS_BAD;
+
+	if (!keyblob || !keyblob_length)
+		return CKR_ARGUMENTS_BAD;
+
+	if (pub_count && !pub_attribs)
+		return CKR_ARGUMENTS_BAD;
+
+	if (priv_count && !priv_attribs)
+		return CKR_ARGUMENTS_BAD;
+
+
+	rv = ck_guess_key_type(mechanism, pub_attribs, &pub_count,
+			       &pub_attribs_n);
+	if (rv != CKR_OK)
+		goto bail;
+
+	rv = ck_add_object_class(pub_attribs_n, &pub_count,
+				   &pub_attribs_n, CKO_PUBLIC_KEY);
+	if (rv != CKR_OK)
+		goto bail;
+
+	rv = ck_guess_key_type(mechanism, priv_attribs, &priv_count,
+				   &priv_attribs_n);
+	if (rv != CKR_OK)
+		goto bail;
+
+	rv = ck_add_object_class(priv_attribs_n, &priv_count,
+				   &priv_attribs_n, CKO_PRIVATE_KEY);
+	if (rv != CKR_OK)
+		goto bail;
+
+	rv = ck_import_key_pair(session, mechanism, pub_attribs_n, pub_count,
+				  priv_attribs_n, priv_count, keyblob, keyblob_length);
+
+bail:
+	if (pub_attribs_n)
+		free(pub_attribs_n);
+	if (priv_attribs_n)
+		free(priv_attribs_n);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_ATTRIBUTE_READ_ONLY:
+	case CKR_ATTRIBUTE_TYPE_INVALID:
+	case CKR_ATTRIBUTE_VALUE_INVALID:
+	case CKR_CRYPTOKI_NOT_INITIALIZED:
+	case CKR_CURVE_NOT_SUPPORTED:
+	case CKR_DEVICE_ERROR:
+	case CKR_DEVICE_MEMORY:
+	case CKR_DEVICE_REMOVED:
+	case CKR_DOMAIN_PARAMS_INVALID:
+	case CKR_FUNCTION_CANCELED:
+	case CKR_FUNCTION_FAILED:
+	case CKR_GENERAL_ERROR:
+	case CKR_HOST_MEMORY:
+	case CKR_MECHANISM_INVALID:
+	case CKR_MECHANISM_PARAM_INVALID:
+	case CKR_OK:
+	case CKR_OPERATION_ACTIVE:
+	case CKR_PIN_EXPIRED:
+	case CKR_SESSION_CLOSED:
+	case CKR_SESSION_HANDLE_INVALID:
+	case CKR_SESSION_READ_ONLY:
+	case CKR_TEMPLATE_INCOMPLETE:
+	case CKR_TEMPLATE_INCONSISTENT:
+	case CKR_TOKEN_WRITE_PROTECTED:
+	case CKR_USER_NOT_LOGGED_IN:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_ExportKey(CK_SESSION_HANDLE session,
+                  CK_BYTE_PTR keyblob,
+                  CK_ULONG keybloblength,
+                  CK_BYTE_PTR pubkey,
+                  CK_ULONG_PTR pubkeylength)
+{
+	CK_RV rv;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	rv = ck_export_key(session, keyblob, keybloblength, pubkey, pubkeylength);
+
+	switch (rv) {
+	case CKR_ARGUMENTS_BAD:
+	case CKR_GENERAL_ERROR:
+	case CKR_OK:
+		break;
+	default:
+		assert(!rv);
+	}
+
+	return rv;
+}
+
+CK_RV C_Utils(CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len)
+
+{
+	CK_RV rv;
+	CK_ULONG out_size = out_len;
+
+	if (!lib_inited)
+		return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+	if (!mechanism)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = ck_utils(session, mechanism, in, in_len, out, &out_size);
+
+	return rv;
+}
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_processing.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_processing.c
new file mode 100644
index 0000000..987b502
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_processing.c
@@ -0,0 +1,1048 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sks_ta.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tee_client_api.h>
+
+#include "pkcs11_processing.h"
+#include "invoke_ta.h"
+#include "serializer.h"
+#include "serialize_ck.h"
+
+static struct sks_invoke *ck_session2sks_ctx(CK_SESSION_HANDLE session)
+{
+	(void)session;
+	// TODO: find back the invocation context from the session handle
+	// Until we do that, let's use the default invacation context.
+	return NULL;
+}
+
+CK_RV ck_create_object(CK_SESSION_HANDLE session,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count,
+			CK_OBJECT_HANDLE_PTR handle)
+{
+	CK_RV rv;
+	struct serializer obj;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+	uint32_t key_handle;
+	uint32_t session_handle = session;
+	size_t key_handle_size = sizeof(key_handle);
+
+	if (!attribs || !count || !handle)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = serialize_ck_attributes(&obj, attribs, count);
+	if (rv)
+		goto bail;
+
+	/* ctrl = [session-handle][headed-serialized-attributes] */
+	ctrl_size = sizeof(uint32_t) + obj.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), obj.buffer, obj.size);
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_IMPORT_OBJECT, ctrl, ctrl_size,
+				 NULL, 0, &key_handle, &key_handle_size);
+	if (rv)
+		goto bail;
+
+	*handle = key_handle;
+
+bail:
+	release_serial_object(&obj);
+	free(ctrl);
+	return rv;
+}
+
+CK_RV ck_destroy_object(CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE obj)
+{
+	uint32_t ctrl[2] = { (uint32_t)session, (uint32_t)obj };
+
+	return ck_invoke_ta(ck_session2sks_ctx(session),
+			    SKS_CMD_DESTROY_OBJECT, ctrl, sizeof(ctrl));
+}
+
+CK_RV ck_digest_init(CK_SESSION_HANDLE session,
+			 CK_MECHANISM_PTR mechanism)
+{
+	CK_RV rv;
+	struct serializer obj;
+	uint32_t session_handle = session;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+
+	if (!mechanism)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = serialize_ck_mecha_params(&obj, mechanism);
+	if (rv)
+		return rv;
+
+	/* params = [session-handle][key-handle][serialized-mechanism-blob] */
+	ctrl_size = sizeof(uint32_t) + obj.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), obj.buffer, obj.size);
+
+	rv = ck_invoke_ta(ck_session2sks_ctx(session), SKS_CMD_DIGEST_INIT,
+			  ctrl, ctrl_size);
+
+bail:
+	release_serial_object(&obj);
+	free(ctrl);
+	return rv;
+}
+
+CK_RV ck_digest_update(CK_SESSION_HANDLE session,
+			   CK_BYTE_PTR in,
+			   CK_ULONG in_len)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *in_buf = in;
+	size_t in_size = in_len;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_DIGEST_UPDATE,
+				 &ctrl, ctrl_size, in_buf, in_buf ? in_size : 0,
+				 NULL, NULL);
+
+	return rv;
+}
+
+CK_RV ck_digest_oneshot(CK_SESSION_HANDLE session,
+			    CK_BYTE_PTR in,
+			    CK_ULONG in_len,
+			    CK_BYTE_PTR out,
+			    CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *in_buf = in;
+	size_t in_size = in_len;
+	void *out_buf = out;
+	size_t out_size;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	if (!out_len)
+		out_size = 0;
+	else
+		out_size = *out_len;
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_DIGEST_ONESHOT,
+				 &ctrl, ctrl_size, in_buf, in_buf ? in_size : 0,
+				 out_buf, out_len ? &out_size : NULL);
+
+	if (out_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
+		*out_len = out_size;
+
+	if (out_len && !out_buf && rv == CKR_BUFFER_TOO_SMALL)
+		rv = CKR_OK;
+
+	return rv;
+}
+
+CK_RV ck_digest_final(CK_SESSION_HANDLE session,
+			  CK_BYTE_PTR out,
+			  CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *out_buf = out;
+	size_t out_size;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	if (!out_len)
+		out_size = 0;
+	else
+		out_size = *out_len;
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_DIGEST_FINAL,
+				 &ctrl, ctrl_size,
+				 NULL, 0,
+				 out_buf, out_len);
+
+	if (out_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
+		*out_len = out_size;
+
+	return rv;
+}
+
+
+CK_RV ck_encdecrypt_init(CK_SESSION_HANDLE session,
+			 CK_MECHANISM_PTR mechanism,
+			 CK_OBJECT_HANDLE key,
+			 int decrypt)
+{
+	CK_RV rv;
+	struct serializer obj;
+	uint32_t session_handle = session;
+	uint32_t key_handle = key;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+
+	if (!mechanism)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = serialize_ck_mecha_params(&obj, mechanism);
+	if (rv)
+		return rv;
+
+	/* params = [session-handle][key-handle][serialized-mechanism-blob] */
+	ctrl_size = 2 * sizeof(uint32_t) + obj.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), &key_handle, sizeof(uint32_t));
+	memcpy(ctrl + 2 * sizeof(uint32_t), obj.buffer, obj.size);
+
+	rv = ck_invoke_ta(ck_session2sks_ctx(session), decrypt ?
+			  SKS_CMD_DECRYPT_INIT : SKS_CMD_ENCRYPT_INIT,
+			  ctrl, ctrl_size);
+
+bail:
+	release_serial_object(&obj);
+	free(ctrl);
+	return rv;
+}
+
+CK_RV ck_encdecrypt_update(CK_SESSION_HANDLE session,
+			   CK_BYTE_PTR in,
+			   CK_ULONG in_len,
+			   CK_BYTE_PTR out,
+			   CK_ULONG_PTR out_len,
+			   int decrypt)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *in_buf = in;
+	size_t in_size = in_len;
+	void *out_buf = out;
+	size_t out_size;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	if (!out_len)
+		out_size = 0;
+	else
+		out_size = *out_len;
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session), decrypt ?
+				 SKS_CMD_DECRYPT_UPDATE :
+				 SKS_CMD_ENCRYPT_UPDATE,
+				 &ctrl, ctrl_size, in_buf, in_buf ? in_size : 0,
+				 out_buf, out_len ? &out_size : NULL);
+
+	if (out_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
+		*out_len = out_size;
+
+	return rv;
+}
+
+CK_RV ck_encdecrypt_oneshot(CK_SESSION_HANDLE session,
+			    CK_BYTE_PTR in,
+			    CK_ULONG in_len,
+			    CK_BYTE_PTR out,
+			    CK_ULONG_PTR out_len,
+			    int decrypt)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *in_buf = in;
+	size_t in_size = in_len;
+	void *out_buf = out;
+	size_t out_size;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	if (!out_len)
+		out_size = 0;
+	else
+		out_size = *out_len;
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session), decrypt ?
+				 SKS_CMD_DECRYPT_ONESHOT :
+				 SKS_CMD_ENCRYPT_ONESHOT,
+				 &ctrl, ctrl_size, in_buf, in_buf ? in_size : 0,
+				 out_buf, out_len ? &out_size : NULL);
+
+	if (out_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
+		*out_len = out_size;
+
+	if (out_len && !out_buf && rv == CKR_BUFFER_TOO_SMALL)
+		rv = CKR_OK;
+
+	return rv;
+}
+
+CK_RV ck_encdecrypt_final(CK_SESSION_HANDLE session,
+			  CK_BYTE_PTR out,
+			  CK_ULONG_PTR out_len,
+			  int decrypt)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *out_buf = out;
+	size_t out_size;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	if (!out_len)
+		out_size = 0;
+	else
+		out_size = *out_len;
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session), decrypt ?
+				 SKS_CMD_DECRYPT_FINAL : SKS_CMD_ENCRYPT_FINAL,
+				 &ctrl, ctrl_size, NULL, 0,
+				 out_buf, out_len ? &out_size : NULL);
+
+	if (out_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
+		*out_len = out_size;
+
+	return rv;
+}
+
+CK_RV ck_generate_key(CK_SESSION_HANDLE session,
+		      CK_MECHANISM_PTR mechanism,
+		      CK_ATTRIBUTE_PTR attribs,
+		      CK_ULONG count,
+		      CK_OBJECT_HANDLE_PTR handle)
+{
+	CK_RV rv;
+	struct serializer smecha;
+	struct serializer sattr;
+	uint32_t session_handle = session;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+	uint32_t key_handle;
+	size_t key_handle_size = sizeof(key_handle);
+
+	if (!mechanism || !handle)
+		return CKR_ARGUMENTS_BAD;
+
+	if (count && !attribs)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = serialize_ck_mecha_params(&smecha, mechanism);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_attributes(&sattr, attribs, count);
+	if (rv)
+		goto bail;
+
+	/* ctrl = [session-handle][serialized-mecha][serialized-attributes] */
+	ctrl_size = sizeof(uint32_t) + smecha.size + sattr.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), smecha.buffer, smecha.size);
+	memcpy(ctrl + sizeof(uint32_t) + smecha.size, sattr.buffer, sattr.size);
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_GENERATE_SYMM_KEY, ctrl, ctrl_size,
+				 NULL, 0, &key_handle, &key_handle_size);
+	if (rv)
+		goto bail;
+
+	*handle = key_handle;
+
+bail:
+	free(ctrl);
+	release_serial_object(&smecha);
+	release_serial_object(&sattr);
+	return rv;
+}
+
+CK_RV ck_generate_key_pair(CK_SESSION_HANDLE session,
+			   CK_MECHANISM_PTR mechanism,
+			   CK_ATTRIBUTE_PTR pub_attribs,
+			   CK_ULONG pub_count,
+			   CK_ATTRIBUTE_PTR priv_attribs,
+			   CK_ULONG priv_count,
+			   CK_OBJECT_HANDLE_PTR pub_key,
+			   CK_OBJECT_HANDLE_PTR priv_key)
+{
+	CK_RV rv;
+	struct serializer smecha;
+	struct serializer pub_sattr;
+	struct serializer priv_sattr;
+	priv_sattr.buffer = NULL;
+	uint32_t session_handle = session;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+	uint32_t key_handle[2];
+	size_t key_handle_size = sizeof(key_handle);
+
+	if (!mechanism || !pub_key || !priv_key)
+		return CKR_ARGUMENTS_BAD;
+
+
+	rv = serialize_ck_mecha_params(&smecha, mechanism);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_attributes(&pub_sattr, pub_attribs, pub_count);
+	if (rv)
+		goto bail;
+
+	rv = serialize_ck_attributes(&priv_sattr, priv_attribs, priv_count);
+	if (rv)
+		goto bail;
+
+	/* ctrl = [session-handle][serial-mecha][serial-pub][serial-priv] */
+	ctrl_size = sizeof(uint32_t) + smecha.size + pub_sattr.size +
+			priv_sattr.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t),
+		smecha.buffer, smecha.size);
+	memcpy(ctrl + sizeof(uint32_t) + smecha.size,
+		pub_sattr.buffer, pub_sattr.size);
+	memcpy(ctrl + sizeof(uint32_t) + smecha.size + pub_sattr.size,
+		priv_sattr.buffer, priv_sattr.size);
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_GENERATE_KEY_PAIR, ctrl, ctrl_size,
+				 NULL, 0, &key_handle[0], &key_handle_size);
+
+	if (key_handle_size != sizeof(key_handle))
+		rv = CKR_GENERAL_ERROR;
+	if (rv)
+		goto bail;
+
+	*pub_key = key_handle[0];
+	*priv_key = key_handle[1];
+
+bail:
+	free(ctrl);
+	release_serial_object(&smecha);
+	release_serial_object(&pub_sattr);
+	release_serial_object(&priv_sattr);
+	return rv;
+}
+
+CK_RV ck_signverify_init(CK_SESSION_HANDLE session,
+			 CK_MECHANISM_PTR mechanism,
+			 CK_OBJECT_HANDLE key,
+			 int sign)
+{
+	CK_RV rv;
+	struct serializer obj;
+	uint32_t session_handle = session;
+	uint32_t key_handle = key;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+
+	rv = serialize_ck_mecha_params(&obj, mechanism);
+	if (rv)
+		return rv;
+
+	/* params = [session-handle][key-handle][serialized-mechanism-blob] */
+	ctrl_size = 2 * sizeof(uint32_t) + obj.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), &key_handle, sizeof(uint32_t));
+	memcpy(ctrl + 2 * sizeof(uint32_t), obj.buffer, obj.size);
+
+	rv = ck_invoke_ta(ck_session2sks_ctx(session), sign ?
+			  SKS_CMD_SIGN_INIT : SKS_CMD_VERIFY_INIT,
+			  ctrl, ctrl_size);
+
+bail:
+	free(ctrl);
+	release_serial_object(&obj);
+	return rv;
+}
+
+CK_RV ck_signverify_update(CK_SESSION_HANDLE session,
+			   CK_BYTE_PTR in,
+			   CK_ULONG in_len,
+			   int sign)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *in_buf = in;
+	size_t in_size = in_len;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	rv = ck_invoke_ta_in(ck_session2sks_ctx(session), sign ?
+			     SKS_CMD_SIGN_UPDATE : SKS_CMD_VERIFY_UPDATE,
+			     &ctrl, ctrl_size, in_buf, in_size);
+
+	return rv;
+}
+
+CK_RV ck_signverify_oneshot(CK_SESSION_HANDLE session,
+			    CK_BYTE_PTR in,
+			    CK_ULONG in_len,
+			    CK_BYTE_PTR sign_ref,
+			    CK_ULONG_PTR sign_len,
+			    int sign)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *in_buf = in;
+	size_t in_size = in_len;
+	void *sign_buf = sign_ref;
+	size_t sign_size;
+	uint8_t dummy_buf[1];
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	if (!sign_len)
+		sign_size = 0;
+	else
+		sign_size = *sign_len;
+
+	if (!sign_buf) {
+		sign_buf = dummy_buf;
+		sign_size = sizeof(dummy_buf);
+	}
+
+	if (sign)
+		rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+					 SKS_CMD_SIGN_ONESHOT,
+					 &ctrl, ctrl_size, in_buf, in_size,
+					 sign_buf, &sign_size);
+	else
+		rv = ck_invoke_ta_in_in(ck_session2sks_ctx(session),
+					SKS_CMD_VERIFY_ONESHOT,
+					&ctrl, ctrl_size, in_buf, in_size,
+					sign_buf, sign_size);
+
+	if (sign && sign_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
+		*sign_len = sign_size;
+
+	if (sign && !sign_ref && rv == CKR_BUFFER_TOO_SMALL)
+		rv = CKR_OK;
+
+	return rv;
+}
+
+CK_RV ck_signverify_final(CK_SESSION_HANDLE session,
+			  CK_BYTE_PTR sign_ref,
+			  CK_ULONG_PTR sign_len,
+			  int sign)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *sign_buf = sign_ref;
+	size_t sign_size = sign_len ? *sign_len : 0;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	if (sign)
+		rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+					 SKS_CMD_SIGN_FINAL, &ctrl, ctrl_size,
+					 NULL, 0, sign_buf,
+					 sign_buf ? &sign_size : NULL);
+	else
+		rv = ck_invoke_ta_in(ck_session2sks_ctx(session),
+				  SKS_CMD_VERIFY_FINAL,
+				  &ctrl, ctrl_size, sign_buf, sign_size);
+
+	if (sign && sign_len && (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL))
+		*sign_len = sign_size;
+
+	return rv;
+}
+
+CK_RV ck_find_objects_init(CK_SESSION_HANDLE session,
+			   CK_ATTRIBUTE_PTR attribs,
+			   CK_ULONG count)
+{
+	CK_RV rv;
+	uint32_t session_handle = session;
+	struct serializer obj;
+	char *ctrl;
+	size_t ctrl_size;
+
+	rv = serialize_ck_attributes(&obj, attribs, count);
+	if (rv)
+		return rv;
+
+	/* ctrl = [session-handle][headed-serialized-attributes] */
+	ctrl_size = sizeof(uint32_t) + obj.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), obj.buffer, obj.size);
+
+	rv = ck_invoke_ta(ck_session2sks_ctx(session),
+			  SKS_CMD_FIND_OBJECTS_INIT, ctrl, ctrl_size);
+
+bail:
+	release_serial_object(&obj);
+	free(ctrl);
+	return rv;
+}
+
+CK_RV ck_find_objects(CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE_PTR obj,
+			CK_ULONG max_count,
+			CK_ULONG_PTR count)
+
+{
+	CK_RV rv;
+	uint32_t ctrl[1] = { session };
+	uint32_t *handles;
+	size_t handles_size = max_count * sizeof(uint32_t);
+	CK_ULONG n;
+	CK_ULONG last;
+
+	handles = malloc(handles_size);
+	if (!handles)
+		return CKR_HOST_MEMORY;
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_FIND_OBJECTS, ctrl, sizeof(ctrl),
+				 NULL, 0, handles, &handles_size);
+
+	if (rv)
+		goto bail;
+
+	last = handles_size / sizeof(uint32_t);
+	*count = last;
+
+	for (n = 0; n < last; n++) {
+		obj[n] = handles[n];
+	}
+
+bail:
+	free(handles);
+	return rv;
+
+}
+
+CK_RV ck_find_objects_final(CK_SESSION_HANDLE session)
+{
+	CK_RV rv;
+	uint32_t ctrl[1] = { session };
+
+	rv = ck_invoke_ta(ck_session2sks_ctx(session),
+			  SKS_CMD_FIND_OBJECTS_FINAL, ctrl, sizeof(ctrl));
+
+	return rv;
+}
+
+CK_RV ck_derive_key(CK_SESSION_HANDLE session,
+		    CK_MECHANISM_PTR mechanism,
+		    CK_OBJECT_HANDLE parent_handle,
+		    CK_ATTRIBUTE_PTR attribs,
+		    CK_ULONG count,
+		    CK_OBJECT_HANDLE_PTR out_handle)
+{
+	CK_RV rv;
+	struct serializer smecha;
+	struct serializer sattr;
+	uint32_t session_handle = session;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+	uint32_t parent_key_handle = parent_handle;
+	uint32_t key_handle;
+	size_t key_handle_size = sizeof(key_handle);
+
+	rv = serialize_ck_mecha_params(&smecha, mechanism);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_attributes(&sattr, attribs, count);
+	if (rv)
+		goto bail;
+
+	/* ctrl = [session][serialized-mecha][parent-key][key-attributes] */
+	ctrl_size = 2 * sizeof(uint32_t) + smecha.size + sattr.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), smecha.buffer, smecha.size);
+	memcpy(ctrl + sizeof(uint32_t) + smecha.size,
+			&parent_key_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t) + smecha.size + sizeof(uint32_t),
+			sattr.buffer, sattr.size);
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_DERIVE_KEY, ctrl, ctrl_size,
+				 NULL, 0, &key_handle, &key_handle_size);
+	if (rv)
+		goto bail;
+
+	*out_handle = key_handle;
+
+bail:
+	free(ctrl);
+	release_serial_object(&smecha);
+	release_serial_object(&sattr);
+	return rv;
+}
+
+
+CK_RV ck_generate_random(CK_SESSION_HANDLE session,
+				CK_BYTE_PTR out,
+				CK_ULONG len)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *out_buf = out;
+	size_t out_size = len;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_GENERATE_RANDOM,
+				 &ctrl, ctrl_size, NULL, 0,
+				 out_buf, &out_size);
+	return rv;
+}
+
+CK_RV ck_get_object_size(CK_SESSION_HANDLE session,
+			     CK_OBJECT_HANDLE obj,
+			     CK_ULONG_PTR out_size)
+{
+	CK_RV rv;
+	uint32_t ctrl[2] = { (uint32_t)session, (uint32_t)obj };
+	uint32_t obj_size = 0;
+	size_t size = sizeof(obj_size);
+
+	if (!out_size)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				SKS_CMD_GET_OBJECT_SIZE, ctrl,
+				sizeof(ctrl), NULL, 0, &obj_size,
+				&size);
+	if (rv)
+		return rv;
+
+	if (obj_size == SKS_CK_UNAVAILABLE_INFORMATION)
+		*out_size = CK_UNAVAILABLE_INFORMATION;
+	else
+		*out_size = obj_size;
+
+	return rv;
+}
+
+CK_RV ck_get_attribute_value(CK_SESSION_HANDLE session,
+			     CK_OBJECT_HANDLE obj,
+			     CK_ATTRIBUTE_PTR attribs,
+			     CK_ULONG count)
+{
+	CK_RV rv;
+	struct serializer sattr;
+	uint32_t session_handle = session;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+	uint8_t *out = NULL;
+	size_t out_size;
+	uint32_t obj_handle = obj;
+	size_t handle_size = sizeof(obj_handle);
+
+	if (!attribs)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = serialize_ck_attributes(&sattr, attribs, count);
+	if (rv)
+		goto bail;
+
+	/* ctrl = [session][obj-handle][attributes] */
+	ctrl_size = sizeof(uint32_t) + handle_size + sattr.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+	/* out = [attributes] */
+	out_size = sattr.size;
+	out = malloc(out_size);
+	if (!out){
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), &obj_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t) + handle_size, sattr.buffer, sattr.size);
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_GET_ATTRIBUTE_VALUE, ctrl, ctrl_size,
+				 NULL, 0, out, &out_size);
+	if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL)
+		goto bail;
+
+	rv = deserialize_ck_attributes(out, attribs, count);
+
+bail:
+	free(ctrl);
+	release_serial_object(&sattr);
+
+	return rv;
+}
+
+CK_RV ck_import_key(CK_SESSION_HANDLE session,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count,
+			CK_BYTE_PTR keyblob,
+			CK_ULONG_PTR keyblob_length)
+{
+	CK_RV rv;
+	struct serializer obj;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+	void *blob_buf = keyblob;
+	uint32_t session_handle = session;
+
+	if (!attribs || !count || !keyblob_length || !keyblob)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = serialize_ck_attributes(&obj, attribs, count);
+	if (rv)
+		goto bail;
+	/* ctrl = [session-handle][headed-serialized-attributes] */
+	ctrl_size = sizeof(uint32_t) + obj.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), obj.buffer, obj.size);
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_IMPORT_KEY, ctrl, ctrl_size,
+				 NULL, 0, blob_buf, keyblob_length);
+	if (rv)
+		goto bail;
+bail:
+	release_serial_object(&obj);
+	free(ctrl);
+	return rv;
+}
+
+
+CK_RV ck_import_key_pair(CK_SESSION_HANDLE session,
+			   CK_MECHANISM_PTR mechanism,
+			   CK_ATTRIBUTE_PTR pub_attribs,
+			   CK_ULONG pub_count,
+			   CK_ATTRIBUTE_PTR priv_attribs,
+			   CK_ULONG priv_count,
+			   CK_BYTE_PTR keyblob,
+			   CK_ULONG_PTR keyblob_length)
+{
+	CK_RV rv;
+	struct serializer smecha;
+	struct serializer pub_sattr;
+	struct serializer priv_sattr;
+	priv_sattr.buffer = NULL;
+	uint32_t session_handle = session;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+	uint32_t key_handle[2];
+	size_t key_handle_size = sizeof(key_handle);
+
+	if (!mechanism || !keyblob || !keyblob_length)
+		return CKR_ARGUMENTS_BAD;
+
+
+	rv = serialize_ck_mecha_params(&smecha, mechanism);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_attributes(&pub_sattr, pub_attribs, pub_count);
+	if (rv)
+		goto bail;
+
+	rv = serialize_ck_attributes(&priv_sattr, priv_attribs, priv_count);
+	if (rv)
+		goto bail;
+
+	/* ctrl = [session-handle][serial-mecha][serial-pub][serial-priv] */
+	ctrl_size = sizeof(uint32_t) + smecha.size + pub_sattr.size +
+			priv_sattr.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t),
+		smecha.buffer, smecha.size);
+	memcpy(ctrl + sizeof(uint32_t) + smecha.size,
+		pub_sattr.buffer, pub_sattr.size);
+	memcpy(ctrl + sizeof(uint32_t) + smecha.size + pub_sattr.size,
+		priv_sattr.buffer, priv_sattr.size);
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_IMPORT_KEY_PAIR, ctrl, ctrl_size,
+				 NULL, 0, keyblob, keyblob_length);
+
+	if (rv)
+		goto bail;
+
+bail:
+	free(ctrl);
+	release_serial_object(&smecha);
+	release_serial_object(&pub_sattr);
+	release_serial_object(&priv_sattr);
+	return rv;
+}
+
+CK_RV ck_export_key(CK_SESSION_HANDLE session,
+			CK_BYTE_PTR keyblob,
+			CK_ULONG keybloblength,
+			CK_BYTE_PTR pubkey,
+			CK_ULONG_PTR pubkeylength)
+{
+	CK_RV rv;
+	uint32_t ctrl;
+	size_t ctrl_size;
+	void *in_buf = keyblob;
+	size_t in_size = keybloblength;
+	void *out_buf = pubkey;
+	size_t out_size = *pubkeylength;
+
+	if (!keyblob || !pubkey || !pubkeylength)
+		return CKR_ARGUMENTS_BAD;
+
+	/* params = [session-handle] */
+	ctrl = session;
+	ctrl_size = sizeof(ctrl);
+
+	rv = ck_invoke_ta_in_out(ck_session2sks_ctx(session),
+				 SKS_CMD_EXPORT_KEY,
+				 &ctrl, ctrl_size, in_buf, in_size,
+				 out_buf, &out_size);
+
+	if (rv == CKR_OK)
+		*pubkeylength = out_size;
+
+	return rv;
+}
+
+CK_RV ck_utils(CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len)
+{
+	CK_RV rv;
+	struct serializer obj;
+	uint32_t session_handle = session;
+	char *ctrl = NULL;
+	size_t ctrl_size;
+
+	(void)in;
+	(void)in_len;
+	(void)out;
+	(void)out_len;
+
+	if (!mechanism)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = serialize_ck_mecha_params(&obj, mechanism);
+	if (rv)
+		return rv;
+
+	ctrl_size = sizeof(uint32_t) + obj.size;
+	ctrl = malloc(ctrl_size);
+	if (!ctrl) {
+		rv = CKR_HOST_MEMORY;
+		goto bail;
+	}
+
+	memcpy(ctrl, &session_handle, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), obj.buffer, obj.size);
+
+	rv = ck_invoke_ta(ck_session2sks_ctx(session), SKS_CMD_UTILS,
+			  ctrl, ctrl_size);
+
+bail:
+	release_serial_object(&obj);
+	free(ctrl);
+	return rv;
+}
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_processing.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_processing.h
new file mode 100644
index 0000000..467db93
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_processing.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __PKCS11_PROCESSING_H
+#define __PKCS11_PROCESSING_H
+
+#include <pkcs11.h>
+
+CK_RV ck_create_object(CK_SESSION_HANDLE session,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count,
+			CK_OBJECT_HANDLE_PTR phObject);
+
+CK_RV ck_destroy_object(CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE obj);
+
+CK_RV ck_digest_init(CK_SESSION_HANDLE session,
+		     CK_MECHANISM_PTR mechanism);
+
+CK_RV ck_digest_update(CK_SESSION_HANDLE session,
+		      CK_BYTE_PTR in,
+		      CK_ULONG in_len);
+
+CK_RV ck_digest_oneshot(CK_SESSION_HANDLE session,
+			CK_BYTE_PTR in,
+			CK_ULONG in_len,
+			CK_BYTE_PTR out,
+			CK_ULONG_PTR out_len);
+
+CK_RV ck_digest_final(CK_SESSION_HANDLE session,
+		      CK_BYTE_PTR out,
+		      CK_ULONG_PTR out_len);
+
+CK_RV ck_encdecrypt_init(CK_SESSION_HANDLE session,
+			 CK_MECHANISM_PTR mechanism,
+			 CK_OBJECT_HANDLE key,
+			 int decrypt);
+
+CK_RV ck_encdecrypt_update(CK_SESSION_HANDLE session,
+			   CK_BYTE_PTR in,
+			   CK_ULONG in_len,
+			   CK_BYTE_PTR out,
+			   CK_ULONG_PTR out_len,
+			   int decrypt);
+
+CK_RV ck_encdecrypt_oneshot(CK_SESSION_HANDLE session,
+			    CK_BYTE_PTR in,
+			    CK_ULONG in_len,
+			    CK_BYTE_PTR out,
+			    CK_ULONG_PTR out_len,
+			    int decrypt);
+
+CK_RV ck_encdecrypt_final(CK_SESSION_HANDLE session,
+			  CK_BYTE_PTR out,
+			  CK_ULONG_PTR out_len,
+			  int decrypt);
+
+CK_RV ck_generate_key(CK_SESSION_HANDLE session,
+		      CK_MECHANISM_PTR mechanism,
+		      CK_ATTRIBUTE_PTR attribs,
+		      CK_ULONG count,
+		      CK_OBJECT_HANDLE_PTR handle);
+
+CK_RV ck_signverify_init(CK_SESSION_HANDLE session,
+			 CK_MECHANISM_PTR mechanism,
+			 CK_OBJECT_HANDLE key,
+			 int sign);
+
+CK_RV ck_signverify_update(CK_SESSION_HANDLE session,
+			   CK_BYTE_PTR in,
+			   CK_ULONG in_len,
+			   int sign);
+
+CK_RV ck_signverify_oneshot(CK_SESSION_HANDLE session,
+			    CK_BYTE_PTR in,
+			    CK_ULONG in_len,
+			    CK_BYTE_PTR out,
+			    CK_ULONG_PTR out_len,
+			    int sign);
+
+CK_RV ck_signverify_final(CK_SESSION_HANDLE session,
+			  CK_BYTE_PTR out,
+			  CK_ULONG_PTR out_len,
+			  int sign);
+
+CK_RV ck_find_objects_init(CK_SESSION_HANDLE session,
+			   CK_ATTRIBUTE_PTR attribs,
+			   CK_ULONG count);
+
+CK_RV ck_find_objects(CK_SESSION_HANDLE session,
+			CK_OBJECT_HANDLE_PTR obj,
+			CK_ULONG max_count,
+			CK_ULONG_PTR count);
+
+CK_RV ck_find_objects_final(CK_SESSION_HANDLE session);
+
+CK_RV ck_generate_key_pair(CK_SESSION_HANDLE session,
+			   CK_MECHANISM_PTR mechanism,
+			   CK_ATTRIBUTE_PTR pub_attribs,
+			   CK_ULONG pub_count,
+			   CK_ATTRIBUTE_PTR priv_attribs,
+			   CK_ULONG priv_count,
+			   CK_OBJECT_HANDLE_PTR pub_key,
+			   CK_OBJECT_HANDLE_PTR priv_key);
+
+CK_RV ck_derive_key(CK_SESSION_HANDLE session,
+		    CK_MECHANISM_PTR mechanism,
+		    CK_OBJECT_HANDLE parent_handle,
+		    CK_ATTRIBUTE_PTR attribs,
+		    CK_ULONG count,
+		    CK_OBJECT_HANDLE_PTR key_handle);
+
+CK_RV ck_generate_random(CK_SESSION_HANDLE session,
+				CK_BYTE_PTR out,
+				CK_ULONG len);
+
+CK_RV ck_get_object_size(CK_SESSION_HANDLE session,
+			 CK_OBJECT_HANDLE obj,
+			 CK_ULONG_PTR out_size);
+
+CK_RV ck_get_attribute_value(CK_SESSION_HANDLE session,
+			     CK_OBJECT_HANDLE obj,
+			     CK_ATTRIBUTE_PTR attribs,
+			     CK_ULONG count);
+
+CK_RV ck_import_key(CK_SESSION_HANDLE session,
+			CK_ATTRIBUTE_PTR attribs,
+			CK_ULONG count,
+			CK_BYTE_PTR keyblob,
+			CK_ULONG_PTR keyblob_length);
+
+CK_RV ck_import_key_pair(CK_SESSION_HANDLE session,
+			CK_MECHANISM_PTR mechanism,
+			CK_ATTRIBUTE_PTR pub_attribs,
+			CK_ULONG pub_count,
+			CK_ATTRIBUTE_PTR priv_attribs,
+			CK_ULONG priv_count,
+			CK_BYTE_PTR keyblob,
+			CK_ULONG_PTR keyblob_length);
+
+CK_RV ck_export_key(CK_SESSION_HANDLE session,
+			CK_BYTE_PTR keyblob,
+			CK_ULONG keybloblength,
+			CK_BYTE_PTR pubkey,
+			CK_ULONG_PTR pubkeylength);
+
+CK_RV ck_utils(CK_SESSION_HANDLE session,
+		CK_MECHANISM_PTR mechanism,
+		CK_BYTE_PTR in,
+		CK_ULONG in_len,
+		CK_BYTE_PTR out,
+		CK_ULONG_PTR out_len);
+#endif /*__PKCS11_PROCESSING_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_token.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_token.c
new file mode 100644
index 0000000..d0685a5
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_token.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <pkcs11.h>
+#include <sks_ck_debug.h>
+#include <sks_ta.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ck_helpers.h"
+#include "invoke_ta.h"
+#include "local_utils.h"
+#include "pkcs11_token.h"
+
+#define SKS_CRYPTOKI_SLOT_MANUFACTURER		"Linaro"
+
+#define PADDED_STRING_COPY(_dst, _src) \
+	do { \
+		memset((char *)_dst, ' ', sizeof(_dst)); \
+		strncpy((char *)_dst, _src, strlen(_src)); \
+		memset((char *)_dst, '\0', sizeof(_src));   \
+	} while (0)
+
+/**
+ * sks_ck_get_info - implementation of C_GetInfo
+ */
+int sks_ck_get_info(CK_INFO_PTR info)
+{
+	const CK_VERSION ck_version = { 2, 40 };
+	const char manuf_id[] = SKS_CRYPTOKI_SLOT_MANUFACTURER; // TODO slot?
+	const CK_FLAGS flags = 0;	/* must be zero per the PKCS#11 2.40 */
+	const char lib_description[] = "OP-TEE SKS Cryptoki library";
+	const CK_VERSION lib_version = { 0, 0 };
+
+	info->cryptokiVersion = ck_version;
+	PADDED_STRING_COPY(info->manufacturerID, manuf_id);
+	info->flags = flags;
+	PADDED_STRING_COPY(info->libraryDescription, lib_description);
+	info->libraryVersion = lib_version;
+
+	return CKR_OK;
+}
+
+/**
+ * slot_get_info - implementation of C_GetSlotList
+ */
+CK_RV sks_ck_slot_get_list(CK_BBOOL present,
+			   CK_SLOT_ID_PTR slots, CK_ULONG_PTR count)
+{
+	TEEC_SharedMemory *shm;
+	size_t size = 0;
+	CK_RV rv = CKR_GENERAL_ERROR;
+	unsigned int n;
+
+	/* Discard present: all are present */
+	(void)present;
+
+	if (!count)
+		return CKR_ARGUMENTS_BAD;
+
+	if (ck_invoke_ta_in_out(NULL, SKS_CMD_CK_SLOT_LIST, NULL, 0,
+				NULL, 0, NULL, &size) != CKR_BUFFER_TOO_SMALL)
+		return CKR_DEVICE_ERROR;
+
+	if (!slots || *count < (size / sizeof(uint32_t))) {
+		*count = size / sizeof(uint32_t);
+		if (!slots)
+			return CKR_OK;
+
+		return CKR_BUFFER_TOO_SMALL;
+	}
+
+	shm = sks_alloc_shm_out(NULL, size);
+	if (!shm)
+		return CKR_HOST_MEMORY;
+
+	if (ck_invoke_ta_in_out(NULL, SKS_CMD_CK_SLOT_LIST, NULL, 0,
+				NULL, 0, shm, NULL) != CKR_OK) {
+		rv = CKR_DEVICE_ERROR;
+		goto bail;
+	}
+
+	for (n = 0; n < (size / sizeof(uint32_t)); n++)
+		slots[n] = *((uint32_t *)shm->buffer + n);
+
+	*count = size / sizeof(uint32_t);
+	rv = CKR_OK;
+bail:
+	sks_free_shm(shm);
+	return rv;
+
+}
+
+/**
+ * slot_get_info - implementation of C_GetSlotInfo
+ */
+int sks_ck_slot_get_info(CK_SLOT_ID slot, CK_SLOT_INFO_PTR info)
+{
+	uint32_t ctrl[1] = { slot };
+	CK_SLOT_INFO *ck_info = info;
+	struct sks_slot_info sks_info;
+	size_t out_size = sizeof(sks_info);
+	CK_RV rv = CKR_GENERAL_ERROR;
+
+	if (!info)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = ck_invoke_ta_in_out(NULL, SKS_CMD_CK_SLOT_INFO, &ctrl,
+			sizeof(ctrl), NULL, 0, &sks_info, &out_size);
+	if (rv)
+		return rv;
+
+	if (sks2ck_slot_info(ck_info, &sks_info)) {
+		LOG_ERROR("unexpected bad token info structure\n");
+		return CKR_DEVICE_ERROR;
+	}
+
+	return CKR_OK;
+}
+
+/**
+ * slot_get_info - implementation of C_GetTokenInfo
+ */
+CK_RV sks_ck_token_get_info(CK_SLOT_ID slot, CK_TOKEN_INFO_PTR info)
+{
+	uint32_t ctrl[1] = { slot };
+	CK_TOKEN_INFO *ck_info = info;
+	TEEC_SharedMemory *shm;
+	size_t size;
+	CK_RV rv = CKR_GENERAL_ERROR;
+
+	if (!info)
+		return CKR_ARGUMENTS_BAD;
+
+	ctrl[0] = (uint32_t)slot;
+	size = 0;
+	if (ck_invoke_ta_in_out(NULL, SKS_CMD_CK_TOKEN_INFO, ctrl, sizeof(ctrl),
+				NULL, 0, NULL, &size) != CKR_BUFFER_TOO_SMALL)
+		return CKR_DEVICE_ERROR;
+
+	shm = sks_alloc_shm_out(NULL, size);
+	if (!shm)
+		return CKR_HOST_MEMORY;
+
+	ctrl[0] = (uint32_t)slot;
+	rv = ck_invoke_ta_in_out(NULL, SKS_CMD_CK_TOKEN_INFO,
+				 ctrl, sizeof(ctrl), NULL, 0, shm, NULL);
+	if (rv)
+		goto bail;
+
+	if (shm->size < sizeof(struct sks_token_info)) {
+		LOG_ERROR("unexpected bad token info size\n");
+		rv = CKR_DEVICE_ERROR;
+		goto bail;
+	}
+
+	rv = sks2ck_token_info(ck_info, shm->buffer);
+
+bail:
+	sks_free_shm(shm);
+
+	return rv;
+}
+
+/**
+ * sks_ck_init_token - implementation of C_InitToken
+ */
+CK_RV sks_ck_init_token(CK_SLOT_ID slot,
+			CK_UTF8CHAR_PTR pin,
+			CK_ULONG pin_len,
+			CK_UTF8CHAR_PTR label)
+{
+	uint32_t sks_slot = slot;
+	uint32_t sks_pin_len = pin_len;
+	size_t ctrl_size = 2 * sizeof(uint32_t) + sks_pin_len +
+			   32 * sizeof(uint8_t);
+	char *ctrl;
+	size_t offset;
+
+	if (!pin || !label)
+		return CKR_ARGUMENTS_BAD;
+
+	ctrl = malloc(ctrl_size);
+	if (!ctrl)
+		return CKR_HOST_MEMORY;
+
+	memcpy(ctrl, &sks_slot, sizeof(uint32_t));
+	offset = sizeof(uint32_t);
+
+	memcpy(ctrl + offset, &sks_pin_len, sizeof(uint32_t));
+	offset += sizeof(uint32_t);
+
+	memcpy(ctrl + offset, pin, sks_pin_len);
+	offset += sks_pin_len;
+
+	memcpy(ctrl + offset, label, 32 * sizeof(uint8_t));
+
+	return ck_invoke_ta(NULL, SKS_CMD_CK_INIT_TOKEN, ctrl, ctrl_size);
+}
+
+/**
+ * sks_ck_token_mechanism_ids - implementation of C_GetMechanismList
+ */
+CK_RV sks_ck_token_mechanism_ids(CK_SLOT_ID slot,
+				 CK_MECHANISM_TYPE_PTR mechanisms,
+				 CK_ULONG_PTR count)
+{
+	uint32_t ctrl[1] = { slot };
+	size_t outsize = 0;
+	void *outbuf = NULL;
+	CK_RV rv;
+
+	if (!count)
+		return CKR_ARGUMENTS_BAD;
+
+	if (mechanisms) {
+		outsize = *count * sizeof(uint32_t);
+		outbuf = malloc(outsize);
+		if (!outbuf)
+			return CKR_HOST_MEMORY;
+	}
+
+	rv = ck_invoke_ta_in_out(NULL, SKS_CMD_CK_MECHANISM_IDS,
+				 &ctrl, sizeof(ctrl),
+				 NULL, 0, outbuf, &outsize);
+
+	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
+		*count = outsize / sizeof(uint32_t);
+	}
+	if (!mechanisms && rv == CKR_BUFFER_TOO_SMALL) {
+		rv = CKR_OK;
+		goto bail;
+	}
+	if (rv) {
+		goto bail;
+	}
+
+	if (sks2ck_mechanism_type_list(mechanisms, outbuf, *count)) {
+		LOG_ERROR("unexpected bad mechanism_type list\n");
+		rv = CKR_DEVICE_ERROR;
+	}
+
+bail:
+	free(outbuf);
+
+	return rv;
+}
+
+/**
+ * sks_ck_token_mechanism_info - implementation of C_GetMechanismInfo
+ */
+CK_RV sks_ck_token_mechanism_info(CK_SLOT_ID slot,
+				  CK_MECHANISM_TYPE type,
+				  CK_MECHANISM_INFO_PTR info)
+{
+	CK_RV rv;
+	uint32_t ctrl[2];
+	struct sks_mechanism_info outbuf;
+	size_t outsize = sizeof(outbuf);
+
+	if (!info)
+		return CKR_ARGUMENTS_BAD;
+
+	ctrl[0] = (uint32_t)slot;
+	ctrl[1] = ck2sks_mechanism_type(type);
+	if (ctrl[1] == SKS_UNDEFINED_ID) {
+		LOG_DEBUG("mechanism is not support by this library\n");
+		return CKR_MECHANISM_INVALID;
+	}
+
+	/* info is large enought, for sure */
+	rv = ck_invoke_ta_in_out(NULL, SKS_CMD_CK_MECHANISM_INFO,
+				 &ctrl, sizeof(ctrl),
+				 NULL, 0, &outbuf, &outsize);
+	if (rv)
+		return rv;
+
+	if (sks2ck_mechanism_info(info, &outbuf)) {
+		LOG_ERROR("unexpected bad mechanism info structure\n");
+		rv = CKR_DEVICE_ERROR;
+	}
+	return rv;
+}
+
+/**
+ * sks_ck_open_session - implementation of C_OpenSession
+ */
+CK_RV sks_ck_open_session(CK_SLOT_ID slot,
+		          CK_FLAGS flags,
+		          CK_VOID_PTR cookie,
+		          CK_NOTIFY callback,
+		          CK_SESSION_HANDLE_PTR session)
+{
+	uint32_t ctrl[1] = { slot };
+	unsigned long cmd;
+	uint32_t handle;
+	size_t out_sz = sizeof(handle);
+	CK_RV rv;
+
+	if (!session)
+		return CKR_ARGUMENTS_BAD;
+
+	if (cookie || callback) {
+		LOG_ERROR("C_OpenSession does not handle callback yet\n");
+		return CKR_FUNCTION_NOT_SUPPORTED;
+	}
+
+	if (flags & CKF_RW_SESSION)
+		cmd = SKS_CMD_CK_OPEN_RW_SESSION;
+	else
+		cmd = SKS_CMD_CK_OPEN_RO_SESSION;
+
+	rv = ck_invoke_ta_in_out(NULL, cmd, &ctrl, sizeof(ctrl),
+				 NULL, 0, &handle, &out_sz);
+	if (rv)
+		return rv;
+
+	*session = handle;
+
+	return CKR_OK;
+}
+
+CK_RV sks_ck_close_session(CK_SESSION_HANDLE session)
+{
+	uint32_t ctrl[1] = { (uint32_t)session };
+
+	return ck_invoke_ta(NULL, SKS_CMD_CK_CLOSE_SESSION,
+			    &ctrl, sizeof(ctrl));
+}
+
+/**
+ * sks_ck_close_all_sessions - implementation of C_CloseAllSessions
+ */
+CK_RV sks_ck_close_all_sessions(CK_SLOT_ID slot)
+{
+	uint32_t ctrl[1] = { (uint32_t)slot };
+
+	return ck_invoke_ta(NULL, SKS_CMD_CK_CLOSE_ALL_SESSIONS,
+			    &ctrl, sizeof(ctrl));
+}
+
+/**
+ * sks_ck_get_session_info - implementation of C_GetSessionInfo
+ */
+CK_RV sks_ck_get_session_info(CK_SESSION_HANDLE session,
+			      CK_SESSION_INFO_PTR info)
+{
+	uint32_t ctrl[1] = { (uint32_t)session };
+	CK_SESSION_INFO *s_info = info;
+	TEEC_SharedMemory *shm = NULL;
+	CK_RV rv = CKR_GENERAL_ERROR;
+	size_t info_size = sizeof(struct sks_session_info);
+
+	if (!info)
+		return CKR_ARGUMENTS_BAD;
+
+	shm = sks_alloc_shm_out(NULL, info_size);
+	if (!shm)
+		return CKR_HOST_MEMORY;
+
+	rv = ck_invoke_ta_in_out(NULL, SKS_CMD_CK_SESSION_INFO,
+				   &ctrl, sizeof(ctrl),
+				   NULL, 0, shm, NULL);
+	if (rv)
+		goto bail;
+
+	if (shm->size < info_size) {
+		LOG_ERROR("unexpected bad session info size\n");
+		rv = CKR_DEVICE_ERROR;
+		goto bail;
+	}
+
+	rv = sks2ck_session_info(s_info, shm->buffer);
+
+bail:
+	sks_free_shm(shm);
+
+	return rv;
+}
+
+/**
+ * sks_ck_init_pin - implementation of C_InitPIN
+ */
+CK_RV sks_ck_init_pin(CK_SESSION_HANDLE session,
+		      CK_UTF8CHAR_PTR pin, CK_ULONG pin_len)
+{
+	uint32_t sks_session = session;
+	uint32_t sks_pin_len = pin_len;
+	size_t ctrl_size = 2 * sizeof(uint32_t) + sks_pin_len;
+	char *ctrl;
+
+	ctrl = malloc(ctrl_size);
+	if (!ctrl)
+		return CKR_HOST_MEMORY;
+
+	memcpy(ctrl, &sks_session, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), &sks_pin_len, sizeof(uint32_t));
+	memcpy(ctrl + 2 * sizeof(uint32_t), pin, sks_pin_len);
+
+	return ck_invoke_ta(NULL, SKS_CMD_INIT_PIN, ctrl, ctrl_size);
+}
+
+/**
+ * sks_ck_set_pin - implementation of C_SetPIN
+ */
+CK_RV sks_ck_set_pin(CK_SESSION_HANDLE session,
+		     CK_UTF8CHAR_PTR old, CK_ULONG old_len,
+		     CK_UTF8CHAR_PTR new, CK_ULONG new_len)
+{
+	uint32_t sks_session = session;
+	uint32_t sks_old_len = old_len;
+	uint32_t sks_new_len = new_len;
+	size_t ctrl_size = 3 * sizeof(uint32_t) + sks_old_len + sks_new_len;
+	char *ctrl;
+	size_t offset;
+
+	ctrl = malloc(ctrl_size);
+	if (!ctrl)
+		return CKR_HOST_MEMORY;
+
+	memcpy(ctrl, &sks_session, sizeof(uint32_t));
+	offset = sizeof(uint32_t);
+
+	memcpy(ctrl + offset, &sks_old_len, sizeof(uint32_t));
+	offset += sizeof(uint32_t);
+
+	memcpy(ctrl + offset, old, sks_old_len);
+	offset += sks_old_len;
+
+	memcpy(ctrl + offset, &sks_new_len, sizeof(uint32_t));
+	offset += sizeof(uint32_t);
+
+	memcpy(ctrl + offset, new, sks_new_len);
+
+	return ck_invoke_ta(NULL, SKS_CMD_SET_PIN, ctrl, ctrl_size);
+}
+
+/**
+ * sks_ck_login - implementation of C_Login
+ */
+CK_RV sks_ck_login(CK_SESSION_HANDLE session, CK_USER_TYPE user_type,
+		   CK_UTF8CHAR_PTR pin, CK_ULONG pin_len)
+
+{
+	uint32_t sks_session = session;
+	uint32_t sks_user = ck2sks_user_type(user_type);
+	uint32_t sks_pin_len = pin_len;
+	size_t ctrl_size = 3 * sizeof(uint32_t) + sks_pin_len;
+	char *ctrl;
+
+	ctrl = malloc(ctrl_size);
+	if (!ctrl)
+		return CKR_HOST_MEMORY;
+
+	memcpy(ctrl, &sks_session, sizeof(uint32_t));
+	memcpy(ctrl + sizeof(uint32_t), &sks_user, sizeof(uint32_t));
+	memcpy(ctrl + 2 * sizeof(uint32_t), &sks_pin_len, sizeof(uint32_t));
+	memcpy(ctrl + 3 * sizeof(uint32_t), pin, sks_pin_len);
+
+	return ck_invoke_ta(NULL, SKS_CMD_LOGIN, ctrl, ctrl_size);
+}
+
+/**
+ * sks_ck_logout - implementation of C_Logout
+ */
+CK_RV sks_ck_logout(CK_SESSION_HANDLE session)
+{
+	uint32_t sks_session = session;
+	size_t ctrl_size = sizeof(uint32_t);
+	char *ctrl;
+
+	ctrl = malloc(ctrl_size);
+	if (!ctrl)
+		return CKR_HOST_MEMORY;
+
+	memcpy(ctrl, &sks_session, sizeof(uint32_t));
+
+	return ck_invoke_ta(NULL, SKS_CMD_LOGOUT, ctrl, ctrl_size);
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_token.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_token.h
new file mode 100644
index 0000000..56e7a00
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/pkcs11_token.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __PKCS11_TOKEN_H
+#define __PKCS11_TOKEN_H
+
+#include <pkcs11.h>
+
+#include "invoke_ta.h"
+
+int sks_ck_get_info(CK_INFO_PTR info);
+CK_RV sks_ck_slot_get_list(CK_BBOOL present,
+			   CK_SLOT_ID_PTR slots, CK_ULONG_PTR count);
+int sks_ck_slot_get_info(CK_SLOT_ID slot, CK_SLOT_INFO_PTR info);
+CK_RV sks_ck_token_get_info(CK_SLOT_ID slot, CK_TOKEN_INFO_PTR info);
+
+CK_RV sks_ck_token_mechanism_ids(CK_SLOT_ID slot,
+				 CK_MECHANISM_TYPE_PTR mechanisms,
+				 CK_ULONG_PTR count);
+
+CK_RV sks_ck_token_mechanism_info(CK_SLOT_ID slot,
+				  CK_MECHANISM_TYPE type,
+				  CK_MECHANISM_INFO_PTR info);
+
+CK_RV sks_ck_init_token(CK_SLOT_ID slot,
+			CK_UTF8CHAR_PTR pin,
+			CK_ULONG pin_len,
+			CK_UTF8CHAR_PTR label);
+
+CK_RV sks_ck_open_session(CK_SLOT_ID slot,
+		          CK_FLAGS flags,
+		          CK_VOID_PTR cookie,
+		          CK_NOTIFY callback,
+		          CK_SESSION_HANDLE_PTR session);
+CK_RV sks_ck_close_session(CK_SESSION_HANDLE session);
+CK_RV sks_ck_close_all_sessions(CK_SLOT_ID slot);
+CK_RV sks_ck_get_session_info(CK_SESSION_HANDLE session,
+			      CK_SESSION_INFO_PTR info);
+
+CK_RV sks_ck_init_pin(CK_SESSION_HANDLE session,
+		      CK_UTF8CHAR_PTR pin, CK_ULONG pin_len);
+CK_RV sks_ck_set_pin(CK_SESSION_HANDLE session,
+		     CK_UTF8CHAR_PTR old, CK_ULONG old_len,
+		     CK_UTF8CHAR_PTR new, CK_ULONG new_len);
+CK_RV sks_ck_login(CK_SESSION_HANDLE session, CK_USER_TYPE user_type,
+		   CK_UTF8CHAR_PTR pin, CK_ULONG pin_len);
+CK_RV sks_ck_logout(CK_SESSION_HANDLE session);
+
+#endif /*__PKCS11_TOKEN_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.c
new file mode 100644
index 0000000..1b5eeb0
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.c
@@ -0,0 +1,1192 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <pkcs11.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sks_ck_debug.h>
+#include <sks_ta.h>
+
+#include "ck_helpers.h"
+#include "local_utils.h"
+#include "serializer.h"
+#include "serialize_ck.h"
+
+/*
+ * Generic way of serializing CK keys, certif, mechanism parameters, ...
+ * In cryptoki 2.40 parameters are almost all packaged as struture below:
+ */
+struct ck_ref {
+	CK_ULONG id;
+	CK_BYTE_PTR ptr;
+	CK_ULONG len;
+};
+
+#if 0
+/*
+ * Append cryptoki generic buffer reference structure into a sks serial
+ * object.
+ *
+ * ck_ref points to a structure aligned CK reference (attributes or else)
+ */
+static CK_RV serialize_ck_ref(struct serializer *obj, void *ck_ref)
+{
+	struct ck_ref *ref = ck_ref;
+	CK_RV rv;
+
+	rv = serialize_ck_ulong(obj, ref->id);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_ulong(obj, ref->len);
+	if (rv)
+		return rv;
+
+	rv = serialize_buffer(obj, ref->ptr, ref->len);
+	if (rv)
+		return rv;
+
+	obj->item_count++;
+
+	return rv;
+}
+
+/*
+ * ck_ref points to a structure aligned CK reference (attributes or else)
+ *
+ * Same as serialize_ck_ref but reference is a ULONG so the blob size
+ * to be set accoring to the 32bit/64bit configuration of target CK ABI.
+ */
+static CK_RV serialize_ulong_ck_ref(struct serializer *obj, void *ck_ref)
+{
+	struct ck_ref *ref = ck_ref;
+	CK_ULONG ck_value;
+	uint32_t sks_value;
+	CK_RV rv;
+
+	rv = serialize_ck_ulong(obj, ref->id);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_ulong(obj, sizeof(sks_value));
+	if (rv)
+		return rv;
+
+	memcpy(&ck_value, ref->ptr, sizeof(CK_ULONG));
+	sks_value = ck_value;
+
+	rv = serialize_buffer(obj, &sks_value, sizeof(sks_value));
+	if (rv)
+		return rv;
+
+	obj->item_count++;
+
+	return rv;
+}
+#endif
+
+/*
+ * This is for attributes that contains data memory indirections.
+ * In other words, an attributes that defines a list of attributes.
+ * They are identified from the attribute type CKA_...
+ *
+ * @obj - ref used to track the serial object being created
+ * @attribute - pointer to a structure aligned of the CK_ATTRIBUTE struct
+ */
+static CK_RV serialize_indirect_attribute(struct serializer *obj,
+					  CK_ATTRIBUTE_PTR attribute)
+{
+	CK_ATTRIBUTE_PTR attr;
+	CK_ULONG count;
+	CK_RV rv;
+	struct serializer obj2;
+
+	switch (attribute->type) {
+	/* These are serialized each seperately */
+	case CKA_WRAP_TEMPLATE:
+	case CKA_UNWRAP_TEMPLATE:
+		count = attribute->ulValueLen / sizeof(CK_ATTRIBUTE);
+		attr = (CK_ATTRIBUTE_PTR)attribute->pValue;
+		break;
+	default:
+		return CKR_NO_EVENT;
+	}
+
+	/* Create a serialized object for the content */
+	rv = serialize_ck_attributes(&obj2, attr, count);
+	if (rv)
+		return rv;
+
+	/*
+	 * Append the created serialized object into target object:
+	 * [attrib-id][byte-size][attributes-data]
+	 */
+	rv = serialize_32b(obj, ck2sks_attribute_type(attribute->type));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, obj2.size);
+	if (rv)
+		return rv;
+
+	rv = serialize_buffer(obj, obj2.buffer, obj2.size);
+	if (rv)
+		return rv;
+
+	obj->item_count++;
+
+	return rv;
+}
+
+static CK_RV deserialize_indirect_attribute(struct sks_attribute_head *obj,
+					    CK_ATTRIBUTE_PTR attribute)
+{
+	CK_ULONG count;
+	CK_ATTRIBUTE_PTR attr;
+	CK_RV rv;
+
+	switch (attribute->type) {
+	/* These are serialized each seperately */
+	case CKA_WRAP_TEMPLATE:
+	case CKA_UNWRAP_TEMPLATE:
+		count = attribute->ulValueLen / sizeof(CK_ATTRIBUTE);
+		attr = (CK_ATTRIBUTE_PTR)attribute->pValue;
+		break;
+	default:
+		return CKR_GENERAL_ERROR;
+	}
+
+	/*
+	 * deserialize_ck_attributes expects sks_attribute_head,
+	 * not sks_object_head, so we need to correct the pointer
+	 */
+	rv = deserialize_ck_attributes(obj->data, attr, count);
+	return rv;
+}
+
+static int ck_attr_is_ulong(CK_ATTRIBUTE_TYPE attribute_id)
+{
+	return (ck_attr_is_class(attribute_id) ||
+		ck_attr_is_type(attribute_id) ||
+		attribute_id == CKA_VALUE_LEN ||
+		attribute_id == CKA_CERTIFICATE_CATEGORY ||
+		attribute_id == CKA_NAME_HASH_ALGORITHM ||
+		attribute_id == CKA_MODULUS_BITS);
+}
+
+static CK_RV serialize_ck_attribute(struct serializer *obj, CK_ATTRIBUTE *attr)
+{
+	uint32_t sks_id = SKS_UNDEFINED_ID;
+	uint32_t sks_size = 0;
+	uint32_t sks_data32;
+	void *sks_pdata;
+	int sks_pdata_alloced = 0;
+	CK_ULONG ck_ulong = 0;		/* keep compiler happy */
+	CK_RV rv;
+	unsigned int n;
+	unsigned int m;
+
+	/* Expect only those from the identification table */
+	sks_id = ck2sks_attribute_type(attr->type);
+	if (sks_id == SKS_UNDEFINED_ID)
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	if (ck_attr_is_ulong(attr->type)) {
+		/* PKCS#11 CK_ULONG are use */
+		if (attr->ulValueLen != sizeof(CK_ULONG))
+			return CKR_ATTRIBUTE_TYPE_INVALID;
+
+		memcpy(&ck_ulong, attr->pValue, sizeof(ck_ulong));
+	}
+
+	switch (attr->type) {
+	case CKA_CLASS:
+		sks_data32 = ck2sks_object_class(ck_ulong);
+		sks_pdata = &sks_data32;
+		sks_size = sizeof(uint32_t);
+		break;
+
+	case CKA_KEY_TYPE:
+		sks_data32 = ck2sks_key_type(ck_ulong);
+		sks_pdata = &sks_data32;
+		sks_size = sizeof(uint32_t);
+		break;
+
+	case CKA_CERTIFICATE_TYPE:
+		sks_data32 = ck2sks_certificate_type(ck_ulong);
+		sks_pdata = &sks_data32;
+		sks_size = sizeof(uint32_t);
+		break;
+
+	case CKA_WRAP_TEMPLATE:
+	case CKA_UNWRAP_TEMPLATE:
+		return serialize_indirect_attribute(obj, attr);
+
+	case CKA_ALLOWED_MECHANISMS:
+		n = attr->ulValueLen / sizeof(CK_ULONG);
+		sks_size = n * sizeof(uint32_t);
+		sks_pdata = malloc(sks_size);
+		if (!sks_pdata)
+			return CKR_HOST_MEMORY;
+
+		sks_pdata_alloced = 1;
+
+		for (m = 0; m < n; m++) {
+			CK_MECHANISM_TYPE *type = attr->pValue;
+
+			sks_data32 = ck2sks_mechanism_type(type[m]);
+			if (sks_data32 == SKS_UNDEFINED_ID) {
+				free(sks_pdata);
+				return CKR_MECHANISM_INVALID;
+			}
+
+			((uint32_t *)sks_pdata)[m] = sks_data32;
+		}
+		break;
+
+	/* Attributes which data value do not need conversion (aside ulong) */
+	default:
+		if (ck_attr_is_ulong(attr->type)) {
+			sks_data32 = (uint32_t)ck_ulong;
+			sks_pdata = &sks_data32;
+			sks_size = sizeof(uint32_t);
+		} else {
+			sks_pdata = attr->pValue;
+			sks_size = attr->ulValueLen;
+		}
+		break;
+	}
+
+	rv = serialize_32b(obj, sks_id);
+	if (rv)
+		goto bail;
+
+	rv = serialize_32b(obj, sks_size);
+	if (rv)
+		goto bail;
+
+	rv = serialize_buffer(obj, sks_pdata, sks_size);
+	if (rv)
+		goto bail;
+
+	obj->item_count++;
+
+bail:
+	if (sks_pdata_alloced)
+		free(sks_pdata);
+
+	return rv;
+}
+
+#ifdef SKS_WITH_GENERIC_ATTRIBS_IN_HEAD
+static CK_RV get_class(struct serializer *obj, struct ck_ref *ref)
+{
+	CK_ULONG ck_value;
+	uint32_t sks_value;
+
+	if (ref->len != sizeof(ck_value))
+		return CKR_TEMPLATE_INCONSISTENT;
+
+	memcpy(&ck_value, ref->ptr, sizeof(ck_value));
+
+	sks_value = ck2sks_object_class(ck_value);
+
+	if (sks_value == SKS_UNDEFINED_ID)
+		return CKR_TEMPLATE_INCONSISTENT; // TODO: errno
+
+	if (obj->object == SKS_UNDEFINED_ID)
+		obj->object = sks_value;
+
+	if (obj->object != sks_value) {
+		printf("Attribute %s redefined\n", cka2str(ref->id));
+		return CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	return CKR_OK;
+}
+
+static CK_RV get_type(struct serializer *obj, struct ck_ref *ref,
+		      CK_ULONG class)
+{
+	CK_ULONG ck_value;
+	uint32_t sks_value;
+
+	if (ref->len != sizeof(ck_value))
+		return CKR_TEMPLATE_INCONSISTENT;
+
+	memcpy(&ck_value, ref->ptr, sizeof(ck_value));
+
+	sks_value = ck2sks_type_in_class(ck_value, class);
+
+	if (sks_value == SKS_UNDEFINED_ID)
+		return CKR_TEMPLATE_INCONSISTENT; // TODO: errno
+
+	if (obj->type == SKS_UNDEFINED_ID)
+		obj->type = sks_value;
+
+	if (obj->type != sks_value) {
+		printf("Attribute %s redefined\n",
+			cktype2str(ck_value, class));
+		return CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	return CKR_OK;
+}
+
+#ifdef /* SKS_WITH_BOOLPROP_ATTRIBS_IN_HEAD */
+static CK_RV get_boolprop(struct serializer *obj,
+			  struct ck_ref *ref, uint32_t *sanity)
+{
+	int shift;
+	uint32_t mask;
+	uint32_t value;
+	uint32_t *boolprop_ptr;
+	uint32_t *sanity_ptr;
+	CK_BBOOL bbool;
+
+	/* Get the boolean property shift position and value */
+	shift = ck_attr2boolprop_shift(ref->id);
+	if (shift < 0)
+		return CKR_NO_EVENT;
+
+	if (shift >= SKS_MAX_BOOLPROP_SHIFT)
+		return CKR_FUNCTION_FAILED;
+
+	memcpy(&bbool, ref->ptr, sizeof(bbool));
+
+	mask = 1 << (shift % 32);
+	if (bbool == CK_TRUE)
+		value = mask;
+	else
+		value = 0;
+
+	/* Locate the current config value for the boolean property */
+	boolprop_ptr = obj->boolprop + (shift / 32);
+	sanity_ptr = sanity + (shift / 32);
+
+	/* Error if already set to a different boolean value */
+	if ((*sanity_ptr & mask) && value != (*boolprop_ptr & mask)) {
+		printf("Attribute %s redefined\n", cka2str(ref->id));
+		return CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	*sanity_ptr |= mask;
+	if (value)
+		*boolprop_ptr |= mask;
+	else
+		*boolprop_ptr &= ~mask;
+
+	return CKR_OK;
+}
+#endif /* SKS_WITH_BOOLPROP_ATTRIBS_IN_HEAD */
+
+/*
+ * Extract object generic attributes
+ * - all objects must provide at least a class
+ * - some classes expect a type
+ * - some classes can define generic boolean attributes (boolprops)
+ */
+static CK_RV serialize_generic_attributes(struct serializer *obj,
+					  CK_ATTRIBUTE_PTR attributes,
+					  CK_ULONG count)
+{
+	struct ck_ref *ref;
+	size_t n;
+	uint32_t sanity[SKS_MAX_BOOLPROP_ARRAY] = { 0 };
+	CK_RV rv = CKR_OK;
+	CK_ULONG class;
+
+	for (ref = (struct ck_ref *)attributes, n = 0; n < count; n++, ref++) {
+		if (ck_attr_is_class(ref->id))
+			rv = get_class(obj, ref);
+		if (rv)
+			return rv;
+	}
+
+	rv = sks2ck_object_class(&class, obj->object);
+	if (rv)
+		return rv;
+
+	for (ref = (struct ck_ref *)attributes, n = 0; n < count; n++, ref++) {
+		if (ck_attr_is_type(ref->id)) {
+			rv = get_type(obj, ref, class);
+			if (rv)
+				return rv;
+
+			continue;
+		}
+
+#ifdef SKS_WITH_BOOLPROP_ATTRIBS_IN_HEAD
+		if (sks_object_has_boolprop(obj->object) &&
+		    ck_attr2boolprop_shift(ref->id) >= 0) {
+			rv = get_boolprop(obj, ref, sanity);
+			if (rv == CKR_NO_EVENT)
+				rv = CKR_OK;
+
+			if (rv)
+				return rv;
+
+			continue;
+		}
+#endif
+	}
+
+	return rv;
+}
+
+static int ck_attr_is_generic(CK_ULONG attribute_id)
+{
+	return (ck_attr_is_class(attribute_id) ||
+#ifdef SKS_WITH_BOOLPROP_ATTRIBS_IN_HEAD
+		(ck_attr2boolprop_shift(attribute_id) >= 0) ||
+#endif
+		ck_attr_is_type(attribute_id));
+}
+#endif /* SKS_WITH_GENERIC_ATTRIBS_IN_HEAD */
+
+/* CK attribute reference arguments are list of attribute item */
+CK_RV serialize_ck_attributes(struct serializer *obj,
+				CK_ATTRIBUTE_PTR attributes, CK_ULONG count)
+{
+	CK_ATTRIBUTE_PTR cur_attr = attributes;
+	CK_ULONG n = count;
+	CK_RV rv = CKR_OK;
+
+	rv = init_serial_object(obj);
+	if (rv)
+		return rv;
+
+#ifdef SKS_WITH_GENERIC_ATTRIBS_IN_HEAD
+	rv = serialize_generic_attributes(obj, attributes, count);
+	if (rv)
+		goto out;
+#endif
+
+	for (; n; n--, cur_attr++) {
+		CK_ATTRIBUTE attr;
+
+		memcpy(&attr, cur_attr, sizeof(attr));
+
+#ifdef SKS_WITH_GENERIC_ATTRIBS_IN_HEAD
+		if (ck_attr_is_generic(attr.type))
+			continue;
+#endif
+
+		rv = serialize_ck_attribute(obj, &attr);
+		if (rv)
+			goto out;
+	}
+
+out:
+	if (rv)
+		release_serial_object(obj);
+	else
+		finalize_serial_object(obj);
+
+	return rv;
+}
+
+static CK_RV deserialize_ck_attribute(struct sks_attribute_head *in,
+				      CK_ATTRIBUTE_PTR out)
+{
+	CK_ULONG ck_ulong;
+	uint32_t sks_data32 = 0;
+	size_t n;
+	CK_RV rv;
+
+	rv = sks2ck_attribute_type(&(out->type), in->id);
+	if (rv)
+		return rv;
+
+	if (out->ulValueLen < in->size) {
+		out->ulValueLen = in->size;
+		return CKR_OK;
+	}
+
+	if (!out->pValue)
+		return CKR_OK;
+
+	/* Specific ulong encoded as 32bit in SKS TA API */
+	if (ck_attr_is_ulong(out->type)) {
+		if (out->ulValueLen != sizeof(CK_ULONG))
+			return CKR_ATTRIBUTE_TYPE_INVALID;
+
+		memcpy(&sks_data32, in->data, sizeof(uint32_t));
+	}
+
+	switch (out->type) {
+	case CKA_CLASS:
+		rv = sks2ck_object_class(&ck_ulong, sks_data32);
+		if (rv)
+			return rv;
+		memcpy(out->pValue, &ck_ulong, sizeof(CK_ULONG));
+		break;
+
+	case CKA_KEY_TYPE:
+		rv = sks2ck_key_type(&ck_ulong, sks_data32);
+		if (rv)
+			return rv;
+		memcpy(out->pValue, &ck_ulong, sizeof(CK_ULONG));
+		break;
+
+	case CKA_CERTIFICATE_TYPE:
+		rv = sks2ck_certificate_type(&ck_ulong, sks_data32);
+		if (rv)
+			return rv;
+		memcpy(out->pValue, &ck_ulong, sizeof(CK_ULONG));
+		break;
+
+	case CKA_KEY_GEN_MECHANISM:
+		memcpy(&sks_data32, in->data, sizeof(uint32_t));
+		if (sks_data32 == SKS_CK_UNAVAILABLE_INFORMATION)
+			ck_ulong = CK_UNAVAILABLE_INFORMATION;
+		else
+			ck_ulong = sks_data32;
+		memcpy(out->pValue, &ck_ulong, sizeof(CK_ULONG));
+		rv = CKR_OK;
+		break;
+
+	case CKA_WRAP_TEMPLATE:
+	case CKA_UNWRAP_TEMPLATE:
+		rv = deserialize_indirect_attribute(in, out->pValue);
+		break;
+
+	case CKA_ALLOWED_MECHANISMS:
+		n = out->ulValueLen / sizeof(CK_ULONG);
+		rv = sks2ck_mechanism_type_list(out->pValue, in->data, n);
+		break;
+
+	/* Attributes which data value do not need conversion (aside ulong) */
+	default:
+		memcpy(out->pValue, in->data, in->size);
+		rv = CKR_OK;
+		break;
+	}
+
+	return rv;
+}
+
+CK_RV deserialize_ck_attributes(uint8_t *in, CK_ATTRIBUTE_PTR attributes,
+				CK_ULONG count)
+{
+	CK_ATTRIBUTE_PTR cur_attr = attributes;
+	CK_ULONG n;
+	CK_RV rv = CKR_OK;
+	uint8_t *curr_head = in;
+	size_t len;
+
+	curr_head += sizeof(struct sks_object_head);
+
+#ifdef SKS_WITH_GENERIC_ATTRIBS_IN_HEAD
+#error Not supported.
+#endif
+
+	for (n = count; n > 0; n--, cur_attr++, curr_head += len) {
+		struct sks_attribute_head *cli_ref =
+			(struct sks_attribute_head *)(void *)curr_head;
+
+		len = sizeof(*cli_ref);
+		/*
+		 * Can't trust size becuase it was set to reflect
+		 * required buffer.
+		 */
+		if (cur_attr->pValue)
+			len += cli_ref->size;
+
+		rv = deserialize_ck_attribute(cli_ref, cur_attr);
+		if (rv)
+			goto out;
+	}
+
+out:
+	return rv;
+}
+
+/*
+ * Serialization of CK mechanism parameters
+ *
+ * Most mechanism have no parameters.
+ * Some mechanism have a single 32bit parameter.
+ * Some mechanism have a specific parameter structure which may contain
+ * indirected data (data referred by a buffer pointer).
+ *
+ * Below are each structure specific mechanisms parameters.
+ *
+ * Be careful that CK_ULONG based types translate to 32bit sks ulong fields.
+ */
+
+/*
+ * typedef struct CK_AES_CTR_PARAMS {
+ *	CK_ULONG ulCounterBits;
+ *	CK_BYTE cb[16];
+ * } CK_AES_CTR_PARAMS;
+ */
+static CK_RV serialize_mecha_aes_ctr(struct serializer *obj,
+				     CK_MECHANISM_PTR mecha)
+{
+	CK_AES_CTR_PARAMS_PTR param = mecha->pParameter;
+	CK_RV rv;
+	uint32_t size;
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	size = sizeof(uint32_t) + sizeof(param->cb);
+	rv = serialize_32b(obj, size);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_ulong(obj, param->ulCounterBits);
+	if (rv)
+		return rv;
+
+	rv = serialize_buffer(obj, param->cb, sizeof(param->cb));
+	if (rv)
+		return rv;
+
+	return rv;
+}
+
+/*
+ * typedef struct CK_GCM_PARAMS {
+ *	CK_BYTE_PTR       pIv;
+ *	CK_ULONG          ulIvLen;
+ *	CK_ULONG          ulIvBits; -> unused (deprecated?)
+ *	CK_BYTE_PTR       pAAD;
+ *	CK_ULONG          ulAADLen;
+ *	CK_ULONG          ulTagBits;
+ * } CK_GCM_PARAMS;
+ *
+ * Serialized:
+ * [uint32_t mechanism_id]
+ * [uint32_t parameters_byte_size = 3 * 8 + IV size + AAD size]
+ * [uint32_t iv_byte_size]
+ * [uint8_t  iv[iv_byte_size]]
+ * [uint32_t aad_byte_size]
+ * [uint8_t  aad[aad_byte_size]]
+ * [uint32_t tag_bit_size]
+ */
+static CK_RV serialize_mecha_aes_gcm(struct serializer *obj,
+				     CK_MECHANISM_PTR mecha)
+{
+	CK_GCM_PARAMS_PTR param = mecha->pParameter;
+	CK_RV rv;
+	CK_ULONG aad_len;
+
+	/* AAD is not manadatory */
+	if (param->pAAD)
+		aad_len = param->ulAADLen;
+	else
+		aad_len = 0;
+
+	if (!param->pIv)
+		return CKR_MECHANISM_PARAM_INVALID;
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, 3 * sizeof(uint32_t) +
+				param->ulIvLen + aad_len);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_ulong(obj, param->ulIvLen);
+	if (rv)
+		return rv;
+
+	rv = serialize_buffer(obj, param->pIv, param->ulIvLen);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_ulong(obj, aad_len);
+	if (rv)
+		return rv;
+
+	rv = serialize_buffer(obj, param->pAAD, aad_len);
+	if (rv)
+		return rv;
+
+	return serialize_ck_ulong(obj, param->ulTagBits);
+}
+
+/*
+ * typedef struct CK_CCM_PARAMS {
+ *	CK_ULONG          ulDataLen;
+ *	CK_BYTE_PTR       pNonce;
+ *	CK_ULONG          ulNonceLen;
+ *	CK_BYTE_PTR       pAAD;
+ *	CK_ULONG          ulAADLen;
+ *	CK_ULONG          ulMACLen;
+ *} CK_CCM_PARAMS;
+ */
+static CK_RV serialize_mecha_aes_ccm(struct serializer *obj,
+				     CK_MECHANISM_PTR mecha)
+{
+	CK_CCM_PARAMS_PTR param = mecha->pParameter;
+	CK_RV rv;
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, 4 * sizeof(uint32_t) +
+				param->ulNonceLen + param->ulAADLen);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_ulong(obj, param->ulDataLen);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_ulong(obj, param->ulNonceLen);
+	if (rv)
+		return rv;
+
+	rv = serialize_buffer(obj, param->pNonce, param->ulNonceLen);
+	if (rv)
+		return rv;
+
+	rv = serialize_ck_ulong(obj, param->ulAADLen);
+	if (rv)
+		return rv;
+
+	rv = serialize_buffer(obj, param->pAAD, param->ulAADLen);
+	if (rv)
+		return rv;
+
+	return serialize_ck_ulong(obj, param->ulMACLen);
+}
+
+static CK_RV serialize_mecha_aes_iv(struct serializer *obj,
+				    CK_MECHANISM_PTR mecha)
+{
+	uint32_t iv_size = mecha->ulParameterLen;
+	CK_RV rv;
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, iv_size);
+	if (rv)
+		return rv;
+
+	return serialize_buffer(obj, mecha->pParameter, mecha->ulParameterLen);
+}
+
+static CK_RV serialize_mecha_ulong_param(struct serializer *obj,
+					 CK_MECHANISM_PTR mecha)
+{
+	CK_RV rv;
+	uint32_t sks_data;
+	CK_ULONG ck_data;
+
+	memcpy(&ck_data, mecha->pParameter, mecha->ulParameterLen);
+	sks_data = ck_data;
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	return serialize_32b(obj, sks_data);
+}
+
+static CK_RV serialize_mecha_ecdh1_derive_param(struct serializer *obj,
+						CK_MECHANISM_PTR mecha)
+{
+	CK_ECDH1_DERIVE_PARAMS *params = mecha->pParameter;
+	CK_RV rv;
+	size_t params_size = 3 * sizeof(uint32_t) + params->ulSharedDataLen +
+				params->ulPublicDataLen;
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params_size);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, ck2sks_ec_kdf_type(params->kdf));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params->ulSharedDataLen);
+	if (rv)
+		return rv;
+
+	rv = serialize_buffer(obj, params->pSharedData,
+				params->ulSharedDataLen);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params->ulPublicDataLen);
+	if (rv)
+		return rv;
+
+	return serialize_buffer(obj, params->pPublicData,
+				params->ulPublicDataLen);
+}
+
+static CK_RV serialize_mecha_ecdh_aes_key_wrap_param(struct serializer *obj,
+						     CK_MECHANISM_PTR mecha)
+{
+	CK_ECDH_AES_KEY_WRAP_PARAMS *params = mecha->pParameter;
+	CK_RV rv;
+	size_t params_size = 3 * sizeof(uint32_t) + params->ulSharedDataLen;
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params_size);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params->ulAESKeyBits);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, ck2sks_ec_kdf_type(params->kdf));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params->ulSharedDataLen);
+	if (rv)
+		return rv;
+
+	return serialize_buffer(obj, params->pSharedData,
+				params->ulSharedDataLen);
+}
+
+static CK_RV serialize_mecha_rsa_oaep_param(struct serializer *obj,
+					    CK_MECHANISM_PTR mecha)
+{
+	CK_RSA_PKCS_OAEP_PARAMS *params = mecha->pParameter;
+	CK_RV rv;
+	size_t params_size = 4 * sizeof(uint32_t) + params->ulSourceDataLen;
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params_size);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, ck2sks_mechanism_type(params->hashAlg));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, ck2sks_rsa_pkcs_mgf_type(params->mgf));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj,
+			   ck2sks_rsa_pkcs_oaep_source_type(params->source));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params->ulSourceDataLen);
+	if (rv)
+		return rv;
+
+	return serialize_buffer(obj, params->pSourceData,
+				params->ulSourceDataLen);
+}
+
+static CK_RV serialize_mecha_rsa_pss_param(struct serializer *obj,
+					   CK_MECHANISM_PTR mecha)
+{
+	CK_RSA_PKCS_PSS_PARAMS *params = mecha->pParameter;
+	CK_RV rv;
+	size_t params_size = 3 * sizeof(uint32_t);
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params_size);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, ck2sks_mechanism_type(params->hashAlg));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, ck2sks_rsa_pkcs_mgf_type(params->mgf));
+	if (rv)
+		return rv;
+
+	return serialize_32b(obj, params->sLen);
+}
+
+static CK_RV serialize_mecha_rsa_aes_key_wrap_param(struct serializer *obj,
+						    CK_MECHANISM_PTR mecha)
+{
+	CK_RSA_AES_KEY_WRAP_PARAMS *params = mecha->pParameter;
+	CK_RSA_PKCS_OAEP_PARAMS *oaep_p = params->pOAEPParams;
+	CK_RV rv;
+	size_t params_size = 5 * sizeof(uint32_t) + params->pOAEPParams->ulSourceDataLen;
+
+	rv = serialize_32b(obj, obj->type);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params_size);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, params->ulAESKeyBits);
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, ck2sks_mechanism_type(oaep_p->hashAlg));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, ck2sks_rsa_pkcs_mgf_type(oaep_p->mgf));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj,
+			   ck2sks_rsa_pkcs_oaep_source_type(oaep_p->source));
+	if (rv)
+		return rv;
+
+	rv = serialize_32b(obj, oaep_p->ulSourceDataLen);
+	if (rv)
+		return rv;
+
+	return serialize_buffer(obj, oaep_p->pSourceData,
+				oaep_p->ulSourceDataLen);
+}
+
+/**
+ * serialize_ck_mecha_params - serialize a mechanism type & params
+ *
+ * @obj - serializer used to track the serialization
+ * @mechanism - pointer of the in structure aligned CK_MECHANISM.
+ *
+ * Serialized content:
+ *	[sks-mechanism-type][sks-mechanism-param-blob]
+ *
+ * [sks-mechanism-param-blob] depends on mechanism type ID, see
+ * serialize_mecha_XXX().
+ */
+CK_RV serialize_ck_mecha_params(struct serializer *obj,
+				CK_MECHANISM_PTR mechanism)
+{
+	CK_MECHANISM mecha;
+	CK_RV rv;
+
+	memset(obj, 0, sizeof(*obj));
+
+	obj->object = SKS_CKO_MECHANISM;
+
+	memcpy(&mecha, mechanism, sizeof(mecha));
+	obj->type = ck2sks_mechanism_type(mecha.mechanism);
+	if (obj->type == SKS_UNDEFINED_ID)
+		return CKR_MECHANISM_INVALID;
+
+	switch (mecha.mechanism) {
+	case CKM_GENERIC_SECRET_KEY_GEN:
+	case CKM_AES_KEY_GEN:
+	case CKM_AES_ECB:
+	case CKM_AES_CMAC:
+	case CKM_MD5_HMAC:
+	case CKM_SHA_1_HMAC:
+	case CKM_SHA224_HMAC:
+	case CKM_SHA256_HMAC:
+	case CKM_SHA384_HMAC:
+	case CKM_SHA512_HMAC:
+	case CKM_AES_XCBC_MAC:
+	case CKM_AES_XCBC_MAC_96:
+	case CKM_EC_KEY_PAIR_GEN:
+	case CKM_RSA_PKCS_KEY_PAIR_GEN:
+	case CKM_ECDSA:
+	case CKM_ECDSA_SHA1:
+	case CKM_ECDSA_SHA224:
+	case CKM_ECDSA_SHA256:
+	case CKM_ECDSA_SHA384:
+	case CKM_ECDSA_SHA512:
+	case CKM_RSA_PKCS:
+	case CKM_RSA_9796:
+	case CKM_RSA_X_509:
+	case CKM_SHA1_RSA_PKCS:
+	case CKM_SHA256_RSA_PKCS:
+	case CKM_SHA384_RSA_PKCS:
+	case CKM_SHA512_RSA_PKCS:
+	case CKM_SHA224_RSA_PKCS:
+	case CKM_DES_KEY_GEN:
+	case CKM_MTK_HSM_AES_ECB:
+	case CKM_MTK_HSM_AES_CMAC:
+	case CKM_MTK_HSM_SHA256_HMAC:
+	case CKM_MTK_HSM_SHA384_HMAC:
+	case CKM_MTK_HSM_ECDSA:
+	case CKM_MTK_HSM_ECDSA_SHA1:
+	case CKM_MTK_HSM_ECDSA_SHA224:
+	case CKM_MTK_HSM_ECDSA_SHA256:
+	case CKM_MTK_HSM_ECDSA_SHA384:
+	case CKM_MTK_HSM_ECDSA_SHA512:
+	case CKM_MTK_HSM_SHA1:
+	case CKM_MTK_HSM_SHA224:
+	case CKM_MTK_HSM_SHA256:
+	case CKM_MTK_HSM_SHA384:
+	case CKM_MTK_HSM_SHA512:
+	case CKM_MTK_HSM_AES_KEY_GEN:
+	case CKM_MTK_HSM_EC_KEY_PAIR_GEN:
+	case CKM_MTK_HSM_EC_KEY_PAIR_IMPORT:
+	case CKM_MTK_HSM_DUMP_LOG:
+		/* No parameter expected, size shall be 0 */
+		if (mechanism->ulParameterLen)
+			return CKR_MECHANISM_PARAM_INVALID;
+
+		rv = serialize_32b(obj, obj->type);
+		if (rv)
+			return rv;
+
+		return serialize_32b(obj, 0);
+
+	case CKM_AES_CMAC_GENERAL:
+		return serialize_mecha_ulong_param(obj, &mecha);
+
+	case CKM_AES_CBC:
+	case CKM_AES_CBC_PAD:
+	case CKM_AES_CTS:
+	case CKM_MTK_HSM_AES_CBC:
+		return serialize_mecha_aes_iv(obj, &mecha);
+
+	case CKM_AES_CTR:
+	case CKM_MTK_HSM_AES_CTR:
+		return serialize_mecha_aes_ctr(obj, &mecha);
+
+	case CKM_AES_CCM:
+		return serialize_mecha_aes_ccm(obj, &mecha);
+
+	case CKM_AES_GCM:
+	case CKM_MTK_HSM_AES_GCM:
+		return serialize_mecha_aes_gcm(obj, &mecha);
+
+	case CKM_ECDH1_DERIVE:
+	case CKM_ECDH1_COFACTOR_DERIVE:
+		return serialize_mecha_ecdh1_derive_param(obj, &mecha);
+
+	case CKM_ECDH_AES_KEY_WRAP:
+		return serialize_mecha_ecdh_aes_key_wrap_param(obj, &mecha);
+
+	case CKM_RSA_PKCS_OAEP:
+		return serialize_mecha_rsa_oaep_param(obj, &mecha);
+
+	case CKM_RSA_PKCS_PSS:
+	case CKM_SHA1_RSA_PKCS_PSS:
+	case CKM_SHA256_RSA_PKCS_PSS:
+	case CKM_SHA384_RSA_PKCS_PSS:
+	case CKM_SHA512_RSA_PKCS_PSS:
+	case CKM_SHA224_RSA_PKCS_PSS:
+		return serialize_mecha_rsa_pss_param(obj, &mecha);
+
+	case CKM_RSA_AES_KEY_WRAP:
+		return serialize_mecha_rsa_aes_key_wrap_param(obj, &mecha);
+
+	default:
+		return CKR_MECHANISM_INVALID;
+	}
+}
+
+/*
+ * Debug: dump CK attribute array to output trace
+ */
+
+static CK_RV trace_attributes(char *prefix, void *src, void *end)
+{
+	size_t next = 0;
+	char *prefix2;
+	size_t prefix_len = strlen(prefix);
+	char *cur = src;
+
+	/* append 4 spaces to the prefix */
+	prefix2 = malloc(prefix_len + 1 + 4) ;
+	memcpy(prefix2, prefix, prefix_len + 1);
+	memset(prefix2 + prefix_len, ' ', 4);
+	*(prefix2 + prefix_len + 1 + 4) = '\0';
+
+	for (; cur < (char *)end; cur += next) {
+		struct sks_attribute_head ref;
+
+		memcpy(&ref, cur, sizeof(ref));
+		next = sizeof(ref) + ref.size;
+
+		LOG_DEBUG("%s attr 0x%" PRIx32 " (%" PRIu32" byte) : %02x %02x %02x %02x ...\n",
+			prefix, ref.id, ref.size,
+			*((char *)cur + sizeof(ref) + 0),
+			*((char *)cur + sizeof(ref) + 1),
+			*((char *)cur + sizeof(ref) + 2),
+			*((char *)cur + sizeof(ref) + 3));
+
+		switch (ref.id) {
+		case SKS_CKA_WRAP_TEMPLATE:
+		case SKS_CKA_UNWRAP_TEMPLATE:
+			serial_trace_attributes_from_head(prefix2,
+							  cur + sizeof(ref));
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* sanity */
+	if (cur != (char *)end) {
+		LOG_ERROR("unexpected none alignement\n");
+	}
+
+	free(prefix2);
+	return CKR_OK;
+}
+
+CK_RV serial_trace_attributes_from_head(char *prefix, void *ref)
+{
+	struct sks_object_head head;
+	char *pre;
+	CK_RV rv;
+
+	memcpy(&head, ref, sizeof(head));
+
+	pre = calloc(1, prefix ? strlen(prefix) + 2 : 2) ;
+	if (!pre)
+		return CKR_HOST_MEMORY;
+	if (prefix)
+		memcpy(pre, prefix, strlen(prefix));
+
+	LOG_INFO("%s,--- (serial object) Attributes list --------\n", pre);
+	LOG_INFO("%s| %" PRIu32 " item(s) - %" PRIu32 " bytes\n", pre,
+		 head.attrs_count, head.attrs_size);
+
+	pre[prefix ? strlen(prefix) + 1 : 0] = '|';
+
+	rv = trace_attributes(pre, (char *)ref + sizeof(head),
+			      (char *)ref + sizeof(head) + head.attrs_size);
+	if (rv)
+		goto bail;
+
+	LOG_INFO("%s`-----------------------\n", prefix ? prefix : "");
+
+bail:
+	free(pre);
+	return rv;
+}
+
+CK_RV serial_trace_attributes(char *prefix, struct serializer *obj)
+{
+	return serial_trace_attributes_from_head(prefix, obj->buffer);
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.h
new file mode 100644
index 0000000..09c2b61
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serialize_ck.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SERIALIZE_CK_H
+#define __SERIALIZE_CK_H
+
+#include <pkcs11.h>
+#include "serializer.h"
+
+/* Create (and allocate) a serial object for CK_ATTRIBUTE array */
+CK_RV serialize_ck_attributes(struct serializer *obj,
+				CK_ATTRIBUTE_PTR attributes, CK_ULONG count);
+
+/* Convert SKS attributes back to CK_ATTRIBUTE array */
+CK_RV deserialize_ck_attributes(uint8_t *in,
+				CK_ATTRIBUTE_PTR attributes, CK_ULONG count);
+
+/* Create (and allocate) a serial object for CK_MECHANISM array */
+CK_RV serialize_ck_mecha_params(struct serializer *obj,
+				CK_MECHANISM_PTR mechanisms);
+
+/* Log content of a serialized object */
+CK_RV serial_trace_attributes(char *prefix, struct serializer *obj);
+CK_RV serial_trace_attributes_from_head(char *prefix, void *ref);
+
+#endif /*__SERIALIZE_CK_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serializer.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serializer.c
new file mode 100644
index 0000000..eeaefda
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serializer.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sks_ta.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ck_helpers.h"
+#include "local_utils.h"
+#include "serializer.h"
+
+CK_RV init_serial_object(struct serializer *obj)
+{
+	struct sks_object_head head;
+
+	memset(obj, 0, sizeof(*obj));
+	obj->object = SKS_UNDEFINED_ID;
+	obj->type = SKS_UNDEFINED_ID;
+
+	/* Init head to all ones, will be set at finalize_serial_object */
+	memset(&head, 0xFF, sizeof(head));
+	return serialize_buffer(obj, &head, sizeof(head));
+}
+
+void finalize_serial_object(struct serializer *obj)
+{
+	struct sks_object_head head;
+
+	memset(&head, 0xFF, sizeof(head));
+
+#ifdef SKS_WITH_GENERIC_ATTRIBS_IN_HEAD
+fsdf fsd fsdf sdf
+	head.object = obj->object;
+	head.type = obj->type;
+#ifdef SKS_WITH_BOOLPROP_ATTRIBS_IN_HEAD
+	head.boolpropl = *((uint32_t *)obj->boolprop);
+	head.boolproph = *((uint32_t *)obj->boolprop + 1);
+#endif
+#endif
+	head.attrs_size = obj->size - sizeof(head);
+	head.attrs_count = obj->item_count;
+	memcpy(obj->buffer, &head, sizeof(head));
+}
+
+void release_serial_object(struct serializer *obj)
+{
+	free(obj->buffer);
+	obj->buffer = NULL;
+}
+
+/**
+ * serialize - append data in a serialized buffer
+ *
+ * Serialize data in provided buffer.
+ * Ensure 64byte alignement of appended data in the buffer.
+ */
+static CK_RV serialize(char **bstart, size_t *blen, void *data, size_t len)
+{
+	char *buf;
+	size_t nlen;
+
+	nlen = *blen + len;
+
+	buf = realloc(*bstart, nlen);
+	if (!buf)
+		return CKR_HOST_MEMORY;
+
+	memcpy(buf + *blen, data, len);
+
+	*blen = nlen;
+	*bstart = buf;
+
+	return CKR_OK;
+}
+
+CK_RV serialize_buffer(struct serializer *obj, void *data, size_t size)
+{
+	return serialize(&obj->buffer, &obj->size, data, size);
+}
+
+CK_RV serialize_32b(struct serializer *obj, uint32_t data)
+{
+	uint32_t data32 = data;
+
+	return serialize_buffer(obj, &data32, sizeof(uint32_t));
+}
+
+CK_RV serialize_ck_ulong(struct serializer *obj, CK_ULONG data)
+{
+	uint32_t data32 = data;
+
+	return serialize_buffer(obj, &data32, sizeof(data32));
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serializer.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serializer.h
new file mode 100644
index 0000000..2cdd7ce
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/host/src/serializer.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SERIALIZER_H
+#define __SERIALIZER_H
+
+#include <pkcs11.h>
+#include <sks_ta.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define SKS_MAX_BOOLPROP_SHIFT	64
+#define SKS_MAX_BOOLPROP_ARRAY	(SKS_MAX_BOOLPROP_SHIFT / sizeof(uint32_t))
+
+/*
+ * Struct used to create the buffer storing the serialized data.
+ * Contains some fields to help parsing content (type/boolprops).
+ */
+struct serializer {
+	char *buffer;		/* serial buffer base address */
+	size_t size;		/* serial buffer current byte size */
+	size_t item_count;	/* number of items in entry table */
+	uint32_t object;
+	uint32_t type;
+	uint32_t boolprop[SKS_MAX_BOOLPROP_ARRAY];
+};
+
+size_t get_serial_object_size(struct serializer *obj);
+
+/* Init/finalize/release a serializer object */
+CK_RV init_serial_object(struct serializer *obj);
+void finalize_serial_object(struct serializer *obj);
+void release_serial_object(struct serializer *obj);
+
+CK_RV serialize_buffer(struct serializer *obj, void *data, size_t size);
+CK_RV serialize_32b(struct serializer *obj, uint32_t data);
+CK_RV serialize_ck_ulong(struct serializer *obj, CK_ULONG data);
+
+/*
+ * Tools on already serialized object: input referenc is the serial object
+ * head address.
+ */
+
+/* Return the size of the serial blob head or 0 on error */
+size_t sizeof_serial_head(void *ref);
+
+/* Return the size of a serial object (head + attributes size) */
+size_t get_serial_size(void *ref);
+
+/* Return the class of the object or the invalid ID if not found */
+uint32_t serial_get_class(void *ref);
+
+/* Return the type of the object or the invalid ID if not found */
+uint32_t serial_get_type(void *ref);
+
+/* Get the location of target the attribute data and size */
+CK_RV serial_get_attribute_ptr(void *ref, uint32_t attribute,
+			       void **attr, size_t *attr_size);
+
+/* Get target the attribute data content */
+CK_RV serial_get_attribute(void *ref, uint32_t attribute,
+			   void *attr, size_t *attr_size);
+
+/*
+ * Same serial_get_attributes() in case an attribute is defined several
+ * times in the object (i.e several string identifiers for a single object)
+ * TODO.
+ */
+CK_RV serial_get_attribute_multi(void *ref, uint32_t attribute,
+			   void *attr, size_t *attr_size);
+
+#endif /*__SERIALIZER_H*/
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/Makefile b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/Makefile
new file mode 100644
index 0000000..98a546f
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/Makefile
@@ -0,0 +1,22 @@
+# The UUID for the Trusted Application
+BINARY=fd02c9da-306c-48c7-a49c-bbd827ae86ee
+
+ifdef TA_CROSS_COMPILE
+CROSS_COMPILE ?= $(TA_CROSS_COMPILE)
+endif
+export CROSS_COMPILE
+
+CFG_TEE_TA_LOG_LEVEL ?= 2
+CPPFLAGS += -DCFG_TEE_TA_LOG_LEVEL=$(CFG_TEE_TA_LOG_LEVEL)
+
+-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk
+
+ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), )
+clean:
+	@echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA'
+	@echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)'
+endif
+
+.PHONY: install
+install:
+	cp $(BINARY).ta $(TADIR)/
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/hsm_job.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/hsm_job.h
new file mode 100644
index 0000000..9298849
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/hsm_job.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: BSD-2-Clause

+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+#ifndef __HSM_JOB_H__

+#define __HSM_JOB_H__

+

+typedef struct job_sturct_t

+{

+	uint32_t job_id;

+	uint32_t inputPtr;

+	uint32_t inputLength;

+	uint32_t secondaryInputPtr;

+	uint32_t secondaryInputLength;

+	uint32_t tertiaryInputPtr;

+	uint32_t tertiaryInputLength;

+	uint32_t outputPtr;

+	uint32_t outputLength;

+	uint32_t secondaryOutputPtr;

+	uint32_t secondaryOutputLength;

+	uint32_t cryptoKeyId;

+	uint32_t retValPtr;

+	uint16_t event_id;

+	uint16_t priority;

+	uint16_t keyLength;

+	uint8_t  service;

+	uint8_t  family;

+	uint8_t  mode;

+	uint8_t  operation_mode;

+

+} job_struct;

+

+#endif //__HSM_JOB_H__

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/hsm_mbox_if.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/hsm_mbox_if.h
new file mode 100644
index 0000000..6585f86
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/hsm_mbox_if.h
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef __HSM_MBOX_IF_H__
+#define __HSM_MBOX_IF_H__
+
+#include <stdint.h>
+#include "hsm_job.h"
+
+#define HSM_IF_OK               (0)
+#define HSM_IF_ERR_FAIL        (-1)
+#define HSM_IF_ERR_TX_TIMEOUT  (-2)
+
+#define FALSE   0
+#define TRUE    1
+
+#define PTA_MBOX_UUID {0x598e9628, 0xf233, 0x4c83, {0x8d, 0x4c, 0xbd, 0x2f, 0x0a, 0xd4, 0xb2, 0xe4}}
+
+#define PTA_CMD_HSM_GEN_KEY_PAIR        1
+#define PTA_CMD_HSM_GEN_SYMM_KEY        2
+#define PTA_CMD_HSM_GET_KEY_BLOB        3
+#define PTA_CMD_HSM_GET_KEY_TABLE       4
+#define PTA_CMD_HSM_REBUILD_KEY_TABLE   5
+#define PTA_CMD_HSM_REBUILD_KEY_BLOB    6
+#define PTA_CMD_HSM_IMPORT_KEY          7
+#define PTA_CMD_HSM_EXPORT_KEY          8
+#define PTA_CMD_HSM_SEND_JOB            9
+#define PTA_CMD_HSM_DUMP_LOG           10
+#define PTA_CMD_HSM_DELETE_KEY         11
+
+#endif //__HSM_MBOX_IF_H__
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/mtk_crypto.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/mtk_crypto.h
new file mode 100644
index 0000000..c541a63
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/mtk_crypto.h
@@ -0,0 +1,244 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef _TEST_CRYPTO_H_
+#define _TEST_CRYPTO_H_
+
+#include <stdint.h>
+
+#define HSM_TA_DEBUG 1
+
+#define COMMANDID_TEST_0    (0x56)
+#define COMMANDID_TEST_1    (0x78)
+#define COMMANDID_SKS_TA    (0xDD)
+
+enum Crypto_OperationModeType
+{
+	CRYPTO_OPERATIONMODE_INVALID        = 0x00,
+	CRYPTO_OPERATIONMODE_START          = 0x01,
+	CRYPTO_OPERATIONMODE_UPDATE         = 0x02,
+	CRYPTO_OPERATIONMODE_STREAMSTART    = 0x03,
+	CRYPTO_OPERATIONMODE_FINISH         = 0x04,
+	CRYPTO_OPERATIONMODE_SINGLECALL     = 0x05,
+};
+
+enum Crypto_ServiceInfoType
+{
+	CRYPTO_HASH                     = 0x00,
+	CRYPTO_MACGENERATE              = 0x01,
+	CRYPTO_MACVERIFY                = 0x02,
+	CRYPTO_ENCRYPT                  = 0x03,
+	CRYPTO_DECRYPT                  = 0x04,
+
+//    CRYPTO_AEADENCRYPT              = 0x05,
+//    CRYPTO_AEADDECRYPT              = 0x06,
+
+	CRYPTO_SIGNATUREGENERATE        = 0x07,
+	CRYPTO_SIGNATUREVERIFY          = 0x08,
+	CRYPTO_SECCOUNTERINCREMENT      = 0x09,
+	CRYPTO_SECCOUNTERREAD           = 0x0A,
+	CRYPTO_RANDOMGENERATE           = 0x0B,
+};
+
+enum Crypto_VerifyResultType
+{
+	CRYPTO_E_VER_OK     = 0x00,
+	CRYPTO_E_VER_NOT_OK = 0x01,
+};
+
+enum Crypto_JobStateType
+{
+	CRYPTO_JOBSTATE_IDLE   = 0x00,
+	CRYPTO_JOBSTATE_ACTIVE = 0x01,
+};
+
+struct Crypto_JobPrimitiveInputOutputType
+{
+	/*const*/ uint8_t               *inputPtr;
+	uint32_t                        inputLength;
+	/*const*/ uint8_t               *secondaryInputPtr;
+	uint32_t                        secondaryInputLength;
+	/*const*/ uint8_t               *tertiaryInputPtr;
+	uint32_t                        tertiaryInputLength;
+	uint8_t                         *outputPtr;
+	uint32_t                        *outputLengthPtr;
+	uint8_t                         *secondaryOutputPtr;
+	uint32_t                        *secondaryOutputLengthPtr;
+	uint64_t                        input64;
+	enum Crypto_VerifyResultType    *verifyPtr;  // Ptr to
+	uint64_t                        *output64Ptr;
+	enum Crypto_OperationModeType   mode;
+};
+
+enum Crypto_AlgorithmFamilyType
+{
+	CRYPTO_ALGOFAM_NOT_SET          = 0x00,
+	CRYPTO_ALGOFAM_SHA1             = 0x01,
+	CRYPTO_ALGOFAM_SHA2_224         = 0x02,
+	CRYPTO_ALGOFAM_SHA2_256         = 0x03,
+	CRYPTO_ALGOFAM_SHA2_384         = 0x04,
+	CRYPTO_ALGOFAM_SHA2_512         = 0x05,
+	CRYPTO_ALGOFAM_AES              = 0x14,
+	CRYPTO_ALGOFAM_ECCNIST          = 0x19,
+	CRYPTO_ALGOFAM_SECURECOUNTER    = 0x1A,
+	CRYPTO_ALGOFAM_RNG              = 0x1B,
+};
+
+enum Crypto_AlgorithmModeType
+{
+	CRYPTO_ALGOMODE_NOT_SET             = 0x00,
+	CRYPTO_ALGOMODE_ECB                 = 0x01,
+	CRYPTO_ALGOMODE_CBC                 = 0x02,
+	CRYPTO_ALGOMODE_CTR                 = 0x05,
+	CRYPTO_ALGOMODE_GCM                 = 0x06,
+	CRYPTO_ALGOMODE_XTS                 = 0x07,
+	CRYPTO_ALGOMODE_HMAC                = 0x0F,
+	CRYPTO_ALGOMODE_CMAC                = 0x10,
+	CRYPTO_ALGOMODE_GMAC                = 0x11,
+	CRYPTO_ALGOMODE_CTRDRBG             = 0x12,
+};
+
+struct Crypto_AlgorithmInfoType
+{
+	enum Crypto_AlgorithmFamilyType                 family;
+	enum Crypto_AlgorithmFamilyType                 secondaryFamily;
+	uint32_t                                        keyLength;
+	enum Crypto_AlgorithmModeType                   mode;
+};
+
+struct Crypto_PrimitiveInfoType
+{
+	/*const*/ uint32_t                              resultLength;
+	/*const*/ enum Crypto_ServiceInfoType           service;
+	/*const*/ struct Crypto_AlgorithmInfoType       algorithm;
+};
+
+enum Crypto_ProcessingType
+{
+	CRYPTO_PROCESSING_ASYNC = 0x00,
+	CRYPTO_PROCESSING_SYNC  = 0x01,
+};
+
+struct Crypto_JobPrimitiveInfoType
+{
+	/*const*/ uint32_t                              callbackId;
+	/*const*/ struct Crypto_PrimitiveInfoType       *primitiveInfo;
+	/*const*/ uint32_t                              secureCounterId;
+	/*const*/ uint32_t                              cryIfKeyId;
+	/*const*/ enum Crypto_ProcessingType            processingType;
+	/*const*/ uint8_t                               callbackUpdateNotification; // A boolean value
+};
+
+struct Crypto_JobInfoType
+{
+	/*const*/ uint32_t                              jobId;
+	/*const*/ uint32_t                              jobPriority;
+};
+
+struct Crypto_JobType
+{
+	/*const*/ uint32_t                              jobId;
+	enum Crypto_JobStateType                        jobState;
+	struct Crypto_JobPrimitiveInputOutputType       jobPrimitiveInputOutput;
+	/*const*/ struct Crypto_JobPrimitiveInfoType    *jobPrimitiveInfo;
+	/*const*/ struct Crypto_JobInfoType             *jobInfo;
+	uint32_t                                        cryptoKeyId;
+};
+
+typedef enum Std_ReturnType_t
+{
+	E_OK_1                          = 0x00,
+	E_NOT_OK_1                      = 0x01,
+	CRYPTO_E_BUSY                   = 0x02,
+	CRYPTO_E_SMALL_BUFFER           = 0x03,
+	CRYPTO_E_ENTROPY_EXHAUSTION     = 0x04,
+	CRYPTO_E_QUEUE_FULL             = 0x05,
+	CRYPTO_E_KEY_READ_FAIL          = 0x06,
+	CRYPTO_E_KEY_WRITE_FAIL         = 0x07,
+	CRYPTO_E_KEY_NOT_AVAILABLE      = 0x08,
+	CRYPTO_E_KEY_NOT_VALID          = 0x09,
+	CRYPTO_E_KEY_SIZE_MISMATCH      = 0x0A,
+	CRYPTO_E_COUNTER_OVERFLOW       = 0x0B,
+	CRYPTO_E_JOB_CANCELED           = 0x0C,
+} Std_ReturnType;
+
+struct Mtk_JobPrimitiveInfoType
+{
+	uint32_t                            callbackId;
+	struct Crypto_PrimitiveInfoType     primitiveInfo;
+	uint32_t                            secureCounterId;
+	uint32_t                            cryIfKeyId;
+	enum Crypto_ProcessingType          processingType;
+	uint8_t                             callbackUpdateNotification; // A boolean value
+};
+
+struct Mtk_JobPrimitiveInputOutputType
+{
+	uint8_t                             *inputPtr;              // V -> P
+	uint32_t                            inputLength;
+	uint8_t                             *secondaryInputPtr;     // V -> P
+	uint32_t                            secondaryInputLength;
+	uint8_t                             *tertiaryInputPtr;      // V -> P
+	uint32_t                            tertiaryInputLength;
+	uint8_t                             *outputPtr;             // V -> P
+	uint32_t                            outputLength;
+	uint8_t                             *secondaryOutputPtr;    // V -> P
+	uint32_t                            secondaryOutputLength;
+//    uint64_t                          input64;
+//    enum Crypto_VerifyResultType      *verifyPtr;  // Ptr to
+//    uint64_t                          *output64Ptr;
+//    enum Crypto_OperationModeType     mode;
+};
+
+struct Mtk_JobType
+{
+	uint32_t                                    jobId;
+	enum Crypto_JobStateType                    jobState;
+	struct Mtk_JobPrimitiveInputOutputType      jobPrimitiveInputOutput;
+	struct Mtk_JobPrimitiveInfoType             jobPrimitiveInfo;
+	struct Crypto_JobInfoType                   jobInfo;
+	uint32_t                                    cryptoKeyId;
+};
+
+uint8_t Mtk_ProcessJob    // Std_ReturnType
+(
+	uint32_t objectId,
+	struct Mtk_JobType   *job
+);
+
+
+#endif /* _TEST_CRYPTO_H_ */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/processor.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/processor.h
new file mode 100644
index 0000000..517b32a
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/processor.h
@@ -0,0 +1,48 @@
+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+

+#ifndef _PROCESSOR_H_

+#define _PROCESSOR_H_

+

+enum CPU_SERIAL {

+	CPU_SERIAL_CA53,

+	CPU_SERIAL_HSM,

+	CPU_SERIAL_CNT,

+	CPU_SERIAL_INVALID,

+};

+

+#endif /* _PROCESSOR_H_ */

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_internal_abi.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_internal_abi.h
new file mode 100644
index 0000000..7c6ff89
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_internal_abi.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SKS_INTERNAL_ABI_H
+#define __SKS_INTERNAL_ABI_H
+
+/* Internal format is based on the API IDs */
+#include <sks_ta.h>
+#include <stddef.h>
+
+
+/**
+ * Serialization of object attributes
+ *
+ * An object is defined by the list of its attributes among which identifiers
+ * for the type of the object (symmetric key, asymmetric key, ...) and the
+ * object value (i.e the AES key value). In the end, an object is a list of
+ * attributes.
+ *
+ * SKS uses a serialized format for defining the attributes of an object. The
+ * attributes content starts with a header structure header followed by each
+ * attributes, stored in serialized fields:
+ * - the 32bit identifier of the attribute
+ * - the 32bit value attribute byte size
+ * - the effective value of the attribute (variable size)
+ */
+struct sks_ref {
+	uint32_t id;
+	uint32_t size;
+	uint8_t data[];
+};
+
+/*
+ * Header of a serialised memory object inside SKS TA.
+ *
+ * @attrs_size; byte size of the serialized data
+ * @attrs_count; number of items in the blob
+ * @class - object class id (from CK literature): key, certif, etc...
+ * @type - object type id, per class, i.e aes or des3 in the key class.
+ * @boolpropl - 32bit bitmask storing boolean properties #0 to #31.
+ * @boolproph - 32bit bitmask storing boolean properties #32 to #64.
+ * @attrs - then starts the blob binary data
+ */
+struct sks_attrs_head {
+	uint32_t attrs_size;
+	uint32_t attrs_count;
+#ifdef SKS_SHEAD_WITH_TYPE
+	uint32_t class;
+	uint32_t type;
+#endif
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	uint32_t boolpropl;
+	uint32_t boolproph;
+#endif
+	uint8_t attrs[];
+};
+
+#endif /*__SKS_INTERNAL_ABI_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_ta.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_ta.h
new file mode 100644
index 0000000..ce9917c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/sks_ta.h
@@ -0,0 +1,1139 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#ifndef __SKS_TA_H__
+#define __SKS_TA_H__
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#define TA_SKS_UUID { 0xfd02c9da, 0x306c, 0x48c7, \
+			{ 0xa4, 0x9c, 0xbb, 0xd8, 0x27, 0xae, 0x86, 0xee } }
+
+/* SKS trusted application version information */
+#define SKS_VERSION_ID0		0
+#define SKS_VERSION_ID1		0
+
+/*
+ * SKS_CMD_PING		Acknowledge TA presence and return TA version info
+ *
+ * Optional invocation parameter:
+ *
+ * [out]        memref[2] = [
+ *                      32bit version0 value,
+ *                      32bit version1 value
+ *              ]
+ */
+#define SKS_CMD_PING			0x00000000
+
+/*
+ * SKS_CMD_CK_SLOT_LIST - Get the table of the valid slot IDs
+ *
+ * [out]        memref[2] = 32bit array slot_ids[slot counts]
+ *
+ * The TA instance may represent several PKCS#11 slots and associated tokens.
+ * This command relates the PKCS#11 API function C_GetSlotList and return the
+ * valid IDs recognized by the trusted application.
+ */
+#define SKS_CMD_CK_SLOT_LIST		0x00000001
+
+/*
+ * SKS_CMD_CK_SLOT_INFO - Get cryptoki structured slot information
+ *
+ * [in]		memref[0] = 32bit slot ID
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]        memref[2] = (struct sks_ck_slot_info)info
+ *
+ * The TA instance may represent several PKCS#11 slots and associated tokens.
+ * This command relates the PKCS#11 API function C_GetSlotInfo and return the
+ * information about the target slot.
+ */
+#define SKS_CMD_CK_SLOT_INFO		0x00000002
+
+#define SKS_SLOT_DESC_SIZE		64
+#define SKS_SLOT_MANUFACTURER_SIZE	32
+#define SKS_SLOT_VERSION_SIZE		2
+
+struct sks_slot_info {
+	uint8_t slotDescription[SKS_SLOT_DESC_SIZE];
+	uint8_t manufacturerID[SKS_SLOT_MANUFACTURER_SIZE];
+	uint32_t flags;
+	uint8_t hardwareVersion[SKS_SLOT_VERSION_SIZE];
+	uint8_t firmwareVersion[SKS_SLOT_VERSION_SIZE];
+};
+
+/*
+ * Values for sks_token_info::flags.
+ * SKS_CKFS_<x> corresponds to cryptoki flag CKF_<x> related to slot flags.
+ */
+#define SKS_CKFS_TOKEN_PRESENT		(1U << 0)
+#define SKS_CKFS_REMOVABLE_DEVICE	(1U << 1)
+#define SKS_CKFS_HW_SLOT		(1U << 2)
+
+/*
+ * SKS_CMD_CK_TOKEN_INFO - Get cryptoki structured token information
+ *
+ * [in]		memref[0] = 32bit slot ID
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]        memref[2] = (struct sks_ck_token_info)info
+ *
+ * The TA instance may represent several PKCS#11 slots and associated tokens.
+ * This command relates the PKCS#11 API function C_GetTokenInfo and return the
+ * information about the target represented token.
+ */
+#define SKS_CMD_CK_TOKEN_INFO		0x00000003
+
+#define SKS_TOKEN_LABEL_SIZE		32
+#define SKS_TOKEN_MANUFACTURER_SIZE	32
+#define SKS_TOKEN_MODEL_SIZE		16
+#define SKS_TOKEN_SERIALNUM_SIZE	16
+
+struct sks_token_info {
+	uint8_t label[SKS_TOKEN_LABEL_SIZE];
+	uint8_t manufacturerID[SKS_TOKEN_MANUFACTURER_SIZE];
+	uint8_t model[SKS_TOKEN_MODEL_SIZE];
+	uint8_t serialNumber[SKS_TOKEN_SERIALNUM_SIZE];
+	uint32_t flags;
+	uint32_t ulMaxSessionCount;
+	uint32_t ulSessionCount;
+	uint32_t ulMaxRwSessionCount;
+	uint32_t ulRwSessionCount;
+	uint32_t ulMaxPinLen;
+	uint32_t ulMinPinLen;
+	uint32_t ulTotalPublicMemory;
+	uint32_t ulFreePublicMemory;
+	uint32_t ulTotalPrivateMemory;
+	uint32_t ulFreePrivateMemory;
+	uint8_t hardwareVersion[2];
+	uint8_t firmwareVersion[2];
+	uint8_t utcTime[16];
+};
+
+/*
+ * Values for sks_token_info::flags.
+ * SKS_CKFT_<x> corresponds to cryptoki CKF_<x> related to token flags.
+ */
+#define SKS_CKFT_RNG					(1U << 0)
+#define SKS_CKFT_WRITE_PROTECTED			(1U << 1)
+#define SKS_CKFT_LOGIN_REQUIRED				(1U << 2)
+#define SKS_CKFT_USER_PIN_INITIALIZED			(1U << 3)
+#define SKS_CKFT_RESTORE_KEY_NOT_NEEDED			(1U << 4)
+#define SKS_CKFT_CLOCK_ON_TOKEN				(1U << 5)
+#define SKS_CKFT_PROTECTED_AUTHENTICATION_PATH		(1U << 6)
+#define SKS_CKFT_DUAL_CRYPTO_OPERATIONS			(1U << 7)
+#define SKS_CKFT_TOKEN_INITIALIZED			(1U << 8)
+#define SKS_CKFT_USER_PIN_COUNT_LOW			(1U << 9)
+#define SKS_CKFT_USER_PIN_FINAL_TRY			(1U << 10)
+#define SKS_CKFT_USER_PIN_LOCKED			(1U << 11)
+#define SKS_CKFT_USER_PIN_TO_BE_CHANGED			(1U << 12)
+#define SKS_CKFT_SO_PIN_COUNT_LOW			(1U << 13)
+#define SKS_CKFT_SO_PIN_FINAL_TRY			(1U << 14)
+#define SKS_CKFT_SO_PIN_LOCKED				(1U << 15)
+#define SKS_CKFT_SO_PIN_TO_BE_CHANGED			(1U << 16)
+#define SKS_CKFT_ERROR_STATE				(1U << 17)
+
+/*
+ * SKS_CMD_CK_MECHANISM_IDS - Get list of the supported mechanisms
+ *
+ * [in]		memref[0] = 32bit slot ID
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]        memref[2] = 32bit array mechanism IDs
+ *
+ * This commands relates to the PKCS#11 API function C_GetMechanismList.
+ */
+#define SKS_CMD_CK_MECHANISM_IDS	0x00000004
+
+/*
+ * SKS_CMD_CK_MECHANISM_INFO - Get information on a specific mechanism
+ *
+ * [in]		memref[0] = [
+ *			32bit slot ID,
+ *			32bit mechanism ID
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]        memref[2] = (struct sks_mecha_info)info
+ *
+ * This commands relates to the PKCS#11 API function C_GetMechanismInfo.
+ */
+#define SKS_CMD_CK_MECHANISM_INFO	0x00000005
+
+struct sks_mechanism_info {
+	uint32_t min_key_size;
+	uint32_t max_key_size;
+	uint32_t flags;
+};
+
+/*
+ * Values for sks_mechanism_info::flags.
+ * SKS_CKFM_<x> strictly matches cryptoki CKF_<x> related to mechanism flags.
+ */
+#define SKS_CKFM_HW			(1U << 0)
+#define SKS_CKFM_ENCRYPT		(1U << 8)
+#define SKS_CKFM_DECRYPT		(1U << 9)
+#define SKS_CKFM_DIGEST			(1U << 10)
+#define SKS_CKFM_SIGN			(1U << 11)
+#define SKS_CKFM_SIGN_RECOVER		(1U << 12)
+#define SKS_CKFM_VERIFY			(1U << 13)
+#define SKS_CKFM_VERIFY_RECOVER		(1U << 14)
+#define SKS_CKFM_GENERATE		(1U << 15)
+#define SKS_CKFM_GENERATE_PAIR		(1U << 16)
+#define SKS_CKFM_WRAP			(1U << 17)
+#define SKS_CKFM_UNWRAP			(1U << 18)
+#define SKS_CKFM_DERIVE			(1U << 19)
+#define SKS_CKFM_EC_F_P			(1U << 20)
+#define SKS_CKFM_EC_F_2M		(1U << 21)
+#define SKS_CKFM_EC_ECPARAMETERS	(1U << 22)
+#define SKS_CKFM_EC_NAMEDCURVE		(1U << 23)
+#define SKS_CKFM_EC_UNCOMPRESS		(1U << 24)
+#define SKS_CKFM_EC_COMPRESS		(1U << 25)
+
+/*
+ * SKS_CMD_CK_INIT_TOKEN - Initialize PKCS#11 token
+ *
+ * [in]		memref[0] = [
+ *			32bit slot ID,
+ *			32bit PIN length,
+ *			8bit array PIN[PIN length],
+ *			8bit array label[32]
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * This commands relates to the PKCS#11 API function C_InitToken().
+ */
+#define SKS_CMD_CK_INIT_TOKEN		0x00000006
+
+/*
+ * SKS_CMD_CK_INIT_PIN - Initialize PKCS#11 token PIN
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit PIN length,
+ *			8bit array PIN[PIN length]
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * This commands relates to the PKCS#11 API function C_InitPIN().
+ */
+#define SKS_CMD_CK_INIT_PIN		0x00000007
+
+/*
+ * SKS_CMD_CK_SET_PIN - Set PKCS#11 token PIN
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit old_pin_length,
+ *			8bit array old_pin[old_pin_length],
+ *			32bit new_pin_length,
+ *			8bit array new_pin[new_pin_length]
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * This commands relates to the PKCS#11 API function C_SetPIN()
+ */
+#define SKS_CMD_CK_SET_PIN		0x00000008
+
+/*
+ * SKS_CMD_CK_OPEN_RO_SESSION - Open read-only session
+ *
+ * [in]		memref[0] = 32bit slot ID
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[0] = 32bit session handle
+ *
+ * This commands relates to the PKCS#11 API function C_OpenSession() for a
+ * read-only session.
+ */
+#define SKS_CMD_CK_OPEN_RO_SESSION	0x00000009
+
+/*
+ * SKS_CMD_CK_OPEN_RW_SESSION - Open read/write session
+ *
+ * [in]		memref[0] = 32bit slot
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[0] = 32bit session handle
+ *
+ * This commands relates to the PKCS#11 API function C_OpenSession() for a
+ * read/write session.
+ */
+#define SKS_CMD_CK_OPEN_RW_SESSION	0x0000000a
+
+/*
+ * SKS_CMD_CK_CLOSE_SESSION - Close an opened session
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * This commands relates to the PKCS#11 API function C_CloseSession().
+ */
+#define SKS_CMD_CK_CLOSE_SESSION	0x0000000b
+
+/*
+ * SKS_CMD_CK_SESSION_INFO - Get Cryptoki information on a session
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]        memref[2] = (struct sks_ck_session_info)info
+ *
+ * This commands relates to the PKCS#11 API function C_GetSessionInfo().
+ */
+#define SKS_CMD_CK_SESSION_INFO		0x0000000c
+
+/*
+ * Values for sks_session_info::state.
+ * SKS_CKSS_<x> strictly matches cryptoki CKS_<x> related to session state.
+ */
+#define SKS_CKSS_RO_PUBLIC_SESSION	0
+#define SKS_CKSS_RO_USER_FUNCTIONS	1
+#define SKS_CKSS_RW_PUBLIC_SESSION	2
+#define SKS_CKSS_RW_USER_FUNCTIONS	3
+#define SKS_CKSS_RW_SO_FUNCTIONS	4
+
+struct sks_session_info {
+	uint32_t slot_id;
+	uint32_t state;
+	uint32_t flags;
+	uint32_t error_code;
+};
+
+/*
+ * Values for sks_session_info::flags.
+ * SKS_CKFS_<x> strictly matches cryptoki CKF_<x> related to session flags.
+ */
+#define SKS_CKFS_RW_SESSION			(1U << 1)
+#define SKS_CKFS_SERIAL_SESSION		(1U << 2)
+
+/*
+ * SKS_CMD_CK_CLOSE_ALL_SESSIONS - Close all client sessions on slot/token
+ *
+ * [in]		memref[0] = 32bit slot
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * This commands relates to the PKCS#11 API function C_CloseAllSessions().
+ */
+#define SKS_CMD_CK_CLOSE_ALL_SESSIONS	0x0000000d
+
+/*
+ * SKS_CMD_IMPORT_OBJECT - Import a raw object in the session or token
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			(struct sks_object_head)attribs + attributes data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = 32bit object handle
+ *
+ * This commands relates to the PKCS#11 API function C_CreateObject().
+ */
+#define SKS_CMD_IMPORT_OBJECT		0x0000000e
+
+/**
+ * Serialization of object attributes
+ */
+
+/*
+ * sks_object_head - Header of object whose data are serialized in memory
+ *
+ * An object in made of several attributes. Attributes are store one next to
+ * the other with byte alignment as serialized byte arrays. Appended
+ * attributes byte arrays are prepend with this header structure that
+ * defines the number of attribute items and the overall byte size of the
+ * attrs byte array.
+ *
+ * @attrs_size - byte size of whole byte array attrs[]
+ * @attrs_count - number of attribute items stored in attrs[]
+ * @attrs - then starts the attributes data
+ */
+struct sks_object_head {
+	uint32_t attrs_size;
+	uint32_t attrs_count;
+	uint8_t attrs[];
+};
+
+/*
+ * Attribute reference in the TA ABI. Each attribute start with the header
+ * structure followed by the attribute value, its byte size being defined
+ * in the attribute header.
+ *
+ * @id - the 32bit identifier of the attribute, see SKS_CKA_<x>
+ * @size - the 32bit value attribute byte size
+ * @data - then starts the attribute value
+ */
+struct sks_attribute_head {
+	uint32_t id;
+	uint32_t size;
+	uint8_t data[];
+};
+
+/*
+ * SKS_CMD_DESTROY_OBJECT - Destroy an object
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit object handle
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * This commands relates to the PKCS#11 API function C_DestroyObject().
+ */
+#define SKS_CMD_DESTROY_OBJECT		0x0000000f
+
+/*
+ * SKS_CMD_ENCRYPT_INIT - Initialize encryption processing
+ * SKS_CMD_DECRYPT_INIT - Initialize decryption processing
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			(struct sks_attribute_head)mechanism + mecha parameters
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * These commands relate to the PKCS#11 API functions C_EncryptInit() and
+ * C_DecryptInit.
+ */
+#define SKS_CMD_ENCRYPT_INIT		0x00000010
+#define SKS_CMD_DECRYPT_INIT		0x00000011
+
+/*
+ * SKS_CMD_ENCRYPT_UPDATE - Update encryption processing
+ * SKS_CMD_DECRYPT_UPDATE - Update decryption processing
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [in]		memref[1] = input data to be processed
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = output processed data
+ *
+ * These commands relate to the PKCS#11 API functions C_EncryptUpdate() and
+ * C_DecryptUpdate.
+ */
+#define SKS_CMD_ENCRYPT_UPDATE		0x00000012
+#define SKS_CMD_DECRYPT_UPDATE		0x00000013
+
+/*
+ * SKS_CMD_ENCRYPT_FINAL - Finalize encryption processing
+ * SKS_CMD_DECRYPT_FINAL - Finalize decryption processing
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = output processed data
+ *
+ * These commands relate to the PKCS#11 API functions C_EncryptFinal() and
+ * C_DecryptFinal.
+ */
+#define SKS_CMD_ENCRYPT_FINAL		0x00000014
+#define SKS_CMD_DECRYPT_FINAL		0x00000015
+
+/*
+ * SKS_CMD_GENERATE_SYMM_KEY - Generate a symmetric key
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			(struct sks_attribute_head)mechanism + mecha parameters,
+ *			(struct sks_object_head)attribs + attributes data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = 32bit key handle
+ *
+ * This command relates to the PKCS#11 API functions C_GenerateKey().
+ */
+#define SKS_CMD_GENERATE_SYMM_KEY	0x00000016
+
+/*
+ * SKS_CMD_SIGN_INIT - Initialize a signature computation processing
+ * SKS_CMD_VERIFY_INIT - Initialize a signature verification processing
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit key handle,
+ *			(struct sks_attribute_head)mechanism + mecha parameters,
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * These commands relate to the PKCS#11 API functions C_SignInit() and
+ * C_VerifyInit.
+ */
+#define SKS_CMD_SIGN_INIT		0x00000017
+#define SKS_CMD_VERIFY_INIT		0x00000018
+
+/*
+ * SKS_CMD_SIGN_UPDATE - Update a signature computation processing
+ * SKS_CMD_VERIFY_UPDATE - Update a signature verification processing
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [in]		memref[1] = input data to be processed
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * These commands relate to the PKCS#11 API functions C_SignUpdate() and
+ * C_VerifyUpdate.
+ */
+#define SKS_CMD_SIGN_UPDATE		0x00000019
+#define SKS_CMD_VERIFY_UPDATE		0x0000001a
+
+/*
+ * SKS_CMD_SIGN_FINAL - Finalize a signature computation processing
+ * SKS_CMD_VERIFY_FINAL - Finalize a signature verification processing
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = output processed data
+ *
+ * These commands relate to the PKCS#11 API functions C_SignFinal() and
+ * C_VerifyFinal.
+ */
+#define SKS_CMD_SIGN_FINAL		0x0000001b
+#define SKS_CMD_VERIFY_FINAL		0x0000001c
+
+/*
+ * SKS_CMD_FIND_OBJECTS_INIT - Initialize a objects search
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			(struct sks_object_head)attribs + attributes data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * This command relates to the PKCS#11 API function C_FindOjectsInit().
+ */
+#define SKS_CMD_FIND_OBJECTS_INIT	0x0000001d
+
+/*
+ * SKS_CMD_FIND_OBJECTS - Get handles of matching objects
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = 32bit array object_handle_array[N]
+ *
+ * This command relates to the PKCS#11 API function C_FindOjects().
+ * The size of object_handle_array depends output buffer size
+ * provided by the client.
+ */
+#define SKS_CMD_FIND_OBJECTS		0x0000001e
+
+/*
+ * SKS_CMD_FIND_OBJECTS_FINAL - Finalize current objects search
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * This command relates to the PKCS#11 API function C_FindOjectsFinal().
+ */
+#define SKS_CMD_FIND_OBJECTS_FINAL	0x0000001f
+
+/*
+ * SKS_CMD_GET_OBJECT_SIZE - Get size used by object in the TEE
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit key handle
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = 32bit object_byte_size
+ */
+#define SKS_CMD_GET_OBJECT_SIZE		0x00000020
+
+/*
+ * SKS_CMD_GET_ATTRIBUTE_VALUE - Get the value of object attribute(s)
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit object handle,
+ *			(struct sks_object_head)attribs + attributes data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = (struct sks_object_head)attribs + attributes data
+ */
+#define SKS_CMD_GET_ATTRIBUTE_VALUE	0x00000021
+
+/*
+ * SKS_CMD_SET_ATTRIBUTE_VALUE - Set the value for object attribute(s)
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit object handle,
+ *			(struct sks_object_head)attribs + attributes data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = (struct sks_object_head)attribs + attributes data
+ */
+#define SKS_CMD_SET_ATTRIBUTE_VALUE	0x00000022
+
+/*
+ * SKS_CMD_DERIVE_KEY - Derive a key from already provisioned parent key
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			(struct sks_attribute_head)mechanism + mecha parameters,
+ *			32bit key handle,
+ *			(struct sks_object_head)attribs + attributes data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = 32bit object handle
+ */
+#define SKS_CMD_DERIVE_KEY		0x00000023
+
+/*
+ * SKS_CMD_INIT_PIN - Initialize user PIN
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit PIN byte size,
+ *			byte arrays: PIN data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ */
+#define SKS_CMD_INIT_PIN		0x00000024
+
+/*
+ * SKS_CMD_SET_PIN - Change user PIN
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit old PIN byte size,
+ *			byte arrays: PIN data
+ *			32bit new PIN byte size,
+ *			byte arrays: new PIN data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ */
+#define SKS_CMD_SET_PIN			0x00000025
+
+/*
+ * SKS_CMD_LOGIN - Initialize user PIN
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit user identifier,
+ *			32bit PIN byte size,
+ *			byte arrays: PIN data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ */
+#define SKS_CMD_LOGIN			0x00000026
+
+/*
+ * Values for user identifier parameter in SKS_CMD_LOGIN
+ */
+#define SKS_CKU_SO			0x000
+#define SKS_CKU_USER			0x001
+#define SKS_CKU_CONTEXT_SPECIFIC	0x002
+
+/*
+ * SKS_CMD_LOGOUT - Log out from token
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			32bit PIN byte size,
+ *			byte array: PIN data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ */
+#define SKS_CMD_LOGOUT			0x00000027
+
+/*
+ * SKS_CMD_GENERATE_KEY_PAIR - Generate an asymmetric key pair
+ *
+ * [in]		memref[0] = [
+ *			32bit session handle,
+ *			(struct sks_attribute_head)mechanism + mecha parameters,
+ *			(struct sks_object_head)pubkey_attribs + attributes data
+ *			(struct sks_object_head)privkeyattribs + attributes data
+ *		]
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = [
+ *			32bit public key handle,
+ *			32bit prive key handle
+ *		]
+ *
+ * This command relates to the PKCS#11 API functions C_GenerateKeyPair().
+ */
+#define SKS_CMD_GENERATE_KEY_PAIR	0x00000028
+
+/*
+ * SKS_CMD_ENCRYPT_ONESHOT - Update and finalize encryption processing
+ * SKS_CMD_DECRYPT_ONESHOT - Update and finalize decryption processing
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [in]		memref[1] = input data to be processed
+ * [out]	memref[0] = 32bit fine grain return code
+ * [out]	memref[2] = output processed data
+ *
+ * These commands relate to the PKCS#11 API functions C_EncryptUpdate() and
+ * C_DecryptUpdate.
+ */
+#define SKS_CMD_ENCRYPT_ONESHOT		0x00000029
+#define SKS_CMD_DECRYPT_ONESHOT		0x0000002a
+
+/*
+ * SKS_CMD_SIGN_ONESHOT - Update and finalize a signature computation
+ * SKS_CMD_VERIFY_ONESHOT - Update and finalize a signature verification
+ *
+ * [in]		memref[0] = 32bit session handle
+ * [in]		memref[1] = input data to be processed
+ * [out]	memref[0] = 32bit fine grain return code
+ *
+ * These commands relate to the PKCS#11 API functions C_SignUpdate() and
+ * C_VerifyUpdate.
+ */
+#define SKS_CMD_SIGN_ONESHOT		0x0000002b
+#define SKS_CMD_VERIFY_ONESHOT		0x0000002c
+
+#define SKS_CMD_DIGEST_INIT		0x0000002d
+#define SKS_CMD_DIGEST_ONESHOT		0x0000002e
+#define SKS_CMD_DIGEST_UPDATE		0x0000002f
+#define SKS_CMD_DIGEST_FINAL		0x00000030
+
+#define SKS_CMD_GENERATE_RANDOM		0x00000031
+
+#define SKS_CMD_IMPORT_KEY		0x00000032
+#define SKS_CMD_IMPORT_KEY_PAIR		0x00000033
+#define SKS_CMD_EXPORT_KEY		0x00000034
+
+#define SKS_CMD_UTILS			0x00000035
+
+/*
+ * Command return codes
+ * SKS_CKR_<x> relates cryptoki CKR_<x> in meaning if not in value.
+ */
+#define SKS_CKR_OK				0x00000000
+#define SKS_CKR_GENERAL_ERROR			0x00000001
+#define SKS_CKR_DEVICE_MEMORY			0x00000002
+#define SKS_CKR_ARGUMENTS_BAD			0x00000003
+#define SKS_CKR_BUFFER_TOO_SMALL		0x00000004
+#define SKS_CKR_FUNCTION_FAILED			0x00000005
+#define SKS_CKR_SIGNATURE_INVALID		0x00000007
+#define SKS_CKR_ATTRIBUTE_TYPE_INVALID		0x00000008
+#define SKS_CKR_ATTRIBUTE_VALUE_INVALID		0x00000009
+#define SKS_CKR_OBJECT_HANDLE_INVALID		0x0000000a
+#define SKS_CKR_KEY_HANDLE_INVALID		0x0000000b
+#define SKS_CKR_MECHANISM_INVALID		0x0000000c
+#define SKS_CKR_SESSION_HANDLE_INVALID		0x0000000d
+#define SKS_CKR_SLOT_ID_INVALID			0x0000000e
+#define SKS_CKR_MECHANISM_PARAM_INVALID		0x0000000f
+#define SKS_CKR_TEMPLATE_INCONSISTENT		0x00000010
+#define SKS_CKR_TEMPLATE_INCOMPLETE		0x00000011
+#define SKS_CKR_PIN_INCORRECT			0x00000012
+#define SKS_CKR_PIN_LOCKED			0x00000013
+#define SKS_CKR_PIN_EXPIRED			0x00000014
+#define SKS_CKR_PIN_INVALID			0x00000015
+#define SKS_CKR_PIN_LEN_RANGE			0x00000016
+#define SKS_CKR_SESSION_EXISTS			0x00000017
+#define SKS_CKR_SESSION_READ_ONLY		0x00000018
+#define SKS_CKR_SESSION_READ_WRITE_SO_EXISTS	0x00000019
+#define SKS_CKR_OPERATION_ACTIVE		0x0000001a
+#define SKS_CKR_KEY_FUNCTION_NOT_PERMITTED	0x0000001b
+#define SKS_CKR_OPERATION_NOT_INITIALIZED	0x0000001c
+#define SKS_CKR_TOKEN_WRITE_PROTECTED		0x0000001d
+#define SKS_CKR_TOKEN_NOT_PRESENT		0x0000001e
+#define SKS_CKR_TOKEN_NOT_RECOGNIZED		0x0000001f
+#define SKS_CKR_ACTION_PROHIBITED		0x00000020
+#define SKS_CKR_ATTRIBUTE_READ_ONLY		0x00000021
+#define SKS_CKR_PIN_TOO_WEAK			0x00000022
+#define SKS_CKR_CURVE_NOT_SUPPORTED		0x00000023
+#define SKS_CKR_DOMAIN_PARAMS_INVALID		0x00000024
+#define SKS_CKR_USER_ALREADY_LOGGED_IN		0x00000025
+#define SKS_CKR_USER_ANOTHER_ALREADY_LOGGED_IN	0x00000026
+#define SKS_CKR_USER_NOT_LOGGED_IN		0x00000027
+#define SKS_CKR_USER_PIN_NOT_INITIALIZED	0x00000028
+#define SKS_CKR_USER_TOO_MANY_TYPES		0x00000029
+#define SKS_CKR_USER_TYPE_INVALID		0x0000002a
+#define SKS_CKR_SESSION_READ_ONLY_EXISTS	0x0000002b
+#define SKS_CKR_KEY_SIZE_RANGE			0x0000002c
+#define SKS_CKR_ATTRIBUTE_SENSITIVE		0x0000002d
+#define SKS_CKR_SIGNATURE_LEN_RANGE		0x0000002e
+#define SKS_CKR_KEY_TYPE_INCONSISTENT		0x0000002f
+#define SKS_CKR_DATA_LEN_RANGE			0x00000030
+#define SKS_CKR_ENCRYPTED_DATA_LEN_RANGE	0x00000031
+
+/* Status without strict equivalence in Cryptoki API */
+#define SKS_NOT_FOUND				0x00001000
+#define SKS_NOT_IMPLEMENTED			0x00001001
+
+/* Attribute specific values */
+#define SKS_CK_UNAVAILABLE_INFORMATION		((uint32_t)0xFFFFFFFF)
+#define SKS_UNDEFINED_ID			SKS_CK_UNAVAILABLE_INFORMATION
+#define SKS_FALSE				0
+#define SKS_TRUE				1
+
+/*
+ * Attribute identifiers
+ * Valid values for struct sks_attribute_head::id
+ *
+ * SKS_ATTR_<x> corresponds to cryptoki CKA_<x>.
+ * Value range [0 63] is reserved to boolean value attributes.
+ */
+#define SKS_BOOLPROPS_BASE			0x00000000
+#define SKS_CKA_TOKEN				0x00000000
+#define SKS_CKA_PRIVATE				0x00000001
+#define SKS_CKA_TRUSTED				0x00000002
+#define SKS_CKA_SENSITIVE			0x00000003
+#define SKS_CKA_ENCRYPT				0x00000004
+#define SKS_CKA_DECRYPT				0x00000005
+#define SKS_CKA_WRAP				0x00000006
+#define SKS_CKA_UNWRAP				0x00000007
+#define SKS_CKA_SIGN				0x00000008
+#define SKS_CKA_SIGN_RECOVER			0x00000009
+#define SKS_CKA_VERIFY				0x0000000a
+#define SKS_CKA_VERIFY_RECOVER			0x0000000b
+#define SKS_CKA_DERIVE				0x0000000c
+#define SKS_CKA_EXTRACTABLE			0x0000000d
+#define SKS_CKA_LOCAL				0x0000000e
+#define SKS_CKA_NEVER_EXTRACTABLE		0x0000000f
+#define SKS_CKA_ALWAYS_SENSITIVE		0x00000010
+#define SKS_CKA_MODIFIABLE			0x00000011
+#define SKS_CKA_COPYABLE			0x00000012
+#define SKS_CKA_DESTROYABLE			0x00000013
+#define SKS_CKA_ALWAYS_AUTHENTICATE		0x00000014
+#define SKS_CKA_WRAP_WITH_TRUSTED		0x00000015
+/* Last boolean property ID (value is 63) is reserved */
+#define SKS_BOOLPROPS_LAST			SKS_CKA_WRAP_WITH_TRUSTED
+#define SKS_BOOLPROPS_END			0x0000003F
+#define SKS_BOOLPROPH_FLAG			BIT(31)
+
+#define SKS_CKA_LABEL				0x00000040
+#define SKS_CKA_VALUE				0x00000041
+#define SKS_CKA_VALUE_LEN			0x00000042
+#define SKS_CKA_WRAP_TEMPLATE			0x00000043
+#define SKS_CKA_UNWRAP_TEMPLATE			0x00000044
+#define SKS_CKA_DERIVE_TEMPLATE			0x00000045
+#define SKS_CKA_START_DATE			0x00000046
+#define SKS_CKA_END_DATE			0x00000047
+#define SKS_CKA_OBJECT_ID			0x00000048
+#define SKS_CKA_APPLICATION			0x00000049
+#define SKS_CKA_MECHANISM_TYPE			0x0000004a
+#define SKS_CKA_ID				0x0000004b
+#define SKS_CKA_ALLOWED_MECHANISMS		0x0000004c
+#define SKS_CKA_CLASS				0x0000004d
+#define SKS_CKA_KEY_TYPE			0x0000004e
+#define SKS_CKA_EC_POINT			0x0000004f
+#define SKS_CKA_EC_PARAMS			0x00000050
+#define SKS_CKA_MODULUS				0x00000051
+#define SKS_CKA_MODULUS_BITS			0x00000052
+#define SKS_CKA_PUBLIC_EXPONENT			0x00000053
+#define SKS_CKA_PRIVATE_EXPONENT		0x00000054
+#define SKS_CKA_PRIME_1				0x00000055
+#define SKS_CKA_PRIME_2				0x00000056
+#define SKS_CKA_EXPONENT_1			0x00000057
+#define SKS_CKA_EXPONENT_2			0x00000058
+#define SKS_CKA_COEFFICIENT			0x00000059
+#define SKS_CKA_SUBJECT				0x0000005a
+#define SKS_CKA_PUBLIC_KEY_INFO			0x0000005b
+#define SKS_CKA_CERTIFICATE_TYPE		0x0000005c
+#define SKS_CKA_CERTIFICATE_CATEGORY		0x0000005d
+#define SKS_CKA_ISSUER				0x0000005e
+#define SKS_CKA_SERIAL_NUMBER			0x0000005f
+#define SKS_CKA_URL				0x00000060
+#define SKS_CKA_HASH_OF_SUBJECT_PUBLIC_KEY	0x00000061
+#define SKS_CKA_HASH_OF_ISSUER_PUBLIC_KEY	0x00000062
+#define SKS_CKA_NAME_HASH_ALGORITHM		0x00000063
+#define SKS_CKA_KEY_GEN_MECHANISM		0x00000064
+#define SKS_CKA_HSM_KEY_ID			0x00000065
+#define SKS_CKA_HSM_KEY_LEN			0x00000066
+
+/*
+ * Valid values for attribute SKS_CKA_CLASS
+ * SKS_CKO_<x> corresponds to cryptoki CKO_<x>.
+ */
+#define SKS_CKO_SECRET_KEY			0x000
+#define SKS_CKO_PUBLIC_KEY			0x001
+#define SKS_CKO_PRIVATE_KEY			0x002
+#define SKS_CKO_OTP_KEY				0x003
+#define SKS_CKO_CERTIFICATE			0x004
+#define SKS_CKO_DATA				0x005
+#define SKS_CKO_DOMAIN_PARAMETERS		0x006
+#define SKS_CKO_HW_FEATURE			0x007
+#define SKS_CKO_MECHANISM			0x008
+
+/*
+ * Valid values for attribute SKS_CKA_KEY_TYPE
+ * SKS_CKK_<x> corresponds to cryptoki CKK_<x> related to symmetric keys
+ */
+#define SKS_CKK_AES				0x000
+#define SKS_CKK_GENERIC_SECRET			0x001
+#define SKS_CKK_MD5_HMAC			0x002
+#define SKS_CKK_SHA_1_HMAC			0x003
+#define SKS_CKK_SHA224_HMAC			0x004
+#define SKS_CKK_SHA256_HMAC			0x005
+#define SKS_CKK_SHA384_HMAC			0x006
+#define SKS_CKK_SHA512_HMAC			0x007
+#define SKS_CKK_EC				0x008
+#define SKS_CKK_RSA				0x009
+#define SKS_CKK_DSA				0x00a
+#define SKS_CKK_DH				0x00b
+#define SKS_CKK_DES				0x00c
+#define SKS_CKK_DES2				0x00d
+#define SKS_CKK_DES3				0x00e
+
+/*
+ * Valid values for attribute SKS_CKA_CERTIFICATE_TYPE
+ * SKS_CKC_<x> corresponds to cryptoki CKC_<x>.
+ */
+#define SKS_CKC_X_509			0x000
+#define SKS_CKC_X_509_ATTR_CER		0x001
+#define SKS_CKC_WTLS			0x002
+
+/*
+ * Valid values for attribute SKS_CKA_MECHANISM_TYPE
+ * SKS_CKM_<x> corresponds to cryptoki CKM_<x>.
+ */
+#define SKS_CKM_AES_ECB				0x000
+#define SKS_CKM_AES_CBC				0x001
+#define SKS_CKM_AES_CBC_PAD			0x002
+#define SKS_CKM_AES_CTS				0x003
+#define SKS_CKM_AES_CTR				0x004
+#define SKS_CKM_AES_GCM				0x005
+#define SKS_CKM_AES_CCM				0x006
+#define SKS_CKM_AES_GMAC			0x007
+#define SKS_CKM_AES_CMAC			0x008
+#define SKS_CKM_AES_CMAC_GENERAL		0x009
+#define SKS_CKM_AES_ECB_ENCRYPT_DATA		0x00a
+#define SKS_CKM_AES_CBC_ENCRYPT_DATA		0x00b
+#define SKS_CKM_AES_KEY_GEN			0x00c
+#define SKS_CKM_GENERIC_SECRET_KEY_GEN		0x00d
+#define SKS_CKM_MD5_HMAC			0x00e
+#define SKS_CKM_SHA_1_HMAC			0x00f
+#define SKS_CKM_SHA224_HMAC			0x010
+#define SKS_CKM_SHA256_HMAC			0x011
+#define SKS_CKM_SHA384_HMAC			0x012
+#define SKS_CKM_SHA512_HMAC			0x013
+#define SKS_CKM_AES_XCBC_MAC			0x014
+#define SKS_CKM_EC_KEY_PAIR_GEN			0x015
+#define SKS_CKM_ECDSA				0x016
+#define SKS_CKM_ECDSA_SHA1			0x017
+#define SKS_CKM_ECDSA_SHA224			0x018	/* /!\ CK !PKCS#11 */
+#define SKS_CKM_ECDSA_SHA256			0x019	/* /!\ CK !PKCS#11 */
+#define SKS_CKM_ECDSA_SHA384			0x01a	/* /!\ CK !PKCS#11 */
+#define SKS_CKM_ECDSA_SHA512			0x01b	/* /!\ CK !PKCS#11 */
+#define SKS_CKM_ECDH1_DERIVE			0x01c
+#define SKS_CKM_ECDH1_COFACTOR_DERIVE		0x01d
+#define SKS_CKM_ECMQV_DERIVE			0x01e
+#define SKS_CKM_ECDH_AES_KEY_WRAP		0x01f
+#define SKS_CKM_RSA_PKCS_KEY_PAIR_GEN		0x020
+#define SKS_CKM_RSA_PKCS			0x021
+#define SKS_CKM_RSA_9796			0x022
+#define SKS_CKM_RSA_X_509			0x023
+#define SKS_CKM_SHA1_RSA_PKCS			0x024
+#define SKS_CKM_RSA_PKCS_OAEP			0x025
+#define SKS_CKM_SHA1_RSA_PKCS_PSS		0x026
+#define SKS_CKM_SHA256_RSA_PKCS			0x027
+#define SKS_CKM_SHA384_RSA_PKCS			0x028
+#define SKS_CKM_SHA512_RSA_PKCS			0x029
+#define SKS_CKM_SHA256_RSA_PKCS_PSS		0x02a
+#define SKS_CKM_SHA384_RSA_PKCS_PSS		0x02b
+#define SKS_CKM_SHA512_RSA_PKCS_PSS		0x02c
+#define SKS_CKM_SHA224_RSA_PKCS			0x02d
+#define SKS_CKM_SHA224_RSA_PKCS_PSS		0x02e
+#define SKS_CKM_RSA_AES_KEY_WRAP		0x02f
+#define SKS_CKM_RSA_PKCS_PSS			0x030
+#define SKS_CKM_MD5				0x031
+#define SKS_CKM_SHA_1				0x032
+#define SKS_CKM_SHA224				0x033
+#define SKS_CKM_SHA256				0x034
+#define SKS_CKM_SHA384				0x035
+#define SKS_CKM_SHA512				0x036
+#define SKS_CKM_DH_PKCS_DERIVE			0x037
+#define SKS_CKM_DES_KEY_GEN			0x038
+#define SKS_CKM_DES_ECB				0x039
+#define SKS_CKM_DES_CBC				0x040
+#define SKS_CKM_DES_MAC				0x041
+#define SKS_CKM_DES_MAC_GENERAL			0x042
+#define SKS_CKM_DES_CBC_PAD			0x043
+#define SKS_CKM_EC_KEY_PAIR_IMPORT		0x044
+#define SKS_CKM_DUMP_LOG			0x045
+
+
+#define SKS_CKM_MTK_HSM_EXT			0x20000
+#define SKS_CKM_MTK_HSM_AES_ECB			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_AES_ECB)
+#define SKS_CKM_MTK_HSM_AES_CBC			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_AES_CBC)
+#define SKS_CKM_MTK_HSM_AES_CTR			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_AES_CTR)
+#define SKS_CKM_MTK_HSM_AES_GCM			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_AES_GCM)
+#define SKS_CKM_MTK_HSM_AES_CMAC		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_AES_CMAC)
+#define SKS_CKM_MTK_HSM_SHA256_HMAC		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_SHA256_HMAC)
+#define SKS_CKM_MTK_HSM_SHA384_HMAC		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_SHA384_HMAC)
+#define SKS_CKM_MTK_HSM_ECDSA			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_ECDSA)
+#define SKS_CKM_MTK_HSM_ECDSA_SHA1		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_ECDSA_SHA1)
+#define SKS_CKM_MTK_HSM_ECDSA_SHA224		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_ECDSA_SHA224)
+#define SKS_CKM_MTK_HSM_ECDSA_SHA256		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_ECDSA_SHA256)
+#define SKS_CKM_MTK_HSM_ECDSA_SHA384		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_ECDSA_SHA384)
+#define SKS_CKM_MTK_HSM_ECDSA_SHA512		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_ECDSA_SHA512)
+#define SKS_CKM_MTK_HSM_SHA1			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_SHA_1)
+#define SKS_CKM_MTK_HSM_SHA224			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_SHA224)
+#define SKS_CKM_MTK_HSM_SHA256			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_SHA256)
+#define SKS_CKM_MTK_HSM_SHA384			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_SHA384)
+#define SKS_CKM_MTK_HSM_SHA512			(SKS_CKM_MTK_HSM_EXT | SKS_CKM_SHA512)
+#define SKS_CKM_MTK_HSM_AES_KEY_GEN		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_AES_KEY_GEN)
+#define SKS_CKM_MTK_HSM_GENERIC_SECRET_KEY_GEN	(SKS_CKM_MTK_HSM_EXT | SKS_CKM_GENERIC_SECRET_KEY_GEN)
+#define SKS_CKM_MTK_HSM_EC_KEY_PAIR_GEN		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_EC_KEY_PAIR_GEN)
+#define SKS_CKM_MTK_HSM_EC_KEY_PAIR_IMPORT	(SKS_CKM_MTK_HSM_EXT | SKS_CKM_EC_KEY_PAIR_IMPORT)
+#define SKS_CKM_MTK_HSM_DUMP_LOG		(SKS_CKM_MTK_HSM_EXT | SKS_CKM_DUMP_LOG)
+
+/* SKS added IDs for operation without cryptoki mechanism ID defined */
+#define SKS_PROCESSING_IMPORT			0x1000
+#define SKS_PROCESSING_COPY			0x1001
+
+/*
+ * Valid values key differentiation function identifiers
+ * SKS_CKD_<x> reltaes to cryptoki CKD_<x>.
+ */
+#define SKS_CKD_NULL				0x0000UL
+#define SKS_CKD_SHA1_KDF			0x0001UL
+#define SKS_CKD_SHA1_KDF_ASN1			0x0002UL
+#define SKS_CKD_SHA1_KDF_CONCATENATE		0x0003UL
+#define SKS_CKD_SHA224_KDF			0x0004UL
+#define SKS_CKD_SHA256_KDF			0x0005UL
+#define SKS_CKD_SHA384_KDF			0x0006UL
+#define SKS_CKD_SHA512_KDF			0x0007UL
+#define SKS_CKD_CPDIVERSIFY_KDF			0x0008UL
+
+/*
+ * Valid values MG function identifiers
+ * SKS_CKG_<x> reltaes to cryptoki CKG_<x>.
+ */
+#define SKS_CKG_MGF1_SHA1			0x0001UL
+#define SKS_CKG_MGF1_SHA224			0x0005UL
+#define SKS_CKG_MGF1_SHA256			0x0002UL
+#define SKS_CKG_MGF1_SHA384			0x0003UL
+#define SKS_CKG_MGF1_SHA512			0x0004UL
+
+/*
+ * Valid values for RSA PKCS/OAEP source type identifier
+ * SKS_CKZ_<x> reltaes to cryptoki CKZ_<x>.
+ */
+#define SKS_CKZ_DATA_SPECIFIED			0x0001UL
+
+/*
+ * Processing parameters
+ *
+ * These can hardly be described by ANSI-C structures since the byte size of
+ * some fields of the structure are specified by a previous field in the
+ * structure. Therefore the format of the parameter binary data for each
+ * supported processing is defined here from this comment rather than using
+ * C structures.
+ *
+ * Processing parameters are used as argument the C_EncryptInit and friends
+ * using the struct sks_attribute_head format where field 'type' is the SKS
+ * processing ID and field 'size' is the parameter byte size. Below is shown
+ * the head structure struct sks_attribute_head fields and the trailling data
+ * that are the effective parameters binary blob for the target
+ * processing/mechanism.
+ *
+ * AES ECB
+ *   head:	32bit: type = SKS_CKM_AES_ECB
+ *		32bit: params byte size = 0
+ *
+ * AES CBC, CBC_NOPAD and CTS
+ *   head:	32bit: type = SKS_CKM_AES_CBC
+ *			  or SKS_CKM_AES_CBC_PAD
+ *			  or SKS_CKM_AES_CTS
+ *		32bit: params byte size = 16
+ *  params:	16byte: IV
+ *
+ * AES CTR, params relates to struct CK_AES_CTR_PARAMS.
+ *   head:	32bit: type = SKS_CKM_AES_CTR
+ *		32bit: params byte size = 20
+ *  params:	32bit: counter bit increment
+ *		16byte: IV
+ *
+ * AES GCM, params relates to struct CK_AES_GCM_PARAMS.
+ *   head:	32bit: type = SKS_CKM_AES_GCM
+ *		32bit: params byte size
+ *  params:	32bit: IV_byte_size
+ *		byte array: IV (IV_byte_size bytes)
+ *		32bit: AAD_byte_size
+ *		byte array: AAD data (AAD_byte_size bytes)
+ *		32bit: tag bit size
+ *
+ * AES CCM, params relates to struct CK_AES_CCM_PARAMS.
+ *   head:	32bit: type = SKS_CKM_AES_CCM
+ *		32bit: params byte size
+ *  params:	32bit: data_byte_size
+ *		32bit: nonce_byte_size
+ *		byte array: nonce data (nonce_byte_size bytes)
+ *		32bit: AAD_byte_size
+ *		byte array: AAD data (AAD_byte_size bytes)
+ *		32bit: MAC byte size
+ *
+ * AES GMAC
+ *   head:	32bit: type = SKS_CKM_AES_GMAC
+ *		32bit: params byte size = 12
+ *  params:	12byte: IV
+ *
+ * AES CMAC with general length, params relates to struct CK_MAC_GENERAL_PARAMS.
+ *   head:	32bit: type = SKS_CKM_AES_CMAC_GENERAL
+ *		32bit: params byte size = 12
+ *  params:	32bit: byte size of the output CMAC data
+ *
+ * AES CMAC fixed size (16byte CMAC)
+ *   head:	32bit: type = SKS_CKM_AES_CMAC_GENERAL
+ *		32bit: size = 0
+ *
+ * AES derive by ECB, params relates to struct CK_KEY_DERIVATION_STRING_DATA.
+ *   head:	32bit: type = SKS_CKM_AES_ECB_ENCRYPT_DATA
+ *		32bit: params byte size
+ *  params:	32bit: byte size of the data to encrypt
+ *		byte array: data to encrypt
+ *
+ * AES derive by CBC, params relates to struct CK_AES_CBC_ENCRYPT_DATA_PARAMS.
+ *   head:	32bit: type = SKS_CKM_AES_CBC_ENCRYPT_DATA
+ *		32bit: params byte size
+ *  params:	16byte: IV
+ *		32bit: byte size of the data to encrypt
+ *		byte array: data to encrypt
+ *
+ * AES and generic secret generation
+ *   head:	32bit: type = SKS_CKM_AES_KEY_GEN
+ *			   or SKS_CKM_GENERIC_SECRET_KEY_GEN
+ *		32bit: size = 0
+ *
+ * ECDH, params relates to struct CK_ECDH1_DERIVE_PARAMS.
+ *   head:	32bit: type = SKS_CKM_ECDH1_DERIVE
+ *			   or SKS_CKM_ECDH1_COFACTOR_DERIVE
+ *		32bit: params byte size
+ *  params:	32bit: key derivation function (SKS_CKD_xxx)
+ *		32bit: byte size of the shared data
+ *		byte array: shared data
+ *		32bit: byte: size of the public data
+ *		byte array: public data
+ *
+ * AES key wrap by ECDH, params relates to struct CK_ECDH_AES_KEY_WRAP_PARAMS.
+ *   head:	32bit: type = SKS_CKM_ECDH_AES_KEY_WRAP
+ *		32bit: params byte size
+ *  params:	32bit: bit size of the AES key
+ *		32bit: key derivation function (SKS_CKD_xxx)
+ *		32bit: byte size of the shared data
+ *		byte array: shared data
+ *
+ * RSA_PKCS (pre-hashed payload)
+ *   head:	32bit: type = SKS_CKM_RSA_PKCS
+ *		32bit: size = 0
+ *
+ * RSA PKCS OAEP, params relates to struct CK_RSA_PKCS_OAEP_PARAMS.
+ *   head:	32bit: type = SKS_CKM_RSA_PKCS_OAEP
+ *		32bit: params byte size
+ *  params:	32bit: hash algorithm identifier (SKS_CK_M_xxx)
+ *		32bit: CK_RSA_PKCS_MGF_TYPE
+ *		32bit: CK_RSA_PKCS_OAEP_SOURCE_TYPE
+ *		32bit: byte size of the source data
+ *		byte array: source data
+ *
+ * RSA PKCS PSS, params relates to struct CK_RSA_PKCS_PSS_PARAMS.
+ *   head:	32bit: type = SKS_CKM_RSA_PKCS_PSS
+ *			   or SKS_CKM_SHA256_RSA_PKCS_PSS
+ *			   or SKS_CKM_SHA384_RSA_PKCS_PSS
+ *			   or SKS_CKM_SHA512_RSA_PKCS_PSS
+ *		32bit: params byte size
+ *  params:	32bit: hash algorithm identifier (SKS_CK_M_xxx)
+ *		32bit: CK_RSA_PKCS_MGF_TYPE
+ *		32bit: byte size of the salt in the PSS encoding
+ *
+ * AES key wrapping by RSA, params relates to struct CK_RSA_AES_KEY_WRAP_PARAMS.
+ *   head:	32bit: type = CKM_RSA_AES_KEY_WRAP
+ *		32bit: params byte size
+ *  params:	32bit: bit size of the AES key
+ *		32bit: hash algorithm identifier (SKS_CK_M_xxx)
+ *		32bit: CK_RSA_PKCS_MGF_TYPE
+ *		32bit: CK_RSA_PKCS_OAEP_SOURCE_TYPE
+ *		32bit: byte size of the source data
+ *		byte array: source data
+ */
+
+#endif /*__SKS_TA_H__*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/system_event.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/system_event.h
new file mode 100644
index 0000000..79f9fa8
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/include/system_event.h
@@ -0,0 +1,81 @@
+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+

+#ifndef _SYSTEM_EVENT_H_

+#define _SYSTEM_EVENT_H_

+

+#include "processor.h"

+#include <stdint.h>

+

+#define MBOX_ENTRY_SIZE		16U

+#define MBOX_HEADER_SIZE	1U

+#define MBOX_DATA_SIZE		(MBOX_ENTRY_SIZE - MBOX_HEADER_SIZE)

+

+/* Puts SYSTEM EVENT ID */

+enum sys_event_id {

+	/* Please keep this on the top */

+	SYS_EVENT_MSG_ACK,

+

+	/* Please puts the events from here */

+	SYS_EVENT_CLI,

+	SYS_EVENT_CLI_REQ,

+

+	SYS_EVENT_CRY_AES_SHA,  // <-- Crypto event START

+	SYS_EVENT_CRY_ECC,

+	SYS_EVENT_CRY_TRNG,

+	SYS_EVENT_CANCEL_JOB,   // <-- Crypto event END

+

+	SYS_EVENT_JOB_MGMT,

+	SYS_EVENT_KEY_MANAGEMENT,

+	SYS_EVENT_HSM_CONTROL,

+

+	SYS_EVENT_CNT,

+};

+

+/* system management */

+struct sys_event {

+	uint8_t event_id;

+	enum CPU_SERIAL cpu_serial;

+	uint32_t priority;

+

+	union system_data {

+		uint32_t data[MBOX_DATA_SIZE];

+		/* Put your struct here */

+	} data;

+};

+

+#endif /* _SYSTEM_EVENT_H_ */

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/attributes.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/attributes.c
new file mode 100644
index 0000000..a6e9fcf
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/attributes.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <compiler.h>
+#include <sks_internal_abi.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string_ext.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <trace.h>
+#include <util.h>
+
+#include "attributes.h"
+#include "sks_helpers.h"
+#include "serializer.h"
+
+uint32_t init_attributes_head(struct sks_attrs_head **head)
+{
+	*head = TEE_Malloc(sizeof(struct sks_attrs_head), TEE_MALLOC_FILL_ZERO);
+	if (!*head)
+		return SKS_MEMORY;
+
+#ifdef SKS_SHEAD_WITH_TYPE
+	(*head)->class = SKS_UNDEFINED_ID;
+	(*head)->type = SKS_UNDEFINED_ID;
+#endif
+
+	return SKS_OK;
+}
+
+#if defined(SKS_SHEAD_WITH_TYPE) || defined(SKS_SHEAD_WITH_BOOLPROPS)
+static bool attribute_is_in_head(uint32_t attribute)
+{
+#ifdef SKS_SHEAD_WITH_TYPE
+	if (attribute == SKS_CKA_CLASS || sks_attr_is_type(attribute))
+		return true;
+#endif
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	if (sks_attr2boolprop_shift(attribute) >= 0)
+		return true;
+#endif
+
+	return false;
+}
+#endif
+
+uint32_t add_attribute(struct sks_attrs_head **head,
+			uint32_t attribute, void *data, size_t size)
+{
+	size_t buf_len = sizeof(struct sks_attrs_head) + (*head)->attrs_size;
+	uint32_t rv = 0;
+	uint32_t data32 = 0;
+	char **bstart = (void *)head;
+	int __maybe_unused shift = 0;
+
+#ifdef SKS_SHEAD_WITH_TYPE
+	if (attribute == SKS_CKA_CLASS || sks_attr_is_type(attribute)) {
+		assert(size == sizeof(uint32_t));
+
+		TEE_MemMove(attribute == SKS_CKA_CLASS ?
+				&(*head)->class : &(*head)->type,
+				data, sizeof(uint32_t));
+
+		return SKS_OK;
+	}
+#endif
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	shift = sks_attr2boolprop_shift(attribute);
+	if (head_contains_boolprops(*head) && shift >= 0) {
+		uint32_t mask = shift < 32 ? BIT(shift) : BIT(shift - 32);
+		uint32_t val = *(uint8_t *)data ? mask : 0;
+
+		if (size != sizeof(uint8_t)) {
+			EMSG("Invalid size %zu", size);
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		}
+
+		if (shift < 32)
+			(*head)->boolpropl = ((*head)->boolpropl & ~mask) | val;
+		else
+			(*head)->boolproph = ((*head)->boolproph & ~mask) | val;
+
+		return SKS_OK;
+	}
+#endif
+
+	data32 = attribute;
+	rv = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	data32 = size;
+	rv = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialize(bstart, &buf_len, data, size);
+	if (rv)
+		return rv;
+
+	/* Alloced buffer is always 64byte align, safe for us */
+	head = (void *)bstart;
+	(*head)->attrs_size += 2 * sizeof(uint32_t) + size;
+	(*head)->attrs_count++;
+
+	return rv;
+}
+
+uint32_t remove_attribute(struct sks_attrs_head **head, uint32_t attribute)
+{
+	struct sks_attrs_head *h = *head;
+	char *cur = NULL;
+	char *end = NULL;
+	size_t next_off = 0;
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	/* Can't remove an attribute that is defined in the head */
+	if (head_contains_boolprops(*head) && attribute_is_in_head(attribute)) {
+		EMSG("Can't remove attribute from the head");
+		return SKS_FAILED;
+	}
+#endif
+
+	/* Let's find the target attribute */
+	cur = (char *)h + sizeof(struct sks_attrs_head);
+	end = cur + h->attrs_size;
+	for (; cur < end; cur += next_off) {
+		struct sks_ref sks_ref;
+
+		TEE_MemMove(&sks_ref, cur, sizeof(sks_ref));
+		next_off = sizeof(sks_ref) + sks_ref.size;
+
+		if (sks_ref.id != attribute)
+			continue;
+
+		TEE_MemMove(cur, cur + next_off, end - (cur + next_off));
+
+		h->attrs_count--;
+		h->attrs_size -= next_off;
+		end -= next_off;
+		next_off = 0;
+		return SKS_OK;
+	}
+
+	DMSG("SKS_VALUE not found");
+	return SKS_NOT_FOUND;
+}
+
+uint32_t remove_attribute_check(struct sks_attrs_head **head, uint32_t attribute,
+				size_t max_check)
+{
+	struct sks_attrs_head *h = *head;
+	char *cur = NULL;
+	char *end = NULL;
+	size_t next_off = 0;
+	size_t found = 0;
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	/* Can't remove an attribute that is defined in the head */
+	if (head_contains_boolprops(*head) && attribute_is_in_head(attribute)) {
+		EMSG("Can't remove attribute from the head");
+		TEE_Panic(0);
+	}
+#endif
+
+	/* Let's find the target attribute */
+	cur = (char *)h + sizeof(struct sks_attrs_head);
+	end = cur + h->attrs_size;
+	for (; cur < end; cur += next_off) {
+		struct sks_ref sks_ref;
+
+		TEE_MemMove(&sks_ref, cur, sizeof(sks_ref));
+		next_off = sizeof(sks_ref) + sks_ref.size;
+
+		if (sks_ref.id != attribute)
+			continue;
+
+		found++;
+		if (found > max_check) {
+			DMSG("Too many attribute occurrences");
+			return SKS_FAILED;
+		}
+
+		TEE_MemMove(cur, cur + next_off, end - (cur + next_off));
+
+		h->attrs_count--;
+		h->attrs_size -= next_off;
+		end -= next_off;
+		next_off = 0;
+	}
+
+	/* sanity */
+	if (cur != end) {
+		EMSG("Bad end address");
+		return SKS_ERROR;
+	}
+
+	if (!found) {
+		EMSG("SKS_VALUE not found");
+		return SKS_FAILED;
+
+	}
+
+	return SKS_OK;
+}
+
+void get_attribute_ptrs(struct sks_attrs_head *head, uint32_t attribute,
+			void **attr, uint32_t *attr_size, size_t *count)
+{
+	char *cur = (char *)head + sizeof(struct sks_attrs_head);
+	char *end = cur + head->attrs_size;
+	size_t next_off = 0;
+	size_t max_found = *count;
+	size_t found = 0;
+	void **attr_ptr = attr;
+	uint32_t *attr_size_ptr = attr_size;
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	/* Can't return a pointer to a boolprop attribute */
+	if (head_contains_boolprops(head) && attribute_is_in_head(attribute)) {
+		EMSG("Can't get pointer to an attribute in the head");
+		TEE_Panic(0);
+	}
+#endif
+
+	for (; cur < end; cur += next_off) {
+		/* Structure aligned copy of the sks_ref in the object */
+		struct sks_ref sks_ref;
+
+		TEE_MemMove(&sks_ref, cur, sizeof(sks_ref));
+		next_off = sizeof(sks_ref) + sks_ref.size;
+
+		if (sks_ref.id != attribute)
+			continue;
+
+		found++;
+
+		if (!max_found)
+			continue;	/* only count matching attributes */
+
+		if (attr)
+			*attr_ptr++ = cur + sizeof(sks_ref);
+
+		if (attr_size)
+			*attr_size_ptr++ = sks_ref.size;
+
+		if (found == max_found)
+			break;
+	}
+
+	/* Sanity */
+	if (cur > end) {
+		DMSG("Exceeding serial object length");
+		TEE_Panic(0);
+	}
+
+	*count = found;
+}
+
+uint32_t get_attribute_ptr(struct sks_attrs_head *head, uint32_t attribute,
+			   void **attr_ptr, uint32_t *attr_size)
+{
+	size_t count = 1;
+
+#ifdef SKS_SHEAD_WITH_TYPE
+
+	if (attribute == SKS_CKA_CLASS) {
+		if (attr_size)
+			*attr_size = sizeof(uint32_t);
+		if (attr_ptr)
+			*attr_ptr = &head->class;
+
+		return SKS_OK;
+	}
+	if (attribute == SKS_CKA_KEY_TYPE) {
+		if (attr_size)
+			*attr_size = sizeof(uint32_t);
+		if (attr_ptr)
+			*attr_ptr = &head->type;
+
+		return SKS_OK;
+	}
+#endif
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	if (head_contains_boolprops(head) &&
+	    sks_attr2boolprop_shift(attribute) >= 0)
+		TEE_Panic(0);
+#endif
+
+	get_attribute_ptrs(head, attribute, attr_ptr, attr_size, &count);
+
+	if (!count)
+		return SKS_NOT_FOUND;
+
+	if (count != 1)
+		return SKS_ERROR;
+
+	return SKS_OK;
+}
+
+uint32_t get_attribute(struct sks_attrs_head *head, uint32_t attribute,
+			void *attr, uint32_t *attr_size)
+{
+	uint32_t rc = 0;
+	void *attr_ptr = NULL;
+	uint32_t size = 0;
+	uint8_t __maybe_unused bbool = 0;
+	int __maybe_unused shift = 0;
+
+#ifdef SKS_SHEAD_WITH_TYPE
+	if (attribute == SKS_CKA_CLASS) {
+		size = sizeof(uint32_t);
+		attr_ptr = &head->class;
+		goto found;
+	}
+
+	if (attribute == SKS_CKA_KEY_TYPE) {
+		size = sizeof(uint32_t);
+		attr_ptr = &head->type;
+		goto found;
+	}
+#endif
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	shift = sks_attr2boolprop_shift(attribute);
+	if (head_contains_boolprops(head) && shift >= 0) {
+		uint32_t *boolprop = NULL;
+
+		boolprop = (shift < 32) ? &head->boolpropl : &head->boolproph;
+		bbool = (*boolprop & (1 << (shift % 32))) ? SKS_TRUE : SKS_FALSE;
+
+		size = sizeof(uint8_t);
+		attr_ptr = &bbool;
+		goto found;
+	}
+#endif
+	rc = get_attribute_ptr(head, attribute, &attr_ptr, &size);
+	if (rc == SKS_OK)
+		goto found;
+
+	return rc;
+
+found:
+	if (attr_size && *attr_size != size) {
+		*attr_size = size;
+		/* This reuses buffer-to-small for any bad size matching */
+		return SKS_SHORT_BUFFER;
+	}
+
+	if (attr)
+		TEE_MemMove(attr, attr_ptr, size);
+
+	if (attr_size)
+		*attr_size = size;
+
+	return SKS_OK;
+}
+
+bool get_bool(struct sks_attrs_head *head, uint32_t attribute)
+{
+	uint32_t __maybe_unused rc = 0;
+	uint8_t bbool = 0;
+	uint32_t size = sizeof(bbool);
+	int __maybe_unused shift = 0;
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	shift = sks_attr2boolprop_shift(attribute);
+	if (shift < 0)
+		TEE_Panic(SKS_NOT_FOUND);
+
+	if (head_contains_boolprops(head)) {
+		if (shift > 31)
+			return head->boolproph & BIT(shift - 32);
+		else
+			return head->boolpropl & BIT(shift);
+	}
+#endif
+
+	rc = get_attribute(head, attribute, &bbool, &size);
+
+	if (rc == SKS_NOT_FOUND)
+		return false;
+
+	assert(rc == SKS_OK);
+	return !!bbool;
+}
+
+bool attributes_match_reference(struct sks_attrs_head *candidate,
+				struct sks_attrs_head *ref)
+{
+	size_t count = ref->attrs_count;
+	unsigned char *ref_attr = ref->attrs;
+	uint32_t rc = 0;
+
+	if (!ref->attrs_count) {
+		DMSG("Empty reference: no match");
+		return false;
+	}
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	/*
+	 * All boolprops attributes must be explicitly defined
+	 * as an attribute reference in the reference object.
+	 */
+	assert(!head_contains_boolprops(ref));
+#endif
+
+	for (count = 0; count < ref->attrs_count; count++) {
+		struct sks_ref sks_ref;
+		void *found = NULL;
+		uint32_t size = 0;
+		int shift = 0;
+
+		TEE_MemMove(&sks_ref, ref_attr, sizeof(sks_ref));
+
+		shift = sks_attr2boolprop_shift(sks_ref.id);
+		if (shift >= 0) {
+
+			bool bb_ref = get_bool(ref, sks_ref.id);
+			bool bb_candidate = get_bool(candidate, sks_ref.id);
+
+			if (bb_ref != bb_candidate) {
+				return false;
+			}
+		} else {
+			rc = get_attribute_ptr(candidate, sks_ref.id,
+					       &found, &size);
+
+			if (rc || !found || size != sks_ref.size ||
+			    TEE_MemCompare(ref_attr + sizeof(sks_ref),
+					   found, size)) {
+				return false;
+			}
+		}
+
+		ref_attr += sizeof(sks_ref) + sks_ref.size;
+	}
+
+	return true;
+}
+
+/*
+ * Debug: dump CK attribute array to output trace
+ */
+#define ATTR_TRACE_FMT	"%s attr %s / %s\t(0x%04" PRIx32 " %" PRIu32 "-byte"
+#define ATTR_FMT_0BYTE	ATTR_TRACE_FMT ")"
+#define ATTR_FMT_1BYTE	ATTR_TRACE_FMT ": %02x)"
+#define ATTR_FMT_2BYTE	ATTR_TRACE_FMT ": %02x %02x)"
+#define ATTR_FMT_3BYTE	ATTR_TRACE_FMT ": %02x %02x %02x)"
+#define ATTR_FMT_4BYTE	ATTR_TRACE_FMT ": %02x %02x %02x %02x)"
+#define ATTR_FMT_ARRAY	ATTR_TRACE_FMT ": %02x %02x %02x %02x ...)"
+
+static uint32_t __trace_attributes(char *prefix, void *src, void *end)
+{
+	size_t next_off = 0;
+	char *prefix2 = NULL;
+	size_t prefix_len = strlen(prefix);
+	char *cur = src;
+
+	/* append 4 spaces to the prefix plus terminal '\0' */
+	prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
+	if (!prefix2)
+		return SKS_MEMORY;
+
+	TEE_MemMove(prefix2, prefix, prefix_len + 1);
+	TEE_MemFill(prefix2 + prefix_len, ' ', 4);
+	*(prefix2 + prefix_len + 4) = '\0';
+
+	for (; cur < (char *)end; cur += next_off) {
+		struct sks_ref sks_ref;
+		uint8_t data[4] = { 0 };
+
+		TEE_MemMove(&sks_ref, cur, sizeof(sks_ref));
+		TEE_MemMove(&data[0], cur + sizeof(sks_ref),
+			    MIN(sks_ref.size, sizeof(data)));
+
+		next_off = sizeof(sks_ref) + sks_ref.size;
+
+		switch (sks_ref.size) {
+		case 0:
+			IMSG_RAW(ATTR_FMT_0BYTE,
+				 prefix, sks2str_attr(sks_ref.id), "*",
+				 sks_ref.id, sks_ref.size);
+			break;
+		case 1:
+			IMSG_RAW(ATTR_FMT_1BYTE,
+				 prefix, sks2str_attr(sks_ref.id),
+				 sks2str_attr_value(sks_ref.id, sks_ref.size,
+						    cur + sizeof(sks_ref)),
+				 sks_ref.id, sks_ref.size, data[0]);
+			break;
+		case 2:
+			IMSG_RAW(ATTR_FMT_2BYTE,
+				 prefix, sks2str_attr(sks_ref.id),
+				 sks2str_attr_value(sks_ref.id, sks_ref.size,
+						    cur + sizeof(sks_ref)),
+				 sks_ref.id, sks_ref.size, data[0], data[1]);
+			break;
+		case 3:
+			IMSG_RAW(ATTR_FMT_3BYTE,
+				 prefix, sks2str_attr(sks_ref.id),
+				 sks2str_attr_value(sks_ref.id, sks_ref.size,
+						    cur + sizeof(sks_ref)),
+				 sks_ref.id, sks_ref.size,
+				 data[0], data[1], data[2]);
+			break;
+		case 4:
+			IMSG_RAW(ATTR_FMT_4BYTE,
+				 prefix, sks2str_attr(sks_ref.id),
+				 sks2str_attr_value(sks_ref.id, sks_ref.size,
+						    cur + sizeof(sks_ref)),
+				 sks_ref.id, sks_ref.size,
+				 data[0], data[1], data[2], data[3]);
+			break;
+		default:
+			IMSG_RAW(ATTR_FMT_ARRAY,
+				 prefix, sks2str_attr(sks_ref.id),
+				 sks2str_attr_value(sks_ref.id, sks_ref.size,
+						    cur + sizeof(sks_ref)),
+				 sks_ref.id, sks_ref.size,
+				 data[0], data[1], data[2], data[3]);
+			break;
+		}
+
+		switch (sks_ref.id) {
+		case SKS_CKA_WRAP_TEMPLATE:
+		case SKS_CKA_UNWRAP_TEMPLATE:
+		case SKS_CKA_DERIVE_TEMPLATE:
+			trace_attributes(prefix2,
+					 (void *)(cur + sizeof(sks_ref)));
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Sanity */
+	if (cur != (char *)end) {
+		EMSG("Warning: unexpected alignment in object attributes");
+	}
+
+	TEE_Free(prefix2);
+	return SKS_OK;
+}
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+static void trace_boolprops(const char *prefix, struct sks_attrs_head *head)
+{
+	size_t __maybe_unused n = 0;
+
+	for (n = 0; n <= SKS_BOOLPROPS_LAST; n++) {
+		bool bp = n < 32 ? !!(head->boolpropl & BIT(n)) :
+				 !!(head->boolproph & BIT(n - 32));
+
+		IMSG_RAW("%s| attr %s / %s (0x%" PRIx32 ")",
+			 prefix, sks2str_attr(n), bp ? "TRUE" : "FALSE", n);
+	}
+}
+#endif
+
+uint32_t trace_attributes(const char *prefix, void *ref)
+{
+	struct sks_attrs_head head;
+	char *pre = NULL;
+	uint32_t rc = 0;
+	size_t __maybe_unused n = 0;
+
+	TEE_MemMove(&head, ref, sizeof(head));
+
+	pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
+	if (!pre)
+		return SKS_MEMORY;
+	if (prefix)
+		TEE_MemMove(pre, prefix, strlen(prefix));
+
+	IMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
+	IMSG_RAW("%s| %" PRIu32 " item(s) - %" PRIu32 " bytes",
+		pre, head.attrs_count, head.attrs_size);
+#ifdef SKS_SHEAD_WITH_TYPE
+	IMSG_RAW("%s| class (0x%" PRIx32 ") %s type (0x%" PRIx32 ") %s",
+		 pre, head.class, sks2str_class(head.class),
+		 head.type, sks2str_type(head.type, head.class));
+#endif
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	if (head_contains_boolprops(&head))
+		trace_boolprops(pre, &head);
+#endif
+
+	pre[prefix ? strlen(prefix) : 0] = '|';
+	rc = __trace_attributes(pre, (char *)ref + sizeof(head),
+			        (char *)ref + sizeof(head) + head.attrs_size);
+	if (rc)
+		goto bail;
+
+	IMSG_RAW("%s`-----------------------", prefix ? prefix : "");
+
+bail:
+	TEE_Free(pre);
+	return rc;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/attributes.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/attributes.h
new file mode 100644
index 0000000..f602c3e
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/attributes.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __ATTRIBUTES_H
+#define __ATTRIBUTES_H
+
+#include <assert.h>
+#include <sks_internal_abi.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "sks_helpers.h"
+
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+static inline void set_attributes_in_head(struct sks_attrs_head *head)
+{
+	head->boolproph |= SKS_BOOLPROPH_FLAG;
+}
+
+static inline bool head_contains_boolprops(struct sks_attrs_head __unused *head)
+{
+	return head->boolproph & SKS_BOOLPROPH_FLAG;
+}
+#endif
+
+/*
+ * Allocation a reference for a serialized attributes.
+ * Can be freed from a simple TEE_Free(reference);
+ *
+ * Return a SKS_OK on success or a SKS return code.
+ */
+uint32_t init_attributes_head(struct sks_attrs_head **head);
+
+/*
+ * Update serialized attributes to add an entry. Can relocate the attribute
+ * list buffer.
+ *
+ * Return a SKS_OK on success or a SKS return code.
+ */
+uint32_t add_attribute(struct sks_attrs_head **head,
+			uint32_t attribute, void *data, size_t size);
+
+/*
+ * Update serialized attributes to remove an entry. Can relocate the attribute
+ * list buffer. Only 1 instance of the entry is expected (TODO factory with _check)
+ *
+ * Return a SKS_OK on success or a SKS return code.
+ */
+uint32_t remove_attribute(struct sks_attrs_head **head, uint32_t attrib);
+
+/*
+ * Update serialized attributes to remove an entry. Can relocate the attribute
+ * list buffer. If attribute ID is find several times, remove all of them.
+ *
+ * Return a SKS_OK on success or a SKS return code.
+ */
+uint32_t remove_attribute_check(struct sks_attrs_head **head, uint32_t attribute,
+				size_t max_check);
+
+/*
+ * If *count == 0, count and return in *count the number of attributes matching
+ * the input attribute ID.
+ *
+ * If *count != 0, return the address and size of the attributes found, up to
+ * the occurrence number *count. attr and attr_size and expected large
+ * enough. attr is the output array of the values found. attr_size is the
+ * output array of the size of each values found.
+ *
+ * If attr_size != NULL, return in in *attr_size attribute value size.
+ * If attr != NULL return in *attr the address in memory of the attribute value.
+ */
+void get_attribute_ptrs(struct sks_attrs_head *head, uint32_t attribute,
+			void **attr, uint32_t *attr_size, size_t *count);
+
+/*
+ * If attributes is not found return SKS_NOT_FOUND.
+ * If attr_size != NULL, return in in *attr_size attribute value size.
+ * If attr != NULL return in *attr the address in memory of the attribute value.
+ *
+ * Return a SKS_OK or SKS_NOT_FOUND on success, or a SKS return code.
+ */
+uint32_t get_attribute_ptr(struct sks_attrs_head *head, uint32_t attribute,
+			   void **attr_ptr, uint32_t *attr_size);
+/*
+ * If attribute is not found, return SKS_NOT_FOUND.
+ * If attr_size != NULL, check *attr_size matches attributes size of return
+ * SKS_SHORT_BUFFER with expected size in *attr_size.
+ * If attr != NULL and attr_size is NULL or gives expected buffer size,
+ * copy attribute value into attr.
+ *
+ * Return a SKS_OK or SKS_NOT_FOUND on success, or a SKS return code.
+ */
+uint32_t get_attribute(struct sks_attrs_head *head, uint32_t attribute,
+			void *attr, uint32_t *attr_size);
+
+static inline uint32_t get_u32_attribute(struct sks_attrs_head *head,
+					 uint32_t attribute, uint32_t *attr)
+{
+	uint32_t size = sizeof(uint32_t);
+	uint32_t rv = get_attribute(head, attribute, attr, &size);
+
+	if (size != sizeof(uint32_t))
+		return SKS_ERROR;
+
+	return rv;
+}
+
+/*
+ * Return true all attributes from the reference are found and match value
+ * in the candidate attribute list.
+ *
+ * Return a SKS_OK on success, or a SKS return code.
+ */
+bool attributes_match_reference(struct sks_attrs_head *ref,
+				struct sks_attrs_head *candidate);
+
+/*
+ * Some helpers
+ */
+static inline size_t attributes_size(struct sks_attrs_head *head)
+{
+	return sizeof(struct sks_attrs_head) + head->attrs_size;
+}
+
+#ifdef SKS_SHEAD_WITH_TYPE
+static inline uint32_t get_class(struct sks_attrs_head *head)
+{
+	return head->class;
+}
+
+static inline uint32_t get_type(struct sks_attrs_head *head)
+{
+	return head->type;
+}
+#else
+static inline uint32_t get_class(struct sks_attrs_head *head)
+{
+	uint32_t class;
+	uint32_t size = sizeof(class);
+
+	if (get_attribute(head, SKS_CKA_CLASS, &class, &size))
+		return SKS_UNDEFINED_ID;
+
+	return class;
+}
+static inline uint32_t get_type(struct sks_attrs_head *head)
+{
+	uint32_t type;
+	uint32_t size = sizeof(type);
+
+	if (get_attribute(head, SKS_CKA_KEY_TYPE, &type, &size))
+		return SKS_UNDEFINED_ID;
+
+	return type;
+}
+#endif
+
+bool get_bool(struct sks_attrs_head *head, uint32_t attribute);
+
+/* Debug: dump object attributes to IMSG() trace console */
+uint32_t trace_attributes(const char *prefix, void *ref);
+
+#endif /*__ATTRIBUTES_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/entry.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/entry.c
new file mode 100644
index 0000000..ea0f035
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/entry.c
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#include <compiler.h>
+#include <sks_ta.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+
+#include "handle.h"
+#include "object.h"
+#include "pkcs11_token.h"
+#include "processing.h"
+#include "sks_helpers.h"
+
+#include "processing_mtk_key.h"
+
+/* Client session context: currently only use the allocated address */
+struct tee_session {
+	int foo;
+};
+
+
+TEE_Result TA_CreateEntryPoint(void)
+{
+	if (pkcs11_init())
+		return TEE_ERROR_SECURITY;
+
+	mtk_rebuild_key_table();
+
+	return TEE_SUCCESS;
+}
+
+void TA_DestroyEntryPoint(void)
+{
+	pkcs11_deinit();
+}
+
+TEE_Result TA_OpenSessionEntryPoint(uint32_t __unused param_types,
+				    TEE_Param __unused params[4],
+				    void **tee_session)
+{
+	uintptr_t client = register_client();
+
+	if (!client)
+		return TEE_ERROR_OUT_OF_MEMORY;
+
+	*tee_session = (void *)client;
+
+	return TEE_SUCCESS;
+}
+
+void TA_CloseSessionEntryPoint(void *tee_session)
+{
+	unregister_client((uintptr_t)tee_session);
+}
+
+static uint32_t entry_ping(TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t *ver = NULL;
+
+	if (ctrl || in)
+		return SKS_BAD_PARAM;
+
+	if (!out)
+		return SKS_OK;
+
+	if (out->memref.size < 2 * sizeof(uint32_t))
+		return SKS_SHORT_BUFFER;
+
+	if ((uintptr_t)out->memref.buffer & 0x03UL)
+		return SKS_BAD_PARAM;
+
+	ver = (uint32_t *)out->memref.buffer;
+	*ver = SKS_VERSION_ID0;
+	*(ver + 1) = SKS_VERSION_ID1;
+
+	return SKS_OK;
+}
+
+
+/*
+ * Entry point for SKS TA commands
+ *
+ * ABI: param#0 is the control buffer with serialized arguments.
+ *	param#1 is an input/output data buffer
+ *	param#2 is an input/output data buffer (also used to return handles)
+ *	param#3 is not used
+ *
+ * Param#0 ctrl, if defined is an in/out buffer, is used to send back to
+ * the client a Cryptoki status ID that supersedes the TEE result code which
+ * will be force to TEE_SUCCESS. Note that some Cryptoki error status are
+ * sent straight through TEE result code. See sks2tee_noerr().
+ */
+TEE_Result TA_InvokeCommandEntryPoint(void *tee_session, uint32_t cmd,
+				      uint32_t ptypes,
+				      TEE_Param params[TEE_NUM_PARAMS])
+{
+	TEE_Param *ctrl = NULL;
+	TEE_Param *p1_in = NULL;
+	TEE_Param __maybe_unused *p1_out = NULL;
+	TEE_Param *p2_in = NULL;
+	TEE_Param *p2_out = NULL;
+	uintptr_t teesess = (uintptr_t)tee_session;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t rc = 0;
+
+	/* param#0: input buffer with request serialized arguments */
+	switch (TEE_PARAM_TYPE_GET(ptypes, 0)) {
+	case TEE_PARAM_TYPE_NONE:
+		break;
+	case TEE_PARAM_TYPE_MEMREF_INPUT:
+	case TEE_PARAM_TYPE_MEMREF_INOUT:
+		ctrl = &params[0];
+		break;
+	default:
+		goto bad_types;
+	}
+
+	/* param#1: input data buffer */
+	switch (TEE_PARAM_TYPE_GET(ptypes, 1)) {
+	case TEE_PARAM_TYPE_NONE:
+		break;
+	case TEE_PARAM_TYPE_MEMREF_INPUT:
+		p1_in = &params[1];
+		break;
+	case TEE_PARAM_TYPE_MEMREF_OUTPUT:
+		p1_out = &params[1];
+		break;
+	case TEE_PARAM_TYPE_MEMREF_INOUT:
+		p1_in = &params[1];
+		p1_out = &params[1];
+		break;
+	default:
+		goto bad_types;
+	}
+
+	/* param#2: input or output data buffer */
+	switch (TEE_PARAM_TYPE_GET(ptypes, 2)) {
+	case TEE_PARAM_TYPE_NONE:
+		break;
+	case TEE_PARAM_TYPE_MEMREF_INPUT:
+		p2_in = &params[2];
+		break;
+	case TEE_PARAM_TYPE_MEMREF_OUTPUT:
+		p2_out = &params[2];
+		break;
+	case TEE_PARAM_TYPE_MEMREF_INOUT:
+		p2_in = &params[2];
+		p2_out = &params[2];
+		break;
+	default:
+		goto bad_types;
+	}
+
+	/* param#3: unused */
+	switch (TEE_PARAM_TYPE_GET(ptypes, 3)) {
+	case TEE_PARAM_TYPE_NONE:
+		break;
+	default:
+		goto bad_types;
+	}
+
+	DMSG("%s ctrl %" PRIu32 "@%p, %s %" PRIu32 "@%p, %s %" PRIu32 "@%p",
+		sks2str_skscmd(cmd),
+		ctrl ? ctrl->memref.size : 0, ctrl ? ctrl->memref.buffer : 0,
+		p1_out ? "out" : (p1_in ? "in" : "---"),
+		p1_out ? p1_out->memref.size : (p1_in ? p1_in->memref.size : 0),
+		p1_out ? p1_out->memref.buffer :
+			(p1_in ? p1_in->memref.buffer : NULL),
+		p2_out ? "out" : (p2_in ? "in" : "---"),
+		p2_out ? p2_out->memref.size : (p2_in ? p2_in->memref.size : 0),
+		p2_out ? p2_out->memref.buffer :
+			(p2_in ? p2_in->memref.buffer : NULL));
+
+	switch (cmd) {
+	case SKS_CMD_PING:
+		rc = entry_ping(ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_CK_SLOT_LIST:
+		rc = entry_ck_slot_list(ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_CK_SLOT_INFO:
+		rc = entry_ck_slot_info(ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_CK_TOKEN_INFO:
+		rc = entry_ck_token_info(ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_CK_INIT_TOKEN:
+		rc = entry_ck_token_initialize(ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_CK_MECHANISM_IDS:
+		rc = entry_ck_token_mecha_ids(ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_CK_MECHANISM_INFO:
+		rc = entry_ck_token_mecha_info(ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_CK_OPEN_RO_SESSION:
+		rc = entry_ck_token_ro_session(teesess, ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_CK_OPEN_RW_SESSION:
+		rc = entry_ck_token_rw_session(teesess, ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_CK_CLOSE_SESSION:
+		rc = entry_ck_token_close_session(teesess, ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_CK_CLOSE_ALL_SESSIONS:
+		rc = entry_ck_token_close_all(teesess, ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_CK_SESSION_INFO:
+		rc = entry_ck_token_session_info(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_IMPORT_OBJECT:
+		rc = entry_import_object(teesess, ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_DESTROY_OBJECT:
+		rc = entry_destroy_object(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_DIGEST_INIT:
+		rc = entry_digesting_init(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_DIGEST);
+		break;
+
+	case SKS_CMD_DIGEST_UPDATE:
+		rc = entry_digesting_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_DIGEST,
+					   SKS_FUNC_STEP_UPDATE);
+		break;
+
+	case SKS_CMD_DIGEST_ONESHOT:
+		rc = entry_digesting_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_DIGEST,
+					   SKS_FUNC_STEP_ONESHOT);
+		break;
+
+	case SKS_CMD_DIGEST_FINAL:
+		rc = entry_digesting_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_DIGEST,
+					   SKS_FUNC_STEP_FINAL);
+		break;
+
+	case SKS_CMD_ENCRYPT_INIT:
+		rc = entry_processing_init(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_ENCRYPT);
+		break;
+	case SKS_CMD_DECRYPT_INIT:
+		rc = entry_processing_init(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_DECRYPT);
+		break;
+	case SKS_CMD_ENCRYPT_UPDATE:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_ENCRYPT,
+					   SKS_FUNC_STEP_UPDATE);
+		break;
+	case SKS_CMD_DECRYPT_UPDATE:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_DECRYPT,
+					   SKS_FUNC_STEP_UPDATE);
+		break;
+	case SKS_CMD_ENCRYPT_ONESHOT:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_ENCRYPT,
+					   SKS_FUNC_STEP_ONESHOT);
+		break;
+	case SKS_CMD_DECRYPT_ONESHOT:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_DECRYPT,
+					   SKS_FUNC_STEP_ONESHOT);
+		break;
+	case SKS_CMD_ENCRYPT_FINAL:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_ENCRYPT,
+					   SKS_FUNC_STEP_FINAL);
+		break;
+	case SKS_CMD_DECRYPT_FINAL:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_DECRYPT,
+					   SKS_FUNC_STEP_FINAL);
+		break;
+
+	case SKS_CMD_GENERATE_SYMM_KEY:
+		rc = entry_generate_secret(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_SIGN_INIT:
+		rc = entry_processing_init(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_SIGN);
+		break;
+	case SKS_CMD_VERIFY_INIT:
+		rc = entry_processing_init(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_VERIFY);
+		break;
+	case SKS_CMD_SIGN_ONESHOT:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_SIGN,
+					   SKS_FUNC_STEP_ONESHOT);
+		break;
+	case SKS_CMD_VERIFY_ONESHOT:
+		rc = entry_verify_oneshot(teesess, ctrl, p1_in, p2_in,
+					   SKS_FUNCTION_VERIFY,
+					   SKS_FUNC_STEP_ONESHOT);
+		break;
+	case SKS_CMD_SIGN_UPDATE:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_SIGN,
+					   SKS_FUNC_STEP_UPDATE);
+		break;
+	case SKS_CMD_VERIFY_UPDATE:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_VERIFY,
+					   SKS_FUNC_STEP_UPDATE);
+		break;
+	case SKS_CMD_SIGN_FINAL:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_SIGN,
+					   SKS_FUNC_STEP_FINAL);
+		break;
+	case SKS_CMD_VERIFY_FINAL:
+		rc = entry_processing_step(teesess, ctrl, p1_in, p2_out,
+					   SKS_FUNCTION_VERIFY,
+					   SKS_FUNC_STEP_FINAL);
+		break;
+
+	case SKS_CMD_FIND_OBJECTS_INIT:
+		rc = entry_find_objects_init(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_FIND_OBJECTS:
+		rc = entry_find_objects(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_FIND_OBJECTS_FINAL:
+		rc = entry_find_objects_final(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_GET_OBJECT_SIZE:
+		rc = entry_get_object_size(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_GET_ATTRIBUTE_VALUE:
+		rc = entry_get_attribute_value(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_INIT_PIN:
+		rc = entry_init_pin(teesess, ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_SET_PIN:
+		rc = entry_set_pin(teesess, ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_LOGIN:
+		rc = entry_login(teesess, ctrl, p1_in, p2_out);
+		break;
+	case SKS_CMD_LOGOUT:
+		rc = entry_logout(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_GENERATE_KEY_PAIR:
+		rc = entry_generate_key_pair(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_DERIVE_KEY:
+		rc = entry_derive_key(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_GENERATE_RANDOM:
+		rc = entry_generate_random(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_IMPORT_KEY:
+		rc = entry_import_key(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_IMPORT_KEY_PAIR:
+		rc = entry_import_key_pair(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_EXPORT_KEY:
+		rc = entry_export_key_pair(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	case SKS_CMD_UTILS:
+		rc = entry_utils(teesess, ctrl, p1_in, p2_out);
+		break;
+
+	default:
+		EMSG("Command ID 0x%x is not supported", cmd);
+		return TEE_ERROR_NOT_SUPPORTED;
+	}
+
+	if (TEE_PARAM_TYPE_GET(ptypes, 0) == TEE_PARAM_TYPE_MEMREF_INOUT &&
+	    ctrl->memref.size >= sizeof(uint32_t) &&
+	    !((uintptr_t)ctrl->memref.buffer & 0x03UL)) {
+
+		TEE_MemMove(ctrl->memref.buffer, &rc, sizeof(uint32_t));
+		ctrl->memref.size = sizeof(uint32_t);
+
+		res = sks2tee_noerr(rc);
+
+		DMSG("SKS TA exit: %s rc 0x%08" PRIx32 "/%s",
+			sks2str_skscmd(cmd), rc, sks2str_rc(rc));
+	} else {
+		res = sks2tee_error(rc);
+		DMSG("SKS TA exit: %s rc 0x%08" PRIx32 "/%s, TEE rc %" PRIx32,
+			sks2str_skscmd(cmd), rc, sks2str_rc(rc), res);
+	}
+
+	return res;
+
+bad_types:
+	DMSG("Bad parameter types used at SKS TA entry:");
+	DMSG("- parameter #0: formatted input request buffer or none");
+	DMSG("- parameter #1: processed input data buffer or none");
+	DMSG("- parameter #2: processed output data buffer or none");
+	DMSG("- parameter #3: none");
+	return TEE_ERROR_BAD_PARAMETERS;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/handle.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/handle.c
new file mode 100644
index 0000000..045989e
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/handle.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <stdlib.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+
+#include "handle.h"
+
+/*
+ * Define the initial capacity of the database. It should be a low number
+ * multiple of 2 since some databases a likely to only use a few handles.
+ * Since the algorithm is to doubles up when growing it shouldn't cause a
+ * noticeable overhead on large databases.
+ */
+#define HANDLE_DB_INITIAL_MAX_PTRS	4
+
+void handle_db_init(struct handle_db *db)
+{
+	TEE_MemFill(db, 0, sizeof(*db));
+}
+
+void handle_db_destroy(struct handle_db *db)
+{
+	if (db) {
+		TEE_Free(db->ptrs);
+		db->ptrs = NULL;
+		db->max_ptrs = 0;
+	}
+}
+
+uint32_t handle_get(struct handle_db *db, void *ptr)
+{
+	uint32_t n = 0;
+	void *p = NULL;
+	uint32_t new_max_ptrs = 0;
+
+	if (!db || !ptr)
+		return 0;
+
+	/* Try to find an empty location (index 0 is reserved as invalid) */
+	for (n = 1; n < db->max_ptrs; n++) {
+		if (!db->ptrs[n]) {
+			db->ptrs[n] = ptr;
+			return n;
+		}
+	}
+
+	/* No location available, grow the ptrs array */
+	if (db->max_ptrs)
+		new_max_ptrs = db->max_ptrs * 2;
+	else
+		new_max_ptrs = HANDLE_DB_INITIAL_MAX_PTRS;
+
+	if (new_max_ptrs > SIZE_MAX/sizeof(void *))
+		return 0;
+
+	p = TEE_Realloc(db->ptrs, new_max_ptrs * sizeof(void *));
+	if (!p)
+		return 0;
+	db->ptrs = p;
+	TEE_MemFill(db->ptrs + db->max_ptrs, 0,
+		    (new_max_ptrs - db->max_ptrs) * sizeof(void *));
+	db->max_ptrs = new_max_ptrs;
+
+	/* Since n stopped at db->max_ptrs there is an empty location there */
+	db->ptrs[n] = ptr;
+	return n;
+}
+
+void *handle_put(struct handle_db *db, uint32_t handle)
+{
+	void *p = NULL;
+
+	if (!db || !handle || handle >= db->max_ptrs)
+		return NULL;
+
+	p = db->ptrs[handle];
+	db->ptrs[handle] = NULL;
+	return p;
+}
+
+void *handle_lookup(struct handle_db *db, uint32_t handle)
+{
+	if (!db || !handle || handle >= db->max_ptrs)
+		return NULL;
+
+	return db->ptrs[handle];
+}
+
+uint32_t handle_lookup_handle(struct handle_db *db, void *ptr)
+{
+	uint32_t n = 0;
+
+	if (ptr) {
+		for (n = 1; n < db->max_ptrs; n++) {
+			if (db->ptrs[n] == ptr) {
+				return n;
+			}
+		}
+	}
+
+	return 0;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/handle.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/handle.h
new file mode 100644
index 0000000..8ba4726
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/handle.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __HANDLE_H
+#define __HANDLE_H
+
+#include <stddef.h>
+
+struct handle_db {
+	void **ptrs;
+	uint32_t max_ptrs;
+};
+
+#define HANDLE_DB_INITIALIZER { NULL, 0 }
+
+/*
+ * Initialize the handle database
+ */
+void handle_db_init(struct handle_db *db);
+
+/*
+ * Free all internal data structures of the database, but does not free
+ * the db pointer. The database is safe to reuse after it's destroyed, it
+ * just be empty again.
+ */
+void handle_db_destroy(struct handle_db *db);
+
+/*
+ * Allocate a new handle and assigns the supplied pointer to it,
+ * ptr must not be NULL.
+ * The function returns
+ * >= 0 on success and
+ * -1 on failure
+ */
+uint32_t handle_get(struct handle_db *db, void *ptr);
+
+/*
+ * Deallocate a handle. Returns the associated pointer of the handle
+ * the the handle was valid or NULL if it's invalid.
+ */
+void *handle_put(struct handle_db *db, uint32_t handle);
+
+/*
+ * Return the associated pointer of the handle if the handle is a valid
+ * handle.
+ * Returns NULL on failure.
+ */
+void *handle_lookup(struct handle_db *db, uint32_t handle);
+
+/* Return the handle associated to a pointer if found, else return 0 */
+uint32_t handle_lookup_handle(struct handle_db *db, void *ptr);
+
+#endif /*__HANDLE_H*/
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/mtk_key.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/mtk_key.h
new file mode 100644
index 0000000..9c9de1d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/mtk_key.h
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#ifndef __MTK_KEY_H__
+#define __MTK_KEY_H__
+
+#include <stdint.h>
+
+// #define PTA_GPT_TEST_PTA_UUID { 0x472567ad, 0xa180, 0x402c, \
+// 			{ 0x50, 0x95, 0x7b, 0x4e, 0xd3, 0xe0, 0x5e, 0x83 } }
+
+#define PTA_MBOX_UUID {0x598e9628, 0xf233, 0x4c83, {0x8d, 0x4c, 0xbd, 0x2f, 0x0a, 0xd4, 0xb2, 0xe4}}
+
+/* command IDs to PTA */
+#define PTA_CMD_HSM_GEN_KEY_PAIR        1
+#define PTA_CMD_HSM_GEN_SYMM_KEY        2
+#define PTA_CMD_HSM_GET_KEY_BLOB        3
+#define PTA_CMD_HSM_GET_KEY_TABLE       4
+#define PTA_CMD_HSM_REBUILD_KEY_TABLE   5
+#define PTA_CMD_HSM_REBUILD_KEY_BLOB    6
+#define PTA_CMD_HSM_IMPORT_KEY          7
+#define PTA_CMD_HSM_EXPORT_KEY          8
+#define PTA_CMD_HSM_SEND_JOB            9
+#define PTA_CMD_HSM_DUMP_LOG           10
+#define PTA_CMD_HSM_DELETE_KEY         11
+
+/* The return value of key management in HSM */
+#define KM_OK                               (0)
+#define KM_FAIL                            (-1)
+#define KM_ERROR_BAD_ARGUMENTS             (-2)
+#define KM_ERROR_GET_SLOT_FAIL             (-3)
+#define KM_ERROR_RESOURCE_ALLOCATE_FAIL    (-4)
+#define KM_ERROR_DEBLOB_FAIL               (-5)
+#define KM_ERROR_ENBLOB_FAIL               (-6)
+#define KM_ERROR_INVALID_CURVE             (-7)
+#define KM_ERROR_UECC_FAIL                 (-8)
+#define KM_ERROR_SET_KEY_FAIL              (-9)
+#define KM_ERROR_GET_KEY_FAIL             (-10)
+#define KM_ERROR_INTERNAL_ERROR           (-11)
+#define KM_ERROR_INVALID_ECC_KEY_PAIR     (-12)
+
+#define MAX_KEY_NUMS (25)
+
+#define KEY_ALGO_ID_AES    1
+#define KEY_ALGO_ID_ECC    2
+
+#define MAX_BLOB_SIZE (256)
+#define BLOB_HEADER_SIZE (sizeof(key_blob_header))
+#define BLOB_MAC_SIZE (16)
+
+
+typedef struct key_blob_header_t
+{
+	uint32_t id;
+	uint32_t algorithm;
+	uint32_t body_size;
+} key_blob_header;
+
+typedef struct key_wrapper
+{
+	uint32_t size;
+	uint32_t addr32;
+} key_wrapper;
+
+typedef struct key_slot
+{
+	uint32_t valid;
+	uint32_t id;
+	uint32_t algorithm;
+	key_wrapper key_w;
+} key_slot;
+
+/* This structure must be consistent with the one in HSM side */
+typedef struct key_table_t
+{
+	uint32_t is_rebuild_done;
+	uint32_t nkeys;
+	key_slot slot[MAX_KEY_NUMS];
+} key_table;
+
+/* This enum must be consistent with the one in HSM side */
+typedef enum uECC_curve_id
+{
+	UECC_CURVE_ID_UNSUPPORT,
+	UECC_CURVE_ID_SECP160R1,
+	UECC_CURVE_ID_SECP192R1,
+	UECC_CURVE_ID_SECP224R1,
+	UECC_CURVE_ID_SECP256R1,
+	UECC_CURVE_ID_SECP256K1,
+	UECC_CURVE_ID_SECP384R1,
+} uECC_curve_id;
+
+typedef struct ecc_keypair_datastruct
+{
+	uECC_curve_id curve_id;
+	uint8_t public[96];
+	uint8_t private[48];
+	uint8_t reserved[12];
+} ecc_keypair_datastruct;
+
+#endif /*__MTK_KEY_H__*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/object.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/object.c
new file mode 100644
index 0000000..2dd50d6
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/object.c
@@ -0,0 +1,874 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#include <inttypes.h>
+#include <sks_internal_abi.h>
+#include <string_ext.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+
+#include "attributes.h"
+#include "handle.h"
+#include "object.h"
+#include "pkcs11_attributes.h"
+#include "pkcs11_token.h"
+#include "processing.h"
+#include "sanitize_object.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+struct sks_object *sks_handle2object(uint32_t handle,
+				     struct pkcs11_session *session)
+{
+	return handle_lookup(&session->object_handle_db, handle);
+}
+
+uint32_t sks_object2handle(struct sks_object *obj,
+			   struct pkcs11_session *session)
+{
+	return handle_lookup_handle(&session->object_handle_db, obj);
+}
+
+/* Currently handle pkcs11 sessions and tokens */
+
+static struct object_list *get_session_objects(void *session)
+{
+	/* Currently supporting only pkcs11 session */
+	struct pkcs11_session *ck_session = session;
+
+	return pkcs11_get_session_objects(ck_session);
+}
+
+static struct ck_token *get_session_token(void *session)
+{
+	/* Currently supporting only pkcs11 session */
+	struct pkcs11_session *ck_session = session;
+
+	return pkcs11_session2token(ck_session);
+}
+
+/* Release resources of a non persistent object */
+static void cleanup_volatile_obj_ref(struct sks_object *obj)
+{
+	if (!obj)
+		return;
+
+	if (obj->key_handle != TEE_HANDLE_NULL)
+		TEE_FreeTransientObject(obj->key_handle);
+
+	if (obj->attribs_hdl != TEE_HANDLE_NULL) {
+		TEE_CloseObject(obj->attribs_hdl);
+	}
+
+	TEE_Free(obj->attributes);
+	TEE_Free(obj->uuid);
+	TEE_Free(obj);
+}
+
+
+/* Release resources of a persistent object including volatile resources */
+void cleanup_persistent_object(struct sks_object *obj,
+				      struct ck_token *token)
+{
+	TEE_Result res;
+
+	if (!obj)
+		return;
+
+	/* Open handle with write properties to destroy the object */
+	if (obj->attribs_hdl != TEE_HANDLE_NULL) {
+		TEE_CloseObject(obj->attribs_hdl);
+	}
+
+	res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
+					obj->uuid, sizeof(TEE_UUID),
+					TEE_DATA_FLAG_ACCESS_WRITE_META,
+					&obj->attribs_hdl);
+	assert(!res);
+	if (res)
+		goto out;
+
+	TEE_CloseAndDeletePersistentObject1(obj->attribs_hdl);
+
+out:
+	obj->attribs_hdl = TEE_HANDLE_NULL;
+	destroy_object_uuid(token, obj);
+
+	LIST_REMOVE(obj, link);
+
+	cleanup_volatile_obj_ref(obj);
+}
+
+/*
+ * destroy_object - destroy an SKS object
+ *
+ * @session - session requesting object destruction
+ * @object - reference to the sks object
+ * @session_object_only - true is only session object shall be destroyed
+ */
+void destroy_object(struct pkcs11_session *session,
+			  struct sks_object *obj,
+			  bool session_only)
+{
+#ifdef DEBUG
+	trace_attributes("[destroy]", obj->attributes);
+	if (obj->uuid)
+		MSG_RAW("[destroy] obj uuid %pUl", (void *)obj->uuid);
+#endif
+
+	/* Remove from session list only if was published */
+	if (obj->link.le_next || obj->link.le_prev)
+		LIST_REMOVE(obj, link);
+
+	if (session_only) {
+		/* Destroy object due to session closure */
+		handle_put(&session->object_handle_db,
+			   sks_object2handle(obj, session));
+		cleanup_volatile_obj_ref(obj);
+
+		return;
+	}
+
+	/* Destroy target object (persistent or not) */
+	if (get_bool(obj->attributes, SKS_CKA_TOKEN)) {
+		assert(obj->uuid);
+		/* Try twice otherwise panic! */
+		if (unregister_persistent_object(session->token, obj->uuid) &&
+		    unregister_persistent_object(session->token, obj->uuid))
+			TEE_Panic(0);
+
+		cleanup_persistent_object(obj, session->token);
+		handle_put(&session->object_handle_db,
+			   sks_object2handle(obj, session));
+	} else {
+		handle_put(&session->object_handle_db,
+			   sks_object2handle(obj, session));
+		cleanup_volatile_obj_ref(obj);
+	}
+}
+
+static struct sks_object *create_object_instance(struct sks_attrs_head *head)
+{
+	struct sks_object *obj = NULL;
+
+	obj = TEE_Malloc(sizeof(struct sks_object), TEE_MALLOC_FILL_ZERO);
+	if (!obj)
+		return NULL;
+
+	obj->key_handle = TEE_HANDLE_NULL;
+	obj->attribs_hdl = TEE_HANDLE_NULL;
+	obj->attributes = head;
+
+	return obj;
+}
+
+struct sks_object *create_token_object_instance(struct sks_attrs_head *head,
+						TEE_UUID *uuid)
+{
+	struct sks_object *obj = create_object_instance(head);
+
+	if (!obj)
+		return NULL;
+
+	obj->uuid = uuid;
+
+	return obj;
+}
+
+/*
+ * create_object - create an SKS object from its attributes and value
+ *
+ * @session - session requesting object creation
+ * @attributes - reference to serialized attributes
+ * @handle - generated handle for the created object
+ */
+uint32_t create_object(void *sess, struct sks_attrs_head *head,
+		       uint32_t *out_handle)
+{
+	uint32_t rv = 0;
+	TEE_Result res = TEE_SUCCESS;
+	struct sks_object *obj = NULL;
+	struct pkcs11_session *session = (struct pkcs11_session *)sess;
+	uint32_t obj_handle = 0;
+
+#ifdef DEBUG
+	trace_attributes("[create]", head);
+#endif
+
+	/*
+	 * We do not check the key attributes. At this point, key attributes
+	 * are expected consistent and reliable.
+	 */
+
+	obj = create_object_instance(head);
+	if (!obj)
+		return SKS_MEMORY;
+
+	/* Create a handle for the object in the session database */
+	obj_handle = handle_get(&session->object_handle_db, obj);
+	if (!obj_handle) {
+		rv = SKS_MEMORY;
+		goto bail;
+	}
+
+	if (get_bool(obj->attributes, SKS_CKA_TOKEN)) {
+		/*
+		 * Get an ID for the persistent object
+		 * Create the file
+		 * Register the object in the persistent database
+		 * (move the full sequence to persisent_db.c?)
+		 */
+		size_t size = attributes_size(obj->attributes);
+
+		rv = create_object_uuid(get_session_token(session), obj);
+		if (rv)
+			goto bail;
+
+		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
+						 obj->uuid, sizeof(TEE_UUID),
+						 TEE_DATA_FLAG_ACCESS_READ |
+						 TEE_DATA_FLAG_ACCESS_WRITE |
+						 TEE_DATA_FLAG_ACCESS_WRITE_META,
+						 TEE_HANDLE_NULL,
+						 obj->attributes, size,
+						 &obj->attribs_hdl);
+		if (res) {
+			rv = tee2sks_error(res);
+			goto bail;
+		}
+
+		rv = register_persistent_object(get_session_token(session),
+						obj->uuid);
+		if (rv)
+			goto bail;
+
+		LIST_INSERT_HEAD(&session->token->object_list, obj, link);
+	} else {
+		rv = SKS_OK;
+		LIST_INSERT_HEAD(get_session_objects(session), obj, link);
+	}
+
+
+	*out_handle = obj_handle;
+
+bail:
+	if (rv) {
+		handle_put(&session->object_handle_db, obj_handle);
+		if (get_bool(obj->attributes, SKS_CKA_TOKEN))
+			cleanup_persistent_object(obj, session->token);
+		else
+			cleanup_volatile_obj_ref(obj);
+	}
+
+	return rv;
+}
+
+uint32_t entry_destroy_object(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out)
+{
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	uint32_t object_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_object *object = NULL;
+	uint32_t rv = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	object = sks_handle2object(object_handle, session);
+	if (!object)
+		return SKS_BAD_PARAM;
+
+	destroy_object(session, object, false);
+	handle_put(&session->object_handle_db, object_handle);
+
+	IMSG("SKSs%" PRIu32 ": destroy object 0x%" PRIx32,
+	     session_handle, object_handle);
+
+	return rv;
+}
+
+static uint32_t token_obj_matches_ref(struct sks_attrs_head *req_attrs,
+				      struct sks_object *obj)
+{
+	uint32_t rv = 0;
+
+	if (!obj->attributes)
+		return SKS_NOT_FOUND;
+
+	if (!attributes_match_reference(obj->attributes, req_attrs))
+		return SKS_NOT_FOUND;
+
+	rv = SKS_OK;
+
+	return rv;
+}
+
+static void release_find_obj_context(struct pkcs11_session *session,
+				     struct pkcs11_find_objects *find_ctx)
+{
+	size_t idx = 0;
+
+	if (!find_ctx)
+		return;
+
+	/* Release handles not yet published to client */
+	idx = find_ctx->next;
+	if (idx < find_ctx->temp_start)
+		idx = find_ctx->temp_start;
+
+	for (;idx < find_ctx->count; idx++)
+		handle_put(&session->object_handle_db, find_ctx->handles[idx]);
+
+	TEE_Free(find_ctx->attributes);
+	TEE_Free(find_ctx->handles);
+	TEE_Free(find_ctx);
+}
+
+/* TODO : not finished */
+uint32_t check_key_object_not_generated(struct pkcs11_session *session,
+				     struct sks_attrs_head *req_attrs)
+{
+	uint32_t rv = SKS_OK;
+	struct sks_object *obj = NULL;
+	uint32_t *id_ptr = NULL;
+	uint32_t id_len = 0;
+
+	if (req_attrs == NULL)
+		return SKS_BAD_PARAM;
+
+	rv = get_attribute_ptr(req_attrs, SKS_CKA_ID, &id_ptr, &id_len);
+	if (rv) {
+		IMSG("[%s][%d] no SKS_CKA_ID in attributes!\n", __FUNCTION__, __LINE__);
+		goto bail;
+	}
+
+
+	return SKS_OK;
+bail:
+	return rv;
+}
+
+/*
+ * Entry for command SKS_CMD_FIND_OBJECTS_INIT
+ */
+uint32_t entry_find_objects_init(uintptr_t tee_session, TEE_Param *ctrl,
+				 TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_object_head *template = NULL;
+	struct sks_attrs_head *req_attrs = NULL;
+	struct sks_object *obj = NULL;
+	struct pkcs11_find_objects *find_ctx = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session) {
+		rv = SKS_CKR_SESSION_HANDLE_INVALID;
+		goto bail;
+	}
+
+	/* Search objects only if no operation is on-going */
+	if (session_is_active(session)) {
+		rv = SKS_CKR_OPERATION_ACTIVE;
+		goto bail;
+	}
+
+	if (session->find_ctx) {
+		EMSG("Active object search already in progress");
+		rv = SKS_FAILED;
+		goto bail;
+	}
+
+	/* Must zero init the structure */
+	find_ctx = TEE_Malloc(sizeof(*find_ctx), TEE_MALLOC_FILL_ZERO);
+	if (!find_ctx) {
+		rv = SKS_MEMORY;
+		goto bail;
+	}
+
+	rv = sanitize_client_object(&req_attrs, template,
+				    sizeof(*template) + template->attrs_size);
+	if (rv)
+		goto bail;
+
+	TEE_Free(template);
+	template = NULL;
+
+	switch (get_class(req_attrs)) {
+	case SKS_UNDEFINED_ID:
+	/* Unspecified class searches among data objects */
+	case SKS_CKO_CERTIFICATE:
+	case SKS_CKO_SECRET_KEY:
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+	case SKS_CKO_DATA:
+		break;
+	default:
+		EMSG("Find object of class %s (%u) is not supported",
+		     sks2str_class(get_class(req_attrs)),
+		     get_class(req_attrs));
+		rv = SKS_CKR_ARGUMENTS_BAD;
+		goto bail;
+
+	}
+
+	/*
+	 * Scan all objects (sessions and persistent ones) and set a list of
+	 * candidates that match caller attributes. First scan all current
+	 * session objects (that are visible to the session). Then scan all
+	 * remaining persistent object for which no session object handle was
+	 * published to the client.
+	 */
+
+	LIST_FOREACH(obj, &session->object_list, link) {
+		uint32_t *handles = NULL;
+
+		rv = check_access_attrs_against_token(session, obj->attributes);
+		if (rv)
+			continue;
+
+		if (!attributes_match_reference(obj->attributes, req_attrs))
+			continue;
+
+		handles = TEE_Realloc(find_ctx->handles,
+				      (find_ctx->count + 1) * sizeof(*handles));
+		if (!handles) {
+			rv = SKS_MEMORY;
+			goto bail;
+		}
+		find_ctx->handles = handles;
+
+		*(find_ctx->handles + find_ctx->count) =
+			sks_object2handle(obj, session);
+		find_ctx->count++;
+	}
+
+	/* Remaining handles are those not yet published by the session */
+	find_ctx->temp_start = find_ctx->count;
+
+
+	LIST_FOREACH(obj, &session->token->object_list, link) {
+		uint32_t obj_handle = 0;
+		uint32_t *handles = NULL;
+
+		/*
+		 * If there are no attributes specified, we return
+		 * every object
+		 */
+		if (req_attrs->attrs_count) {
+			rv = token_obj_matches_ref(req_attrs, obj);
+			if (rv == SKS_NOT_FOUND)
+				continue;
+			if (rv != SKS_OK)
+				goto bail;
+		}
+
+		// rv = check_access_attrs_against_token(session, obj->attributes);
+		// if (rv)
+		// 	continue;
+
+		/* Object may not yet be published in the session */
+		obj_handle = sks_object2handle(obj, session);
+		if (!obj_handle) {
+			obj_handle = handle_get(&session->object_handle_db,
+						obj);
+			if (!obj_handle) {
+				rv = SKS_MEMORY;
+				goto bail;
+			}
+		}
+
+		handles = TEE_Realloc(find_ctx->handles,
+				      (find_ctx->count + 1) * sizeof(*handles));
+		if (!handles) {
+			rv = SKS_MEMORY;
+			goto bail;
+		}
+
+		/* Store object handle for later publishing */
+		find_ctx->handles = handles;
+		*(handles + find_ctx->count) = obj_handle;
+		find_ctx->count++;
+	}
+
+	if (rv == SKS_NOT_FOUND)
+		rv = SKS_OK;
+
+	/* Save target attributes to search (if needed later) */
+	find_ctx->attributes = req_attrs;
+	req_attrs = NULL;
+	session->find_ctx = find_ctx;
+	find_ctx = NULL;
+	rv = SKS_OK;
+
+bail:
+	TEE_Free(req_attrs);
+	TEE_Free(template);
+	release_find_obj_context(session, find_ctx);
+
+	return rv;
+}
+
+/*
+ * Entry for command SKS_CMD_FIND_OBJECTS
+ */
+uint32_t entry_find_objects(uintptr_t tee_session, TEE_Param *ctrl,
+			    TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct pkcs11_find_objects *ctx = NULL;
+	uint32_t *out_handles = NULL;
+	size_t out_count = 0;
+	size_t count = 0;
+	size_t idx = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	out_count = out->memref.size / sizeof(uint32_t);
+	out_handles = (uint32_t *)(uintptr_t)out->memref.buffer;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	ctx = session->find_ctx;
+
+	/*
+	 * TODO: should we check again if these handles are valid?
+	 */
+	if (!ctx)
+		return SKS_CKR_OPERATION_NOT_INITIALIZED;
+
+	for (count = 0, idx = ctx->next; idx < ctx->count; idx++, count++) {
+		struct sks_object *obj = NULL;
+
+		if (count >= out_count)
+			break;
+
+		*(out_handles + count) = *(ctx->handles + idx);
+		ctx->next = idx + 1;
+
+		if (idx < session->find_ctx->temp_start)
+			continue;
+
+		/* Newly published handles: store in session list */
+		obj = handle_lookup(&session->object_handle_db,
+				    *(ctx->handles + idx));
+		if (!obj)
+			TEE_Panic(0);
+
+	}
+
+	/* Update output buffer according the number of handles provided */
+	out->memref.size = count * sizeof(uint32_t);
+
+	IMSG("SKSs%" PRIu32 ": finding objects", session_handle);
+
+	return SKS_OK;
+}
+
+void release_session_find_obj_context(struct pkcs11_session *session)
+{
+	release_find_obj_context(session, session->find_ctx);
+	session->find_ctx = NULL;
+}
+
+/*
+ * Entry for command SKS_CMD_FIND_OBJECTS_FINAL
+ */
+uint32_t entry_find_objects_final(uintptr_t tee_session, TEE_Param *ctrl,
+				  TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 9;
+	struct pkcs11_session *session = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	if (!session->find_ctx)
+		return SKS_CKR_OPERATION_NOT_INITIALIZED;
+
+	release_session_find_obj_context(session);
+
+	return SKS_OK;
+}
+
+
+/*
+ * Entry for command SKS_CMD_GET_OBJECT_SIZE
+ */
+uint32_t entry_get_object_size(uintptr_t tee_session, TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out)
+{
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	uint32_t object_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_object *object = NULL;
+	uint32_t rv = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < sizeof(uint32_t))
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	object = sks_handle2object(object_handle, session);
+	if (!object)
+		return SKS_CKR_OBJECT_HANDLE_INVALID;
+
+	*(uint32_t *)out->memref.buffer = SKS_CK_UNAVAILABLE_INFORMATION;
+	out->memref.size = sizeof(uint32_t);
+
+	return rv;
+}
+
+/*
+ * Entry for command SKS_CMD_GET_ATTRIBUTE_VALUE
+ */
+uint32_t entry_get_attribute_value(uintptr_t tee_session, TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_object_head *template = NULL;
+	struct sks_object *obj = NULL;
+	uint32_t object_handle = 0;
+	char *cur = NULL;
+	size_t len = 0;
+	char *end = NULL;
+	bool attr_sensitive = 0;
+	bool attr_type_invalid = 0;
+	bool buffer_too_small = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&ctrlargs, &object_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session) {
+		rv = SKS_CKR_SESSION_HANDLE_INVALID;
+		goto bail;
+	}
+
+	obj = sks_handle2object(object_handle, session);
+	if (!obj) {
+		rv = SKS_CKR_OBJECT_HANDLE_INVALID;
+		goto bail;
+	}
+
+	rv = check_access_attrs_against_token(session, obj->attributes);
+	if (rv) {
+		rv = SKS_CKR_OBJECT_HANDLE_INVALID;
+		goto bail;
+	}
+
+	/* iterate over attributes and set their values */
+	/*
+	 * 1. If the specified attribute (i.e., the attribute specified by the
+	 * type field) for the object cannot be revealed because the object is
+	 * sensitive or unextractable, then the ulValueLen field in that triple
+	 * is modified to hold the value CK_UNAVAILABLE_INFORMATION.
+	 *
+	 * 2. Otherwise, if the specified value for the object is invalid (the
+	 * object does not possess such an attribute), then the ulValueLen field
+	 * in that triple is modified to hold the value
+	 * CK_UNAVAILABLE_INFORMATION.
+	 *
+	 * 3. Otherwise, if the pValue field has the value NULL_PTR, then the
+	 * ulValueLen field is modified to hold the exact length of the
+	 * specified attribute for the object.
+	 *
+	 * 4. Otherwise, if the length specified in ulValueLen is large enough
+	 * to hold the value of the specified attribute for the object, then
+	 * that attribute is copied into the buffer located at pValue, and the
+	 * ulValueLen field is modified to hold the exact length of the
+	 * attribute.
+	 *
+	 * 5. Otherwise, the ulValueLen field is modified to hold the value
+	 * CK_UNAVAILABLE_INFORMATION.
+	 */
+	cur = (char *)template + sizeof(struct sks_object_head);
+	end = cur + template->attrs_size;
+
+	for (; cur < end; cur += len) {
+		struct sks_attribute_head *cli_ref_orgi;
+		struct sks_attribute_head tmp;
+		struct sks_attribute_head *cli_ref;
+
+		cli_ref_orgi = (struct sks_attribute_head *)(void *)cur;
+		TEE_MemMove(&tmp,cli_ref_orgi,sizeof(tmp));
+
+		len = sizeof(tmp)+tmp.size;
+		cli_ref = TEE_Malloc(len,TEE_USER_MEM_HINT_NO_FILL_ZERO);
+
+		if (!cli_ref) {
+			rv = SKS_MEMORY;
+			goto bail;
+		}
+
+		TEE_MemMove(cli_ref,cli_ref_orgi,len);
+
+		/* Check 1. */
+		if (!attribute_is_exportable(cli_ref, obj)) {
+			cli_ref->size = SKS_CK_UNAVAILABLE_INFORMATION;
+			attr_sensitive = 1;
+			continue;
+		}
+
+		/*
+		 * We assume that if size is 0, pValue was NULL, so we return
+		 * the size of the required buffer for it (3., 4.)
+		 */
+		rv = get_attribute(obj->attributes, cli_ref->id,
+				   cli_ref->size ? cli_ref->data : NULL,
+				   &(cli_ref->size));
+		/* Check 2. */
+		switch (rv) {
+		case SKS_OK:
+			break;
+		case SKS_NOT_FOUND:
+			cli_ref->size = SKS_CK_UNAVAILABLE_INFORMATION;
+			attr_type_invalid = 1;
+			break;
+		case SKS_SHORT_BUFFER:
+			buffer_too_small = 1;
+			break;
+		default:
+			rv = SKS_ERROR;
+			TEE_MemMove(cli_ref_orgi,cli_ref,len);
+			TEE_Free(cli_ref);
+			goto bail;
+		}
+
+		TEE_MemMove(cli_ref_orgi,cli_ref,len);
+		TEE_Free(cli_ref);
+	}
+
+	/*
+	 * If case 1 applies to any of the requested attributes, then the call
+	 * should return the value CKR_ATTRIBUTE_SENSITIVE. If case 2 applies to
+	 * any of the requested attributes, then the call should return the
+	 * value CKR_ATTRIBUTE_TYPE_INVALID. If case 5 applies to any of the
+	 * requested attributes, then the call should return the value
+	 * CKR_BUFFER_TOO_SMALL. As usual, if more than one of these error codes
+	 * is applicable, Cryptoki may return any of them. Only if none of them
+	 * applies to any of the requested attributes will CKR_OK be returned.
+	 */
+
+	rv = SKS_OK;
+	if (attr_sensitive)
+		rv = SKS_CKR_ATTRIBUTE_SENSITIVE;
+	if (attr_type_invalid)
+		rv = SKS_CKR_ATTRIBUTE_TYPE_INVALID;
+	if (buffer_too_small)
+		rv = SKS_CKR_BUFFER_TOO_SMALL;
+
+	/* Move updated template to out buffer */
+	TEE_MemMove(out->memref.buffer, template, out->memref.size);
+
+	IMSG("SKSs%" PRIu32 ": get attributes 0x%" PRIx32,
+	     session_handle, object_handle);
+
+bail:
+	TEE_Free(template);
+	template = NULL;
+
+	return rv;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/object.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/object.h
new file mode 100644
index 0000000..31d93a7
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/object.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#ifndef __SKS_OBJECT_H__
+#define __SKS_OBJECT_H__
+
+#include <sks_internal_abi.h>
+#include <sys/queue.h>
+#include <tee_internal_api.h>
+
+struct pkcs11_session;
+struct ck_token;
+
+struct sks_object {
+	LIST_ENTRY(sks_object) link;
+	/* pointer to the serialized object attributes */
+	void *attributes;
+	TEE_ObjectHandle key_handle;	/* Valid handle for TEE operations */
+	uint32_t key_type;		/* TEE type of key_handle */
+
+	/* These are for persistent/token objects */
+	TEE_UUID *uuid;
+	TEE_ObjectHandle attribs_hdl;
+};
+
+LIST_HEAD(object_list, sks_object);
+
+struct sks_object *sks_handle2object(uint32_t client_handle,
+				     struct pkcs11_session *session);
+
+uint32_t sks_object2handle(struct sks_object *obj,
+			   struct pkcs11_session *session);
+
+struct sks_object *create_token_object_instance(struct sks_attrs_head *head,
+						TEE_UUID *uuid);
+
+uint32_t create_object(void *session, struct sks_attrs_head *attributes,
+			uint32_t *handle);
+
+void cleanup_persistent_object(struct sks_object *obj,
+			struct ck_token *token);
+
+void destroy_object(struct pkcs11_session *session, struct sks_object *object,
+		    bool session_object_only);
+
+/*
+ * Entry function called from the SKS command parser
+ */
+uint32_t entry_destroy_object(uintptr_t teesess, TEE_Param *ctrl,
+			      TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_find_objects_init(uintptr_t teesess, TEE_Param *ctrl,
+				 TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_find_objects(uintptr_t teesess, TEE_Param *ctrl,
+			    TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_find_objects_final(uintptr_t teesess, TEE_Param *ctrl,
+				  TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_get_object_size(uintptr_t teesess, TEE_Param *ctrl,
+			       TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_get_attribute_value(uintptr_t teesess, TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out);
+
+void release_session_find_obj_context(struct pkcs11_session *session);
+
+uint32_t check_key_object_not_generated(struct pkcs11_session *session,
+				     struct sks_attrs_head *req_attrs);
+
+#endif /*__SKS_OBJECT_H__*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/persistent_token.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/persistent_token.c
new file mode 100644
index 0000000..2f112ff
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/persistent_token.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <assert.h>
+#include <sks_ta.h>
+#include <string.h>
+#include <string_ext.h>
+#include <tee_internal_api_extensions.h>
+#include <util.h>
+
+#include "pkcs11_token.h"
+#include "sks_helpers.h"
+
+/*
+ * Token persistent objects
+ *
+ * The persistent objects are each identified by a UUID.
+ * The persistent object database stores the list of the UUIDs registered. For
+ * each it is expected that a file of ID "UUID" is store in the OP-TEE secure
+ * storage.
+ */
+
+/* 'X' will be replaced by the token decimal id (up to 9!) */
+#define TOKEN_DB_FILE_BASE		"token.db.X"
+
+void close_persistent_db(struct ck_token *token)
+{
+	int n = 0;
+
+	for (n = 0; n < SKS_MAX_USERS; n++) {
+		TEE_CloseObject(token->pin_hdl[n]);
+		token->pin_hdl[n] = TEE_HANDLE_NULL;
+	}
+
+	TEE_CloseObject(token->db_hdl);
+	token->db_hdl = TEE_HANDLE_NULL;
+}
+
+int update_persistent_db(struct ck_token *token, size_t offset, size_t size)
+{
+	unsigned int token_id = get_token_id(token);
+	char file[] = TOKEN_DB_FILE_BASE;
+	uint8_t *field = (uint8_t *)token->db_main + offset;
+	TEE_Result res = TEE_ERROR_GENERIC;
+
+	if (snprintf(file + sizeof(file) - 2, 2, "%1d", token_id) >= 2)
+		TEE_Panic(0);
+
+	if (token->db_hdl == TEE_HANDLE_NULL)
+		return 1;
+
+	res = TEE_SeekObjectData(token->db_hdl, offset, TEE_DATA_SEEK_SET);
+	if (res)
+		return tee2sks_error(res);
+
+	res = TEE_WriteObjectData(token->db_hdl, field, size);
+	if (res)
+		return tee2sks_error(res);
+
+	return 0;
+}
+
+static void init_pin_keys(struct ck_token *token, unsigned int uid)
+{
+	TEE_Result res = TEE_ERROR_GENERIC;
+	unsigned int token_id = get_token_id(token);
+	TEE_ObjectHandle *key_hdl = &token->pin_hdl[uid];
+	char file[32] = { 0 };
+
+	assert(token_id < 10 && uid < 10);
+
+	if (snprintf(file, 32, "token.db.%1d-pin%1d", token_id, uid) >= 32)
+		TEE_Panic(0);
+
+	res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
+					file, sizeof(file), 0, key_hdl);
+	if (res == TEE_SUCCESS) {
+		DMSG("PIN key found");
+		return;
+	}
+
+	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
+		TEE_Attribute attr;
+		TEE_ObjectHandle hdl = TEE_HANDLE_NULL;
+		uint8_t pin_key[16] = { 0 };
+
+		TEE_MemFill(&attr, 0, sizeof(attr));
+
+		TEE_GenerateRandom(pin_key, sizeof(pin_key));
+		TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE,
+				     pin_key, sizeof(pin_key));
+
+		res = TEE_AllocateTransientObject(TEE_TYPE_AES, 128, &hdl);
+		if (res)
+			TEE_Panic(0);
+
+		res = TEE_PopulateTransientObject(hdl, &attr, 1);
+		if (res)
+			TEE_Panic(0);
+
+		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
+						 file, sizeof(file), 0,
+						 hdl,
+						 pin_key, sizeof(pin_key),
+						 key_hdl);
+		if (res)
+			TEE_Panic(0);
+
+		TEE_FreeTransientObject(hdl);
+		return;
+	}
+
+	TEE_Panic(0);
+}
+
+/* UUID for persistent object */
+uint32_t create_object_uuid(struct ck_token *token __unused,
+			    struct sks_object *obj)
+{
+	assert(!obj->uuid);
+
+	obj->uuid = TEE_Malloc(sizeof(TEE_UUID),
+				TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!obj->uuid)
+		return SKS_MEMORY;
+
+	TEE_GenerateRandom(obj->uuid, sizeof(TEE_UUID));
+
+	/*
+	 * TODO: check uuid against already registered one (in persistent
+	 * database) and the pending created uuids (not already registered
+	 * if any).
+	 */
+	return SKS_OK;
+}
+
+void destroy_object_uuid(struct ck_token *token __unused,
+			 struct sks_object *obj)
+{
+	if (!obj->uuid)
+		return;
+
+	/* TODO: check uuid is not still registered in persistent db ? */
+	TEE_Free(obj->uuid);
+	obj->uuid = NULL;
+}
+
+uint32_t get_persistent_objects_list(struct ck_token *token,
+				     TEE_UUID *array, size_t *size)
+{
+	size_t out_size = *size;
+
+	*size = token->db_objs->count * sizeof(TEE_UUID);
+
+	if (out_size < *size)
+		return SKS_SHORT_BUFFER;
+
+	if (array)
+		TEE_MemMove(array, token->db_objs->uuids, *size);
+
+	return SKS_OK;
+}
+
+uint32_t unregister_persistent_object(struct ck_token *token, TEE_UUID *uuid)
+{
+	int index = 0;
+	int count = 0;
+	struct token_persistent_objs *ptr;
+	TEE_Result res = TEE_ERROR_GENERIC;
+
+	if (!uuid)
+		return SKS_OK;
+
+	for (index = (int)(token->db_objs->count) - 1; index >= 0; index--) {
+		if (!TEE_MemCompare(token->db_objs->uuids + index,
+				    uuid, sizeof(TEE_UUID)))
+			break;
+	}
+
+	if (index < 0) {
+		EMSG("Cannot unregister an invalid persistent object");
+		return SKS_NOT_FOUND;
+	}
+
+	ptr = TEE_Malloc(sizeof(struct token_persistent_objs) +
+			 ((token->db_objs->count - 1) * sizeof(TEE_UUID)),
+			 TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!ptr)
+		return SKS_MEMORY;
+
+	res = TEE_SeekObjectData(token->db_hdl,
+				 sizeof(struct token_persistent_main),
+				 TEE_DATA_SEEK_SET);
+	if (res) {
+		EMSG("Failed to read database");
+		TEE_Free(ptr);
+		return tee2sks_error(res);
+	}
+
+	TEE_MemMove(ptr, token->db_objs,
+		    sizeof(struct token_persistent_objs) +
+		    index * sizeof(TEE_UUID));
+
+	ptr->count--;
+	count = ptr->count - index;
+
+	TEE_MemMove(&ptr->uuids[index],
+		    &token->db_objs->uuids[index + 1],
+		    count * sizeof(TEE_UUID));
+
+	res = TEE_WriteObjectData(token->db_hdl, ptr,
+				  sizeof(struct token_persistent_objs) +
+				  ptr->count * sizeof(TEE_UUID));
+	if (res) {
+		EMSG("Failed to update database");
+		TEE_Free(ptr);
+		return tee2sks_error(res);
+	}
+
+	TEE_Free(token->db_objs);
+	token->db_objs = ptr;
+
+	return SKS_OK;
+}
+
+uint32_t register_persistent_object(struct ck_token *token, TEE_UUID *uuid)
+{
+	int count = 0;
+	void *ptr = NULL;
+	size_t __maybe_unused size = 0;
+	TEE_Result res = TEE_ERROR_GENERIC;
+
+	for (count = (int)token->db_objs->count - 1; count >= 0; count--)
+		if (!TEE_MemCompare(token->db_objs->uuids + count, uuid,
+				    sizeof(TEE_UUID)))
+			TEE_Panic(0);
+
+	count = token->db_objs->count;
+	ptr = TEE_Realloc(token->db_objs,
+			  sizeof(struct token_persistent_objs) +
+			  ((count + 1) * sizeof(TEE_UUID)));
+	if (!ptr)
+		return SKS_MEMORY;
+
+	token->db_objs = ptr;
+	TEE_MemMove(token->db_objs->uuids + count, uuid, sizeof(TEE_UUID));
+
+	size = sizeof(struct token_persistent_main) +
+		sizeof(struct token_persistent_objs) +
+		count * sizeof(TEE_UUID);
+
+	res = TEE_TruncateObjectData(token->db_hdl, size + sizeof(TEE_UUID));
+	if (res)
+		return tee2sks_error(res);
+
+	res = TEE_SeekObjectData(token->db_hdl,
+				 sizeof(struct token_persistent_main),
+				 TEE_DATA_SEEK_SET);
+	if (res)
+		return tee2sks_error(res);
+
+	token->db_objs->count++;
+
+	res = TEE_WriteObjectData(token->db_hdl, token->db_objs,
+				  sizeof(struct token_persistent_objs) +
+				  token->db_objs->count * sizeof(TEE_UUID));
+	if (res) {
+		token->db_objs->count--;
+		return tee2sks_error(res);
+	}
+
+	return SKS_OK;
+}
+
+static uint32_t token_load_obj_attribs(struct sks_object *obj)
+{
+	uint32_t rv = 0;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	TEE_ObjectHandle hdl = obj->attribs_hdl;
+	TEE_ObjectInfo info;
+	struct sks_attrs_head *attr = NULL;
+	uint32_t read_bytes = 0;
+
+	if (hdl != TEE_HANDLE_NULL) {
+		IMSG("Handle attributes already set for this object");
+		return SKS_OK;
+	}
+
+	res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
+					   obj->uuid, sizeof(*obj->uuid),
+					   TEE_DATA_FLAG_ACCESS_READ,
+					   &hdl);
+	if (res) {
+		EMSG("OpenPersistent failed 0x%" PRIx32, res);
+		return tee2sks_error(res);
+	}
+
+	TEE_MemFill(&info, 0, sizeof(info));
+	res = TEE_GetObjectInfo1(hdl, &info);
+	if (res) {
+		EMSG("GetObjectInfo failed 0x%" PRIx32, res);
+		rv = tee2sks_error(res);
+		goto bail;
+	}
+
+	attr = TEE_Malloc(info.dataSize, TEE_MALLOC_FILL_ZERO);
+	if (!attr) {
+		rv = SKS_MEMORY;
+		goto bail;
+	}
+
+	res = TEE_ReadObjectData(hdl, attr, info.dataSize, &read_bytes);
+	if (!res) {
+		res = TEE_SeekObjectData(hdl, 0, TEE_DATA_SEEK_SET);
+		if (res)
+			EMSG("Seek to 0 failed 0x%" PRIx32, res);
+	}
+
+	if (res) {
+		rv = tee2sks_error(res);
+		EMSG("Read %" PRIu32 " bytes, failed 0x%" PRIx32,
+			read_bytes, res);
+		goto bail;
+	}
+	if (read_bytes != info.dataSize) {
+		EMSG("Read %" PRIu32 " bytes, expected 0x%" PRIu32,
+			read_bytes, info.dataSize);
+		rv = SKS_ERROR;
+		goto bail;
+	}
+
+	obj->attributes = attr;
+	attr = NULL;
+	obj->attribs_hdl = hdl;
+	hdl = TEE_HANDLE_NULL;
+	rv = SKS_OK;
+
+bail:
+	TEE_Free(attr);
+	if (obj->attribs_hdl == TEE_HANDLE_NULL && hdl != TEE_HANDLE_NULL) {
+		TEE_CloseObject(hdl);
+	}
+
+	return rv;
+}
+
+/*
+ * Return the token instance, either initialized from reset or initialized
+ * from the token persistent state if found.
+ */
+struct ck_token *init_token_db(unsigned int token_id)
+{
+	struct ck_token *token = get_token(token_id);
+	TEE_Result res = TEE_ERROR_GENERIC;
+	char db_file[] = TOKEN_DB_FILE_BASE;
+	TEE_ObjectHandle db_hdl = TEE_HANDLE_NULL;
+	/* Copy persistent database: main db and object db */
+	struct token_persistent_main *db_main = NULL;
+	struct token_persistent_objs *db_objs = NULL;
+	int n = 0;
+	void *ptr = NULL;
+
+	if (!token)
+		return NULL;
+
+	for (n = 0; n < SKS_MAX_USERS; n++)
+		init_pin_keys(token, n);
+
+	LIST_INIT(&token->object_list);
+
+	db_main = TEE_Malloc(sizeof(*db_main), TEE_MALLOC_FILL_ZERO);
+	db_objs = TEE_Malloc(sizeof(*db_objs), TEE_MALLOC_FILL_ZERO);
+	if (!db_main || !db_objs)
+		goto error;
+
+	/* Persistent object ID is the string with last char replaced */
+	if (snprintf(db_file + sizeof(db_file) - 2, 2, "%1d", token_id) >= 2)
+		TEE_Panic(0);
+
+	res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
+					db_file, sizeof(db_file),
+					TEE_DATA_FLAG_ACCESS_READ |
+					TEE_DATA_FLAG_ACCESS_WRITE,
+					&db_hdl);
+	if (res == TEE_SUCCESS) {
+		uint32_t size = 0;
+		size_t idx = 0;
+
+		IMSG("SKSt%u: load db", token_id);
+
+		size = sizeof(*db_main);
+		res = TEE_ReadObjectData(db_hdl, db_main, size, &size);
+		if (res || size != sizeof(*db_main))
+			TEE_Panic(0);
+
+		size = sizeof(*db_objs);
+		res = TEE_ReadObjectData(db_hdl, db_objs, size, &size);
+		if (res || size != sizeof(*db_objs))
+			TEE_Panic(0);
+
+		if (db_objs->count > (SIZE_MAX - size)/sizeof(TEE_UUID))
+			goto error;
+
+		size += db_objs->count * sizeof(TEE_UUID);
+		ptr = TEE_Realloc(db_objs, size);
+		if (!ptr)
+			goto error;
+
+		db_objs = ptr;
+		size -= sizeof(struct token_persistent_objs);
+		res = TEE_ReadObjectData(db_hdl, db_objs->uuids, size, &size);
+		if (res || size != (db_objs->count * sizeof(TEE_UUID)))
+			TEE_Panic(0);
+
+		for (idx = 0; idx < db_objs->count; idx++) {
+			/* Create an empty object instance */
+			struct sks_object *obj = NULL;
+			TEE_UUID *uuid = NULL;
+
+			uuid = TEE_Malloc(sizeof(TEE_UUID),
+					  TEE_USER_MEM_HINT_NO_FILL_ZERO);
+			if (!uuid)
+				goto error;
+
+			TEE_MemMove(uuid, &db_objs->uuids[idx], sizeof(*uuid));
+
+			obj = create_token_object_instance(NULL, uuid);
+			if (!obj){
+				TEE_Free(uuid);
+				TEE_Panic(0);
+			}
+
+			if (token_load_obj_attribs(obj) != SKS_OK)
+				EMSG("Unable to load object attributes from db");
+
+			LIST_INSERT_HEAD(&token->object_list, obj, link);
+		}
+
+	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
+
+		IMSG("SKSt%u: init db", token_id);
+
+		TEE_MemFill(db_main, 0, sizeof(*db_main));
+		TEE_MemFill(db_main->label, '*', sizeof(db_main->label));
+
+		/*
+		 * Not supported:
+		 *   SKS_TOKEN_FULLY_RESTORABLE
+		 * TODO: check these:
+		 *   SKS_TOKEN_HAS_CLOCK => related to TEE time secure level
+		 */
+		db_main->flags = SKS_CKFT_SO_PIN_TO_BE_CHANGED |
+				 SKS_CKFT_USER_PIN_TO_BE_CHANGED |
+				 SKS_CKFT_RNG |
+				 SKS_CKFT_DUAL_CRYPTO_OPERATIONS |
+				 SKS_CKFT_LOGIN_REQUIRED;
+
+		/* 2 files: persistent state + persistent object references */
+		res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
+						 db_file, sizeof(db_file),
+						 TEE_DATA_FLAG_ACCESS_READ |
+						 TEE_DATA_FLAG_ACCESS_WRITE,
+						 TEE_HANDLE_NULL,
+						 db_main, sizeof(*db_main),
+						 &db_hdl);
+		if (res)
+			TEE_Panic(0);
+
+		res = TEE_TruncateObjectData(db_hdl, sizeof(*db_main) +
+							sizeof(*db_objs));
+		if (res)
+			TEE_Panic(0);
+
+		res = TEE_SeekObjectData(db_hdl, sizeof(*db_main),
+					 TEE_DATA_SEEK_SET);
+		if (res)
+			TEE_Panic(0);
+
+		db_objs->count = 0;
+		res = TEE_WriteObjectData(db_hdl, db_objs, sizeof(*db_objs));
+		if (res)
+			TEE_Panic(0);
+
+	} else {
+		/* Can't do anything... */
+		return NULL;
+	}
+
+	token->db_main = db_main;
+	token->db_objs = db_objs;
+	token->db_hdl = db_hdl;
+	TEE_SeekObjectData(token->db_hdl, 0, TEE_DATA_SEEK_SET);
+
+	return token;
+
+error:
+	TEE_Free(db_main);
+	TEE_Free(db_objs);
+	if (db_hdl != TEE_HANDLE_NULL)
+		TEE_CloseObject(db_hdl);
+
+	return NULL;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.c
new file mode 100644
index 0000000..0a1052c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.c
@@ -0,0 +1,1829 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <sks_internal_abi.h>
+#include <sks_ta.h>
+#include <string_ext.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <util.h>
+
+#include "attributes.h"
+#include "handle.h"
+#include "object.h"
+#include "pkcs11_attributes.h"
+#include "pkcs11_token.h"
+#include "processing.h"
+#include "sanitize_object.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+/* Byte size of CKA_ID attribute when generated locally */
+#define SKS_CKA_DEFAULT_SIZE		16
+
+struct pkcs11_mechachism_modes {
+	uint32_t id;
+	uint32_t flags;
+	bool available;
+	bool one_shot;
+};
+
+/*
+ * SKS_CKFM_EC_F_P
+ * SKS_CKFM_EC_F_2M
+ * SKS_CKFM_EC_ECPARAMETERS
+ * SKS_CKFM_EC_NAMEDCURVE
+ * SKS_CKFM_EC_UNCOMPRESS
+ * SKS_CKFM_EC_COMPRESS
+ */
+#define SKS_ECM		0
+
+/* SKS_CKFM_HW: need to ask core one HW support of the mechanisms */
+#define SKS_M(_label, _dig, _enc, _dec, _sig, _ver,		\
+		_sr, _vr, _der, _wra, _unw, _gen, _gpa, _1s)	\
+	{							\
+		.id = SKS_CKM_  ## _label,			\
+		.one_shot = _1s,				\
+		.flags = (_enc ? SKS_CKFM_ENCRYPT : 0) |	\
+			(_dec ? SKS_CKFM_DECRYPT : 0) |		\
+			(_dig ? SKS_CKFM_DIGEST : 0) |		\
+			(_sig ? SKS_CKFM_SIGN : 0) |		\
+			(_sr ? SKS_CKFM_SIGN_RECOVER : 0) |	\
+			(_ver ? SKS_CKFM_VERIFY : 0) |		\
+			(_vr ? SKS_CKFM_VERIFY_RECOVER : 0) |	\
+			(_gen ? SKS_CKFM_GENERATE : 0) |	\
+			(_gpa ? SKS_CKFM_GENERATE_PAIR : 0) |	\
+			(_wra ? SKS_CKFM_WRAP : 0) |		\
+			(_unw ? SKS_CKFM_UNWRAP : 0) |		\
+			(_der ? SKS_CKFM_DERIVE : 0) |		\
+			SKS_ECM,				\
+	}
+
+static const __maybe_unused struct pkcs11_mechachism_modes pkcs11_modes[] = {
+	/*
+	 * PKCS#11 directives on mechanism support for the several processing
+	 * modes.
+	 *				1: One shot processing only --------.
+	 *				Gp: Generate secret pair --------.  |
+	 *				Ge: Generate secret value ----.  |  |
+	 *				Wr|Uw: Wrap/Unwrap -------.   |  |  |
+	 *				Dr: Derive ----------.    |   |  |  |
+	 *		Sr|Vr: SignRecover/VerifyRecov --.   |    |   |  |  |
+	 *		Si|Ve: Sign/Verify --------.     |   |    |   |  |  |
+	 *		En|De: Encrypt/Decrypt     |     |   |    |   |  |  |
+	 *		Di: Digest -----.    |     |     |   |    |   |  |  |
+	 *				|   / \   / \   / \  |   / \  |  |  |
+	 * Mechanism			Di|En|De|Si|Ve|Sr|Vr|Dr|Wr|Uw|Ge|Gp|1
+	 */
+	SKS_M(AES_ECB,			0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(AES_CBC,			0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(AES_CBC_PAD,		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(AES_CTS,			0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(AES_CTR,			0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(AES_GCM,			0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(AES_CCM,			0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(AES_GMAC,			0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0),
+	SKS_M(AES_CMAC,			0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(AES_CMAC_GENERAL,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(AES_ECB_ENCRYPT_DATA,	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0),
+	SKS_M(AES_CBC_ENCRYPT_DATA,	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0),
+	SKS_M(AES_KEY_GEN,		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0),
+
+	SKS_M(MTK_HSM_AES_KEY_GEN,	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0),
+
+	SKS_M(MTK_HSM_AES_ECB,		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(MTK_HSM_AES_CBC,		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(MTK_HSM_AES_CTR,		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(MTK_HSM_AES_GCM,		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(MTK_HSM_AES_CMAC,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	/* Mechanism			Di|En|De|Si|Ve|Sr|Vr|Dr|Wr|Uw|Ge|Gp|1 */
+	SKS_M(GENERIC_SECRET_KEY_GEN,	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0),
+	SKS_M(MD5_HMAC,			0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA_1_HMAC,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA224_HMAC,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA256_HMAC,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA384_HMAC,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA512_HMAC,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(AES_XCBC_MAC,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(MTK_HSM_SHA256_HMAC,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(MTK_HSM_SHA384_HMAC,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	/* Mechanism			Di|En|De|Si|Ve|Sr|Vr|Dr|Wr|Uw|Ge|Gp|1 */
+	SKS_M(EC_KEY_PAIR_GEN,		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0),
+	SKS_M(ECDSA,			0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
+	SKS_M(ECDSA_SHA1,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(ECDSA_SHA224,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(ECDSA_SHA256,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(ECDSA_SHA384,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(ECDSA_SHA512,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(ECDH1_DERIVE,		0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0),
+	SKS_M(ECDH1_COFACTOR_DERIVE,	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0),
+	SKS_M(ECMQV_DERIVE,		0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0),
+	SKS_M(ECDH_AES_KEY_WRAP,	0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	SKS_M(MTK_HSM_ECDSA,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
+	SKS_M(MTK_HSM_ECDSA_SHA1,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
+	SKS_M(MTK_HSM_ECDSA_SHA224,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
+	SKS_M(MTK_HSM_ECDSA_SHA256,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
+	SKS_M(MTK_HSM_ECDSA_SHA384,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
+	SKS_M(MTK_HSM_ECDSA_SHA512,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
+	SKS_M(MTK_HSM_EC_KEY_PAIR_GEN,	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0),
+	/* Mechanism			Di|En|De|Si|Ve|Sr|Vr|Dr|Wr|Uw|Ge|Gp|1 */
+	SKS_M(RSA_PKCS_KEY_PAIR_GEN,	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0),
+	SKS_M(RSA_PKCS,			0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1),
+	SKS_M(RSA_PKCS_PSS,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1),
+	SKS_M(RSA_PKCS_OAEP,		0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1),
+	SKS_M(RSA_9796,			0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1),
+	SKS_M(RSA_X_509,		0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1),
+	SKS_M(SHA1_RSA_PKCS,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0),
+	SKS_M(SHA1_RSA_PKCS_PSS,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA256_RSA_PKCS,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA384_RSA_PKCS,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA512_RSA_PKCS,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA256_RSA_PKCS_PSS,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA384_RSA_PKCS_PSS,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA512_RSA_PKCS_PSS,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA224_RSA_PKCS,		0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA224_RSA_PKCS_PSS,	0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(RSA_AES_KEY_WRAP,		0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0),
+	/* Mechanism			Di|En|De|Si|Ve|Sr|Vr|Dr|Wr|Uw|Ge|Gp|1 */
+	SKS_M(MD5,			1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA_1,			1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA224,			1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA256,			1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA384,			1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+	SKS_M(SHA512,			1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+	/*
+	 * Mechanism			Di|En|De|Si|Ve|Sr|Vr|Dr|Wr|Uw|Ge|Gp|1
+	 *                              |   \_/   \_/   \_/  |   \_/  |  |  |
+	 *		Di: Digest -----'    |     |     |   |    |   |  |  |
+	 *		En|De: Encrypt/Decrypt     |     |   |    |   |  |  |
+	 *		Si|Ve: Sign/Verify --------'     |   |    |   |  |  |
+	 *		Sr|Vr: SignUpdate/VerifyRecover -'   |    |   |  |  |
+	 *				Dr: Derive ----------'    |   |  |  |
+	 *				Wr|Uw: Wrap/Unwrap -------'   |  |  |
+	 *				Ge: Generate secret value ----'  |  |
+	 *				Gp: Generate secret pair --------'  |
+	 *				1: One shot processing only --------'
+	 */
+};
+
+static uint32_t sks_function2ckfm(enum processing_func function)
+{
+	switch (function) {
+	case SKS_FUNCTION_DIGEST:
+		return SKS_CKFM_DIGEST;
+	case SKS_FUNCTION_GENERATE:
+		return SKS_CKFM_GENERATE;
+	case SKS_FUNCTION_GENERATE_PAIR:
+		return SKS_CKFM_GENERATE_PAIR;
+	case SKS_FUNCTION_DERIVE:
+		return SKS_CKFM_DERIVE;
+	case SKS_FUNCTION_WRAP:
+		return SKS_CKFM_WRAP;
+	case SKS_FUNCTION_UNWRAP:
+		return SKS_CKFM_UNWRAP;
+	case SKS_FUNCTION_ENCRYPT:
+		return SKS_CKFM_ENCRYPT;
+	case SKS_FUNCTION_DECRYPT:
+		return SKS_CKFM_DECRYPT;
+	case SKS_FUNCTION_SIGN:
+		return SKS_CKFM_SIGN;
+	case SKS_FUNCTION_VERIFY:
+		return SKS_CKFM_VERIFY;
+	case SKS_FUNCTION_SIGN_RECOVER:
+		return SKS_CKFM_SIGN_RECOVER;
+	case SKS_FUNCTION_VERIFY_RECOVER:
+		return SKS_CKFM_VERIFY_RECOVER;
+	default:
+		return 0;
+	}
+}
+
+int check_pkcs11_mechanism_flags(uint32_t mechanism_type, uint32_t flags)
+{
+	size_t n = 0;
+	uint32_t test_flags = flags & (SKS_CKFM_ENCRYPT | SKS_CKFM_DECRYPT |
+				SKS_CKFM_DERIVE | SKS_CKFM_DIGEST |
+				SKS_CKFM_SIGN | SKS_CKFM_SIGN_RECOVER |
+				SKS_CKFM_VERIFY | SKS_CKFM_VERIFY_RECOVER |
+				SKS_CKFM_GENERATE | SKS_CKFM_GENERATE_PAIR |
+				SKS_CKFM_WRAP | SKS_CKFM_UNWRAP);
+
+	for (n = 0; n < ARRAY_SIZE(pkcs11_modes); n++) {
+		if (pkcs11_modes[n].id == mechanism_type) {
+			if (test_flags & ~pkcs11_modes[n].flags) {
+				EMSG("%s flags: 0x%" PRIx32 " vs 0x%" PRIx32,
+					sks2str_proc(mechanism_type),
+					test_flags, pkcs11_modes[n].flags);
+			}
+			return test_flags & ~pkcs11_modes[n].flags;
+		}
+	}
+
+	return 1;
+}
+
+uint32_t check_mechanism_against_processing(struct pkcs11_session *session,
+					    uint32_t mechanism_type,
+					    enum processing_func function,
+					    enum processing_step step)
+{
+	size_t n = 0;
+	bool allowed = false;
+
+	switch (step) {
+	case SKS_FUNC_STEP_INIT:
+		switch (function) {
+		case SKS_FUNCTION_IMPORT:
+		case SKS_FUNCTION_COPY:
+		case SKS_FUNCTION_MODIFY:
+		case SKS_FUNCTION_DESTROY:
+			return SKS_OK;
+		default:
+			for (n = 0; n < ARRAY_SIZE(pkcs11_modes); n++) {
+				if (pkcs11_modes[n].id == mechanism_type) {
+					allowed = pkcs11_modes[n].flags &
+						  sks_function2ckfm(function);
+					break;
+				}
+			}
+			break;
+		}
+		break;
+
+	case SKS_FUNC_STEP_ONESHOT:
+	case SKS_FUNC_STEP_UPDATE:
+		if (session->processing->always_authen &&
+		    !session->processing->relogged)
+			return SKS_CKR_USER_NOT_LOGGED_IN;
+
+		if (!session->processing->updated) {
+			allowed = true;
+		} else {
+			for (n = 0; n < ARRAY_SIZE(pkcs11_modes); n++) {
+				if (pkcs11_modes[n].id == mechanism_type) {
+					allowed = !pkcs11_modes[n].one_shot;
+					break;
+				}
+			}
+		}
+		break;
+
+	case SKS_FUNC_STEP_FINAL:
+		if (session->processing->always_authen &&
+		    !session->processing->relogged)
+			return SKS_CKR_USER_NOT_LOGGED_IN;
+
+		return SKS_OK;
+
+	default:
+		TEE_Panic(step);
+		break;
+	}
+
+	if (!allowed)
+		EMSG("Processing %s (%" PRIx32 ") not permitted (%u/%u)",
+			sks2str_proc(mechanism_type), mechanism_type,
+			function, step);
+
+	return allowed ? SKS_OK : SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+}
+
+/*
+ * Object default boolean attributes as per PKCS#11
+ */
+static uint8_t *pkcs11_object_default_boolprop(uint32_t attribute)
+{
+	static const uint8_t bool_true = 1;
+	static const uint8_t bool_false = 0;
+
+	switch (attribute) {
+	/* As per PKCS#11 default value */
+	case SKS_CKA_MODIFIABLE:
+	case SKS_CKA_COPYABLE:
+	case SKS_CKA_DESTROYABLE:
+	case SKS_CKA_SIGN:
+	case SKS_CKA_VERIFY:
+		return (uint8_t *)&bool_true;
+	case SKS_CKA_TOKEN:
+	case SKS_CKA_PRIVATE:
+	case SKS_CKA_SENSITIVE:  /* TODO: symkey false, privkey: token specific */
+	/* Token specific default value */
+	case SKS_CKA_DERIVE:
+	case SKS_CKA_ENCRYPT:
+	case SKS_CKA_DECRYPT:
+	case SKS_CKA_SIGN_RECOVER:
+	case SKS_CKA_VERIFY_RECOVER:
+	case SKS_CKA_WRAP:
+	case SKS_CKA_UNWRAP:
+	case SKS_CKA_EXTRACTABLE:
+	case SKS_CKA_WRAP_WITH_TRUSTED:
+	case SKS_CKA_ALWAYS_AUTHENTICATE:
+	case SKS_CKA_TRUSTED:
+		return (uint8_t *)&bool_false;
+	default:
+		DMSG("No default for boolprop attribute 0x%" PRIx32, attribute);
+		TEE_Panic(0); // FIXME: errno
+	}
+
+	/* Keep compiler happy */
+	return NULL;
+}
+
+/*
+ * Object expects several boolean attributes to be set to a default value
+ * or to a validate client configuration value. This function append the input
+ * attribute (id/size/value) in the serialized object.
+ */
+static uint32_t pkcs11_import_object_boolprop(struct sks_attrs_head **out,
+					      struct sks_attrs_head *template,
+					      uint32_t attribute)
+{
+	uint32_t rv = 0;
+	uint8_t bbool = 0;
+	uint32_t size = sizeof(uint8_t);
+	void *attr = NULL;
+
+	rv = get_attribute(template, attribute, &bbool, &size);
+	if (rv || !bbool)
+		attr = pkcs11_object_default_boolprop(attribute);
+	else
+		attr = &bbool;
+
+	/* Boolean attributes are 1byte in the ABI, no alignment issue */
+	return add_attribute(out, attribute, attr, sizeof(uint8_t));
+}
+
+static uint32_t set_mandatory_boolprops(struct sks_attrs_head **out,
+					struct sks_attrs_head *temp,
+					uint32_t const *bp, size_t bp_count)
+{
+	uint32_t rv = SKS_OK;
+	size_t n = 0;
+
+	for (n = 0; n < bp_count; n++) {
+		rv = pkcs11_import_object_boolprop(out, temp, bp[n]);
+		if (rv)
+			return rv;
+	}
+
+	return rv;
+}
+
+static uint32_t calculate_modulus_bits(void* modulus, size_t size)
+{
+	uint32_t bits;
+	int mask, i;
+	uint8_t *modules_p;
+
+	bits = size * 8;
+	mask = 0x80;
+	modules_p = (uint8_t *)modulus;
+
+	for (i = 0; bits && (modules_p[i] & mask) == 0; bits--)
+	{
+		mask >>= 1;
+		if (mask == 0)
+		{
+			i++;
+			mask = 0x80;
+		}
+	}
+
+	return bits;
+}
+
+static uint32_t __unused set_mandatory_attributes(struct sks_attrs_head **out,
+					 struct sks_attrs_head *temp,
+					 uint32_t const *bp, size_t bp_count)
+{
+	uint32_t rv = SKS_OK;
+	size_t n = 0;
+
+	for (n = 0; n < bp_count; n++) {
+		uint32_t size = 0;
+		void *value = NULL;
+		uint32_t value_ = 0;
+
+		if (get_attribute_ptr(temp, bp[n], &value, &size)) {
+			/* FIXME: currently set attribute as empty. Fail? */
+			size = 0;
+
+			if(bp[n] == SKS_CKA_MODULUS_BITS) {
+				void* modulus_ptr = NULL;
+				uint32_t modulus_size = 0;
+				if(!get_attribute_ptr(temp, SKS_CKA_MODULUS, &modulus_ptr, &modulus_size)) {
+					value_ = calculate_modulus_bits(modulus_ptr, modulus_size);
+					value = &value_;
+					size = sizeof(value_);
+				}
+			}
+		}
+
+		rv = add_attribute(out, bp[n], value, size);
+		if (rv)
+			return rv;
+	}
+
+	return rv;
+}
+
+static uint32_t set_optional_attributes(struct sks_attrs_head **out,
+					struct sks_attrs_head *temp,
+					uint32_t const *bp, size_t bp_count)
+{
+	uint32_t rv = SKS_OK;
+	size_t n = 0;
+
+	for (n = 0; n < bp_count; n++) {
+		uint32_t size = 0;
+		void *value = NULL;
+
+		if (get_attribute_ptr(temp, bp[n], &value, &size))
+			continue;
+
+		rv = add_attribute(out, bp[n], value, size);
+		if (rv)
+			return rv;
+	}
+
+	return rv;
+}
+
+/*
+ * Below are listed the mandated or optional expected attributes for
+ * PKCS#11 storage objects.
+ *
+ * Note: boolprops (mandated boolean attributes) SKS_CKA_ALWAYS_SENSITIVE,
+ * and SKS_CKA_NEVER_EXTRACTABLE are set by the token, not provided
+ * in the client template.
+ */
+
+/* PKCS#11 specification for any object (session/token) of the storage */
+static const uint32_t pkcs11_any_object_boolprops[] = {
+	SKS_CKA_TOKEN, SKS_CKA_PRIVATE,
+	SKS_CKA_MODIFIABLE, SKS_CKA_COPYABLE, SKS_CKA_DESTROYABLE,
+};
+static const uint32_t pkcs11_any_object_mandated[] = {
+	SKS_CKA_LABEL,
+};
+/* PKCS#11 specification for raw data object (+pkcs11_any_object_xxx) */
+const uint32_t pkcs11_raw_data_optional[] = {
+	SKS_CKA_OBJECT_ID, SKS_CKA_APPLICATION, SKS_CKA_VALUE,
+};
+/* PKCS#11 specification for any key object (+pkcs11_any_object_xxx) */
+static const uint32_t pkcs11_any_key_boolprops[] = {
+	SKS_CKA_DERIVE,
+};
+static const uint32_t pkcs11_any_key_optional[] = {
+	SKS_CKA_ID,
+	SKS_CKA_START_DATE, SKS_CKA_END_DATE,
+	SKS_CKA_ALLOWED_MECHANISMS,
+};
+/* PKCS#11 specification for any symmetric key (+pkcs11_any_key_xxx) */
+static const uint32_t pkcs11_symm_key_boolprops[] = {
+	SKS_CKA_ENCRYPT, SKS_CKA_DECRYPT, SKS_CKA_SIGN, SKS_CKA_VERIFY,
+	SKS_CKA_WRAP, SKS_CKA_UNWRAP,
+	SKS_CKA_SENSITIVE, SKS_CKA_EXTRACTABLE,
+	SKS_CKA_WRAP_WITH_TRUSTED, SKS_CKA_TRUSTED,
+};
+static const uint32_t pkcs11_symm_key_optional[] = {
+	SKS_CKA_WRAP_TEMPLATE, SKS_CKA_UNWRAP_TEMPLATE, SKS_CKA_DERIVE_TEMPLATE,
+	SKS_CKA_VALUE, SKS_CKA_VALUE_LEN,
+};
+/* PKCS#11 specification for any asymmetric public key (+pkcs11_any_key_xxx) */
+static const uint32_t pkcs11_public_key_boolprops[] = {
+	SKS_CKA_ENCRYPT, SKS_CKA_VERIFY, SKS_CKA_VERIFY_RECOVER, SKS_CKA_WRAP,
+	SKS_CKA_TRUSTED,
+};
+static const uint32_t pkcs11_public_key_mandated[] = {
+	SKS_CKA_SUBJECT
+};
+static const uint32_t pkcs11_public_key_optional[] = {
+	SKS_CKA_WRAP_TEMPLATE, SKS_CKA_PUBLIC_KEY_INFO,
+};
+/* PKCS#11 specification for any asymmetric private key (+pkcs11_any_key_xxx) */
+static const uint32_t pkcs11_private_key_boolprops[] = {
+	SKS_CKA_DECRYPT, SKS_CKA_SIGN, SKS_CKA_SIGN_RECOVER,
+	SKS_CKA_UNWRAP,
+	SKS_CKA_SENSITIVE, SKS_CKA_EXTRACTABLE,
+	SKS_CKA_WRAP_WITH_TRUSTED, SKS_CKA_ALWAYS_AUTHENTICATE,
+};
+static const uint32_t pkcs11_private_key_mandated[] = {
+	SKS_CKA_SUBJECT
+};
+static const uint32_t pkcs11_private_key_optional[] = {
+	SKS_CKA_UNWRAP_TEMPLATE, SKS_CKA_PUBLIC_KEY_INFO,
+};
+/* PKCS#11 specification for any RSA key (+pkcs11_public/private_key_xxx) */
+static const uint32_t pkcs11_rsa_public_key_mandated[] = {
+	SKS_CKA_MODULUS_BITS,
+};
+static const uint32_t pkcs11_rsa_public_key_optional[] = {
+	SKS_CKA_MODULUS, SKS_CKA_PUBLIC_EXPONENT,
+};
+static const uint32_t pkcs11_rsa_private_key_optional[] = {
+	SKS_CKA_MODULUS, SKS_CKA_PUBLIC_EXPONENT, SKS_CKA_PRIVATE_EXPONENT,
+	SKS_CKA_PRIME_1, SKS_CKA_PRIME_2,
+	SKS_CKA_EXPONENT_1, SKS_CKA_EXPONENT_2,	SKS_CKA_COEFFICIENT,
+};
+/* PKCS#11 specification for any EC key (+pkcs11_public/private_key_xxx) */
+static const uint32_t pkcs11_ec_public_key_mandated[] = {
+	SKS_CKA_EC_PARAMS,
+};
+static const uint32_t pkcs11_ec_public_key_optional[] = {
+	SKS_CKA_EC_POINT, SKS_CKA_VALUE, SKS_CKA_VALUE_LEN
+};
+static const uint32_t pkcs11_ec_private_key_mandated[] = {
+	SKS_CKA_EC_PARAMS,
+};
+static const uint32_t pkcs11_ec_private_key_optional[] = {
+	SKS_CKA_VALUE, SKS_CKA_EC_POINT, SKS_CKA_VALUE_LEN
+};
+/* PKCS#11 specification for certificate (+pkcs11_any_object_xxx) */
+static const uint32_t pkcs11_cert_boolprops[] = {
+	SKS_CKA_TRUSTED,
+};
+static const uint32_t pkcs11_cert_mandated[] = {
+	SKS_CKA_CERTIFICATE_CATEGORY,
+};
+static const uint32_t pkcs11_cert_optional[] = {
+	SKS_CKA_START_DATE, SKS_CKA_END_DATE,
+	SKS_CKA_PUBLIC_KEY_INFO,
+};
+static const uint32_t pkcs11_cert_x509_mandated[] = {
+	SKS_CKA_SUBJECT,
+};
+static const uint32_t pkcs11_cert_x509_optional[] = {
+	SKS_CKA_ID, SKS_CKA_ISSUER, SKS_CKA_SERIAL_NUMBER,
+	SKS_CKA_VALUE, SKS_CKA_URL,
+	SKS_CKA_HASH_OF_SUBJECT_PUBLIC_KEY,
+	SKS_CKA_HASH_OF_ISSUER_PUBLIC_KEY,
+	SKS_CKA_NAME_HASH_ALGORITHM,
+};
+
+static uint32_t create_pkcs11_storage_attributes(struct sks_attrs_head **out,
+						 struct sks_attrs_head *temp)
+{
+	uint32_t const *boolprops = &pkcs11_any_object_boolprops[0];
+	uint32_t const *mandated = &pkcs11_any_object_mandated[0];
+	size_t boolprops_count = ARRAY_SIZE(pkcs11_any_object_boolprops);
+	size_t mandated_count = ARRAY_SIZE(pkcs11_any_object_mandated);
+	uint32_t class = 0;
+	uint32_t rv = 0;
+
+	init_attributes_head(out);
+#ifdef SKS_SHEAD_WITH_BOOLPROPS
+	set_attributes_in_head(*out);
+#endif
+
+	/* Object class is mandatory */
+	class = get_class(temp);
+	if (class == SKS_UNDEFINED_ID) {
+		EMSG("Class attribute not found");
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+	rv = add_attribute(out, SKS_CKA_CLASS, &class, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = set_mandatory_boolprops(out, temp, boolprops, boolprops_count);
+	if (rv)
+		return rv;
+
+	return set_mandatory_attributes(out, temp, mandated, mandated_count);
+}
+
+static uint32_t create_pkcs11_genkey_attributes(struct sks_attrs_head **out,
+						struct sks_attrs_head *temp)
+{
+	uint32_t const *boolprops = &pkcs11_any_key_boolprops[0];
+	uint32_t const *optional = &pkcs11_any_key_optional[0];
+	size_t boolprops_count = ARRAY_SIZE(pkcs11_any_key_boolprops);
+	size_t optional_count = ARRAY_SIZE(pkcs11_any_key_optional);
+	uint32_t type = 0;
+	uint32_t rv = 0;
+
+	rv = create_pkcs11_storage_attributes(out, temp);
+	if (rv)
+		return rv;
+
+	type = get_type(temp);
+	if (type == SKS_UNDEFINED_ID) {
+		EMSG("Key type attribute not found");
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+	rv = add_attribute(out, SKS_CKA_KEY_TYPE, &type, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = set_mandatory_boolprops(out, temp, boolprops, boolprops_count);
+	if (rv)
+		return rv;
+
+	return set_optional_attributes(out, temp, optional, optional_count);
+}
+
+static uint32_t create_pkcs11_symm_key_attributes(struct sks_attrs_head **out,
+						  struct sks_attrs_head *temp)
+{
+	uint32_t const *boolprops = &pkcs11_symm_key_boolprops[0];
+	uint32_t const *optional = &pkcs11_symm_key_optional[0];
+	size_t boolprops_count = ARRAY_SIZE(pkcs11_symm_key_boolprops);
+	size_t optional_count = ARRAY_SIZE(pkcs11_symm_key_optional);
+	uint32_t rv = 0;
+
+	assert(get_class(temp) == SKS_CKO_SECRET_KEY);
+
+	rv = create_pkcs11_genkey_attributes(out, temp);
+	if (rv)
+		return rv;
+
+	assert(get_class(*out) == SKS_CKO_SECRET_KEY);
+
+	switch (get_type(*out)) {
+	case SKS_CKK_GENERIC_SECRET:
+	case SKS_CKK_AES:
+	case SKS_CKK_MD5_HMAC:
+	case SKS_CKK_SHA_1_HMAC:
+	case SKS_CKK_SHA256_HMAC:
+	case SKS_CKK_SHA384_HMAC:
+	case SKS_CKK_SHA512_HMAC:
+	case SKS_CKK_SHA224_HMAC:
+		break;
+	default:
+		EMSG("Invalid key type (0x%" PRIx32 ", %s)",
+			get_type(*out), sks2str_key_type(get_type(*out)));
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	rv = set_mandatory_boolprops(out, temp, boolprops, boolprops_count);
+	if (rv)
+		return rv;
+
+	return set_optional_attributes(out, temp, optional, optional_count);
+}
+
+static uint32_t create_pkcs11_data_attributes(struct sks_attrs_head **out,
+					      struct sks_attrs_head *temp)
+{
+	uint32_t rv = 0;
+
+	assert(get_class(temp) == SKS_CKO_DATA);
+
+	rv = create_pkcs11_storage_attributes(out, temp);
+	if (rv)
+		return rv;
+
+	assert(get_class(*out) == SKS_CKO_DATA);
+
+	rv = set_optional_attributes(out, temp,
+				     &pkcs11_raw_data_optional[0],
+				     ARRAY_SIZE(pkcs11_raw_data_optional));
+
+	return rv;
+}
+
+static uint32_t create_pkcs11_pub_key_attributes(struct sks_attrs_head **out,
+						 struct sks_attrs_head *temp)
+{
+	uint32_t rv = 0;
+	uint32_t const *boolprops = &pkcs11_public_key_boolprops[0];
+	uint32_t const *mandated = &pkcs11_public_key_mandated[0];
+	uint32_t const *optional = &pkcs11_public_key_optional[0];
+	size_t boolprops_count = ARRAY_SIZE(pkcs11_public_key_boolprops);
+	size_t mandated_count = ARRAY_SIZE(pkcs11_public_key_mandated);
+	size_t optional_count = ARRAY_SIZE(pkcs11_public_key_optional);
+
+	assert(get_class(temp) == SKS_CKO_PUBLIC_KEY);
+
+	rv = create_pkcs11_genkey_attributes(out, temp);
+	if (rv)
+		return rv;
+
+	assert(get_class(*out) == SKS_CKO_PUBLIC_KEY);
+
+	rv = set_mandatory_boolprops(out, temp, boolprops, boolprops_count);
+	if (rv)
+		return rv;
+
+	rv = set_mandatory_attributes(out, temp, mandated, mandated_count);
+	if (rv)
+		return rv;
+
+	rv = set_optional_attributes(out, temp, optional, optional_count);
+	if (rv)
+		return rv;
+
+	switch (get_type(*out)) {
+	case SKS_CKK_RSA:
+		boolprops = NULL;
+		mandated = &pkcs11_rsa_public_key_mandated[0];
+		optional = &pkcs11_rsa_public_key_optional[0];
+		boolprops_count = 0;
+		mandated_count = ARRAY_SIZE(pkcs11_rsa_public_key_mandated);
+		optional_count = ARRAY_SIZE(pkcs11_rsa_public_key_optional);
+		break;
+	case SKS_CKK_EC:
+		boolprops = NULL;
+		mandated = &pkcs11_ec_public_key_mandated[0];
+		optional = &pkcs11_ec_public_key_optional[0];
+		boolprops_count = 0;
+		mandated_count = ARRAY_SIZE(pkcs11_ec_public_key_mandated);
+		optional_count = ARRAY_SIZE(pkcs11_ec_public_key_optional);
+		break;
+	default:
+		EMSG("Invalid key type (0x%" PRIx32 ", %s)",
+			get_type(*out), sks2str_key_type(get_type(*out)));
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	rv = set_mandatory_boolprops(out, temp, boolprops, boolprops_count);
+	if (rv)
+		return rv;
+
+	rv = set_mandatory_attributes(out, temp, mandated, mandated_count);
+	if (rv)
+		return rv;
+
+	return set_optional_attributes(out, temp, optional, optional_count);
+}
+
+static uint32_t create_pkcs11_priv_key_attributes(struct sks_attrs_head **out,
+						  struct sks_attrs_head *temp)
+{
+	uint32_t const *boolprops = &pkcs11_private_key_boolprops[0];
+	uint32_t const *mandated = &pkcs11_private_key_mandated[0];
+	uint32_t const *optional = &pkcs11_private_key_optional[0];
+	size_t boolprops_count = ARRAY_SIZE(pkcs11_private_key_boolprops);
+	size_t mandated_count = ARRAY_SIZE(pkcs11_private_key_mandated);
+	size_t optional_count = ARRAY_SIZE(pkcs11_private_key_optional);
+	uint32_t rv = 0;
+
+	assert(get_class(temp) == SKS_CKO_PRIVATE_KEY);
+
+	rv = create_pkcs11_genkey_attributes(out, temp);
+	if (rv)
+		return rv;
+
+	assert(get_class(*out) == SKS_CKO_PRIVATE_KEY);
+
+	rv = set_mandatory_boolprops(out, temp, boolprops, boolprops_count);
+	if (rv)
+		return rv;
+
+	rv = set_mandatory_attributes(out, temp, mandated, mandated_count);
+	if (rv)
+		return rv;
+
+	rv = set_optional_attributes(out, temp, optional, optional_count);
+	if (rv)
+		return rv;
+
+	switch (get_type(*out)) {
+	case SKS_CKK_RSA:
+		boolprops = NULL;
+		mandated = NULL;
+		optional = &pkcs11_rsa_private_key_optional[0];
+		boolprops_count = 0;
+		mandated_count = 0;
+		optional_count = ARRAY_SIZE(pkcs11_rsa_private_key_optional);
+		break;
+	case SKS_CKK_EC:
+		boolprops = NULL;
+		mandated = &pkcs11_ec_private_key_mandated[0];
+		optional = &pkcs11_ec_private_key_optional[0];
+		boolprops_count = 0;
+		mandated_count = ARRAY_SIZE(pkcs11_ec_private_key_mandated);
+		optional_count = ARRAY_SIZE(pkcs11_ec_private_key_optional);
+		break;
+	default:
+		EMSG("Invalid key type (0x%" PRIx32 ", %s)",
+			get_type(*out), sks2str_key_type(get_type(*out)));
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	rv = set_mandatory_boolprops(out, temp, boolprops, boolprops_count);
+	if (rv)
+		return rv;
+
+	rv = set_mandatory_attributes(out, temp, mandated, mandated_count);
+	if (rv)
+		return rv;
+
+	return set_optional_attributes(out, temp, optional, optional_count);
+}
+
+static uint32_t create_pkcs11_cert_attributes(struct sks_attrs_head **out,
+					       struct sks_attrs_head *temp)
+{
+	uint32_t const *boolprops = &pkcs11_cert_boolprops[0];
+	uint32_t const *mandated = &pkcs11_cert_mandated[0];
+	uint32_t const *optional = &pkcs11_cert_optional[0];
+	size_t boolprops_count = ARRAY_SIZE(pkcs11_cert_boolprops);
+	size_t mandated_count = ARRAY_SIZE(pkcs11_cert_mandated);
+	size_t optional_count = ARRAY_SIZE(pkcs11_cert_optional);
+	uint32_t type = 0;
+	uint32_t size = 0;
+	void *value = NULL;
+	uint32_t rv = 0;
+
+	assert(get_class(temp) == SKS_CKO_CERTIFICATE);
+
+	rv = create_pkcs11_storage_attributes(out, temp);
+	if (rv)
+		return rv;
+
+	rv = set_mandatory_boolprops(out, temp, boolprops, boolprops_count);
+	if (rv)
+		return rv;
+
+	rv = set_mandatory_attributes(out, temp, mandated, mandated_count);
+	if (rv)
+		return rv;
+
+	rv = set_optional_attributes(out, temp, optional, optional_count);
+	if (rv)
+		return rv;
+
+	type = get_type(temp);
+	switch (type) {
+	case SKS_CKC_X_509:
+		mandated = &pkcs11_cert_x509_mandated[0];
+		optional = &pkcs11_cert_x509_optional[0];
+		mandated_count = ARRAY_SIZE(pkcs11_cert_x509_mandated);
+		optional_count = ARRAY_SIZE(pkcs11_cert_x509_optional);
+
+		rv = get_attribute_ptr(temp, SKS_CKA_URL, &value, &size);
+		if (rv || !size) {
+			/* CKA_URL not available */
+			rv = get_attribute_ptr(temp, SKS_CKA_VALUE,
+					&value, &size);
+			if (rv || !size) {
+				EMSG("CKA_VALUE must be non-empty");
+				return SKS_CKR_TEMPLATE_INCONSISTENT;
+			}
+		} else {
+			/* CKA_URL available, check for hashes */
+			rv = get_attribute_ptr(temp,
+					SKS_CKA_HASH_OF_SUBJECT_PUBLIC_KEY,
+					&value, &size);
+			if (rv || !size) {
+				EMSG("CKA_HASH_OF_SUBJECT_PUBLIC_KEY empty");
+				return SKS_CKR_TEMPLATE_INCONSISTENT;
+			}
+			rv = get_attribute_ptr(temp,
+					SKS_CKA_HASH_OF_ISSUER_PUBLIC_KEY,
+					&value, &size);
+			if (rv || !size) {
+				EMSG("CKA_HASH_OF_ISSUER_PUBLIC_KEY empty");
+				return SKS_CKR_TEMPLATE_INCONSISTENT;
+			}
+		}
+		break;
+	default:
+		EMSG("Invalid certificate type (0x%" PRIx32 ", %s)",
+				type, sks2str_certificate_type(type));
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	rv = add_attribute(out, SKS_CKA_CERTIFICATE_TYPE,
+			   &type, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	/* TODO: CKA_CHECK_VALUE */
+	/* TODO: CKA_PUBLIC_KEY_INFO */
+
+	rv = set_mandatory_attributes(out, temp, mandated, mandated_count);
+	if (rv)
+		return rv;
+
+	return set_optional_attributes(out, temp, optional, optional_count);
+}
+
+/*
+ * Create an attribute list for a new object from a template and a parent
+ * object (optional) for an object generation function (generate, copy,
+ * derive...).
+ *
+ * PKCS#11 directives on the supplied template:
+ * - template has an invalid attribute ID: return ATTRIBUTE_TYPE_INVALID
+ * - template has an invalid value for an attribute: return ATTRIBUTE_VALID_INVALID
+ * - template has value for a read-only attribute: return ATTRIBUTE_READ_ONLY
+ * - template+default+parent => still miss an attribute: return TEMPLATE_INCONSISTENT
+ *
+ * INFO on SKS_CMD_COPY_OBJECT:
+ * - parent SKS_CKA_COPYIABLE=false => return ACTION_PROHIBITED.
+ * - template can specify SKS_CKA_TOKEN, SKS_CKA_PRIVATE, SKS_CKA_MODIFIABLE,
+ *   SKS_CKA_DESTROYABLE.
+ * - SENSITIVE can change from false to true, not from true to false.
+ * - LOCAL is the parent LOCAL
+ */
+uint32_t create_attributes_from_template(struct sks_attrs_head **out,
+					 void *template, size_t template_size,
+					 uint32_t proc_id,
+					 struct sks_attrs_head *parent,
+					 enum processing_func function)
+{
+	struct sks_attrs_head *temp = NULL;
+	struct sks_attrs_head *attrs = NULL;
+	uint32_t rv = 0;
+	uint32_t key_gen_m = 0;
+	uint8_t local = 0;
+	uint8_t always_sensitive = 0;
+	uint8_t never_extract = 0;
+	uint32_t class = SKS_UNDEFINED_ID;
+	uint32_t type = SKS_UNDEFINED_ID;
+
+#ifdef DEBUG	/* Sanity: check function argument */
+	trace_attributes_from_api_head("template", template, template_size);
+	switch (function) {
+	case SKS_FUNCTION_GENERATE:
+	case SKS_FUNCTION_GENERATE_PAIR:
+	case SKS_FUNCTION_IMPORT:
+		break;
+	case SKS_FUNCTION_DERIVE:
+		trace_attributes("parent", parent);
+		break;
+	default:
+		TEE_Panic(TEE_ERROR_NOT_SUPPORTED);
+	}
+#endif
+
+	rv = sanitize_client_object(&temp, template, template_size);
+	if (rv)
+		goto bail;
+
+	/* If class/type not defined, match from mechanism */
+	if (get_class(temp) == SKS_UNDEFINED_ID &&
+			get_type(temp) == SKS_UNDEFINED_ID) {
+		switch (proc_id) {
+		case SKS_CKM_GENERIC_SECRET_KEY_GEN:
+			class = SKS_CKO_SECRET_KEY;
+			type = SKS_CKK_GENERIC_SECRET;
+			break;
+		case SKS_CKM_AES_KEY_GEN:
+			class = SKS_CKO_SECRET_KEY;
+			type = SKS_CKK_AES;
+			break;
+		case SKS_CKM_EC_KEY_PAIR_GEN:
+			type = SKS_CKK_DH;
+			break;
+		case SKS_CKM_RSA_PKCS_KEY_PAIR_GEN:
+			type = SKS_CKK_RSA;
+			break;
+		default:
+			EMSG("Unable to define class/type from mechanism");
+			rv = SKS_CKR_TEMPLATE_INCOMPLETE;
+			goto bail;
+		}
+		if (class != SKS_UNDEFINED_ID)
+			add_attribute(&temp, SKS_CKA_CLASS,
+						&class, sizeof(uint32_t));
+		if (type != SKS_UNDEFINED_ID)
+			add_attribute(&temp, SKS_CKA_KEY_TYPE,
+						&type, sizeof(uint32_t));
+	}
+
+	if (!sanitize_consistent_class_and_type(temp)) {
+		EMSG("inconsistent class/type");
+		rv = SKS_CKR_TEMPLATE_INCONSISTENT;
+		goto bail;
+	}
+
+	switch (get_class(temp)) {
+	case SKS_CKO_DATA:
+		rv = create_pkcs11_data_attributes(&attrs, temp);
+		break;
+	case SKS_CKO_SECRET_KEY:
+		rv = create_pkcs11_symm_key_attributes(&attrs, temp);
+		break;
+	case SKS_CKO_PUBLIC_KEY:
+		rv = create_pkcs11_pub_key_attributes(&attrs, temp);
+		break;
+	case SKS_CKO_PRIVATE_KEY:
+		rv = create_pkcs11_priv_key_attributes(&attrs, temp);
+		break;
+	case SKS_CKO_CERTIFICATE:
+		rv = create_pkcs11_cert_attributes(&attrs, temp);
+		break;
+	default:
+		DMSG("Invalid object class 0x%" PRIx32 "/%s",
+			get_class(temp), sks2str_class(get_class(temp)));
+		rv = SKS_CKR_TEMPLATE_INCONSISTENT;
+		break;
+	}
+	if (rv)
+		goto bail;
+
+	switch (get_class(attrs)) {
+	case SKS_CKO_SECRET_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+	case SKS_CKO_PUBLIC_KEY:
+		assert(get_attribute(attrs, SKS_CKA_LOCAL, NULL, NULL) ==
+			SKS_NOT_FOUND);
+
+		local = SKS_FALSE;
+		always_sensitive = SKS_FALSE;
+		never_extract = SKS_FALSE;
+
+		switch (function) {
+		case SKS_FUNCTION_GENERATE:
+			always_sensitive = get_bool(attrs, SKS_CKA_SENSITIVE);
+			never_extract = !get_bool(attrs, SKS_CKA_EXTRACTABLE);
+			local = SKS_TRUE;
+			break;
+		case SKS_FUNCTION_GENERATE_PAIR:
+			local = SKS_TRUE;
+			break;
+		case SKS_FUNCTION_DERIVE:
+			always_sensitive =
+				get_bool(parent, SKS_CKA_ALWAYS_SENSITIVE) &&
+				get_bool(attrs, SKS_CKA_SENSITIVE);
+			never_extract =
+				get_bool(parent, SKS_CKA_NEVER_EXTRACTABLE) &&
+				!get_bool(attrs, SKS_CKA_EXTRACTABLE);
+			break;
+		case SKS_FUNCTION_COPY:
+			always_sensitive =
+				get_bool(parent, SKS_CKA_ALWAYS_SENSITIVE) &&
+				get_bool(attrs, SKS_CKA_SENSITIVE);
+			never_extract =
+				get_bool(parent, SKS_CKA_NEVER_EXTRACTABLE) &&
+				!get_bool(attrs, SKS_CKA_EXTRACTABLE);
+			local = get_bool(parent, SKS_CKA_LOCAL);
+			break;
+		default:
+			break;
+		}
+
+		rv = add_attribute(&attrs, SKS_CKA_LOCAL,
+				   &local, sizeof(local));
+		if (rv)
+			goto bail;
+
+		/* TODO: Set valid key gen mechanism when local */
+		if (local == SKS_FALSE) {
+			key_gen_m = SKS_CK_UNAVAILABLE_INFORMATION;
+			rv = add_attribute(&attrs, SKS_CKA_KEY_GEN_MECHANISM,
+					&key_gen_m, sizeof(key_gen_m));
+			if (rv)
+				goto bail;
+		}
+
+		rv = add_attribute(&attrs, SKS_CKA_ALWAYS_SENSITIVE,
+				   &always_sensitive, sizeof(always_sensitive));
+		if (rv)
+			goto bail;
+
+		rv = add_attribute(&attrs, SKS_CKA_NEVER_EXTRACTABLE,
+				   &never_extract, sizeof(never_extract));
+		if (rv)
+			goto bail;
+
+		break;
+
+	default:
+		break;
+	}
+
+	*out = attrs;
+
+#ifdef DEBUG
+	trace_attributes("object", attrs);
+#endif
+
+bail:
+	TEE_Free(temp);
+	if (rv)
+		TEE_Free(attrs);
+
+	return rv;
+}
+
+static uint32_t check_attrs_misc_integrity(struct sks_attrs_head *head)
+{
+	/* FIXME: is it useful? */
+	if (get_bool(head, SKS_CKA_NEVER_EXTRACTABLE) &&
+	    get_bool(head, SKS_CKA_EXTRACTABLE)) {
+		DMSG("Never/Extractable attributes mismatch %d/%d",
+			get_bool(head, SKS_CKA_NEVER_EXTRACTABLE),
+			get_bool(head, SKS_CKA_EXTRACTABLE));
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	if (get_bool(head, SKS_CKA_ALWAYS_SENSITIVE) &&
+	    !get_bool(head, SKS_CKA_SENSITIVE)) {
+		DMSG("Sensitive/always attributes mismatch %d/%d",
+			get_bool(head, SKS_CKA_SENSITIVE),
+			get_bool(head, SKS_CKA_ALWAYS_SENSITIVE));
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	return SKS_OK;
+}
+
+/*
+ * Check access to object against authentication to token
+ */
+uint32_t check_access_attrs_against_token(struct pkcs11_session *session,
+					  struct sks_attrs_head *head)
+{
+	bool private = true;
+
+	switch(get_class(head)) {
+	case SKS_CKO_SECRET_KEY:
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_CERTIFICATE:
+	case SKS_CKO_DATA:
+		if (!get_bool(head, SKS_CKA_PRIVATE))
+			private = false;
+		break;
+	case SKS_CKO_PRIVATE_KEY:
+		break;
+	default:
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+
+	if (private && pkcs11_session_is_public(session)) {
+		DMSG("Private object access from a public session");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+
+	/*
+	 * TODO: START_DATE and END_DATE: complies with current time?
+	 */
+	return SKS_OK;
+}
+
+/*
+ * Check the attributes of a to-be-created object matches the token state
+ */
+uint32_t check_created_attrs_against_token(struct pkcs11_session *session,
+					   struct sks_attrs_head *head)
+{
+	uint32_t rc = 0;
+
+	rc = check_attrs_misc_integrity(head);
+	if (rc)
+		return rc;
+
+	if (get_bool(head, SKS_CKA_TRUSTED) &&
+	    !pkcs11_session_is_security_officer(session)) {
+		DMSG("Can't create trusted object");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+
+	if (get_bool(head, SKS_CKA_TOKEN) &&
+	    !pkcs11_session_is_read_write(session)) {
+		DMSG("Can't create persistent object");
+		return SKS_CKR_SESSION_READ_ONLY;
+	}
+
+	/*
+	 * TODO: START_DATE and END_DATE: complies with current time?
+	 */
+	return SKS_OK;
+}
+
+/*
+ * Check the attributes of new secret match the requirements of the parent key.
+ */
+uint32_t check_created_attrs_against_parent_key(
+					uint32_t proc_id __unused,
+					struct sks_attrs_head *parent __unused,
+					struct sks_attrs_head *head __unused)
+{
+	/*
+	 * TODO
+	 * Depends on the processing§/mechanism used.
+	 * Wrapping: check head vs parent key WRAP_TEMPLATE attribute.
+	 * Unwrapping: check head vs parent key UNWRAP_TEMPLATE attribute.
+	 * Derive: check head vs parent key DERIVE_TEMPLATE attribute (late comer?).
+	 */
+	return SKS_ERROR;
+}
+
+#define DMSG_BAD_BBOOL(attr, proc, head) \
+	do {	\
+		uint8_t __maybe_unused bvalue = 0;		\
+								\
+		DMSG("%s issue for %s: %sfound, value %d",	\
+			sks2str_attr(attr),			\
+			sks2str_proc(proc),			\
+			get_attribute(head, attr, &bvalue, NULL) ? \
+			"not " : "",				\
+			bvalue);				\
+	} while (0)
+
+/*
+ * Check the attributes of a new secret match the processing/mechanism
+ * used to create it.
+ *
+ * @proc_id - SKS_CKM__xxx
+ * @subproc_id - boolean attribute id as encrypt/decrypt/sign/verify,
+ *		 if applicable to proc_id.
+ * @head - head of the attributes of the to-be-created object.
+ */
+uint32_t check_created_attrs_against_processing(uint32_t proc_id,
+						struct sks_attrs_head *head)
+{
+	uint8_t bbool = 0;
+
+	/*
+	 * Processing that do not create secrets are not expected to call
+	 * this function which would panic.
+	 */
+	/*
+	 * FIXME: really need to check LOCAL here, it was safely set from
+	 * create_attributes_from_template().
+	 */
+	switch (proc_id) {
+	case SKS_PROCESSING_IMPORT:
+	case SKS_CKM_ECDH1_DERIVE:
+	case SKS_CKM_ECDH1_COFACTOR_DERIVE:
+	case SKS_CKM_DH_PKCS_DERIVE:
+		if (get_class(head) != SKS_CKO_CERTIFICATE &&
+		    get_class(head) != SKS_CKO_DATA &&
+		    (get_attribute(head, SKS_CKA_LOCAL, &bbool, NULL) ||
+		    bbool)) {
+			DMSG_BAD_BBOOL(SKS_CKA_LOCAL, proc_id, head);
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		}
+		break;
+	case SKS_CKM_GENERIC_SECRET_KEY_GEN:
+	case SKS_CKM_AES_KEY_GEN:
+	case SKS_CKM_EC_KEY_PAIR_GEN:
+	case SKS_CKM_RSA_PKCS_KEY_PAIR_GEN:
+	case SKS_CKM_MTK_HSM_AES_KEY_GEN:
+	case SKS_CKM_MTK_HSM_EC_KEY_PAIR_GEN:
+	case SKS_CKM_MTK_HSM_EC_KEY_PAIR_IMPORT:
+		if (get_attribute(head, SKS_CKA_LOCAL, &bbool, NULL) ||
+		    !bbool) {
+			DMSG_BAD_BBOOL(SKS_CKA_LOCAL, proc_id, head);
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		}
+		break;
+	default:
+		TEE_Panic(proc_id);
+		break;
+	}
+
+	switch (proc_id) {
+	case SKS_CKM_GENERIC_SECRET_KEY_GEN:
+		if (get_type(head) != SKS_CKK_GENERIC_SECRET)
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		break;
+	case SKS_CKM_AES_KEY_GEN:
+		if (get_type(head) != SKS_CKK_AES)
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		break;
+	case SKS_CKM_EC_KEY_PAIR_GEN:
+		if (get_type(head) != SKS_CKK_EC)
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		break;
+	case SKS_CKM_RSA_PKCS_KEY_PAIR_GEN:
+		if (get_type(head) != SKS_CKK_RSA)
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		break;
+	case SKS_CKM_ECDH1_DERIVE:
+	case SKS_CKM_ECDH1_COFACTOR_DERIVE:
+	case SKS_CKM_DH_PKCS_DERIVE:
+		if (get_class(head) != SKS_CKO_SECRET_KEY)
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		break;
+	case SKS_PROCESSING_IMPORT:
+	default:
+		break;
+	}
+
+	return SKS_OK;
+}
+
+void pkcs11_max_min_key_size(uint32_t key_type, uint32_t *max_key_size,
+			     uint32_t *min_key_size, bool bit_size_only)
+{
+	uint32_t mult = bit_size_only ? 8 : 1;
+
+	switch (key_type) {
+	case SKS_CKK_GENERIC_SECRET:
+		*min_key_size = 1;	/* in bits */
+		*max_key_size = 4096;	/* in bits */
+		break;
+	case SKS_CKK_MD5_HMAC:
+		*min_key_size = 16 * mult;
+		*max_key_size = 16 * mult;
+		break;
+	case SKS_CKK_SHA_1_HMAC:
+		*min_key_size = 20 * mult;
+		*max_key_size = 20 * mult;
+		break;
+	case SKS_CKK_SHA224_HMAC:
+		*min_key_size = 28 * mult;
+		*max_key_size = 28 * mult;
+		break;
+	case SKS_CKK_SHA256_HMAC:
+		*min_key_size = 32 * mult;
+		*max_key_size = 32 * mult;
+		break;
+	case SKS_CKK_SHA384_HMAC:
+		*min_key_size = 48 * mult;
+		*max_key_size = 48 * mult;
+		break;
+	case SKS_CKK_SHA512_HMAC:
+		*min_key_size = 64 * mult;
+		*max_key_size = 64 * mult;
+		break;
+	case SKS_CKK_AES:
+		*min_key_size = 16 * mult;
+		*max_key_size = 32 * mult;
+		break;
+	case SKS_CKK_EC:
+		*min_key_size = 192;	/* in bits */
+		*max_key_size = 521;	/* in bits */
+		break;
+	case SKS_CKK_RSA:
+	case SKS_CKK_DSA:
+	case SKS_CKK_DH:
+		*min_key_size = 256;	/* in bits */
+		*max_key_size = 4096;	/* in bits */
+		break;
+	default:
+		TEE_Panic(key_type);
+		break;
+	}
+}
+
+uint32_t check_created_attrs(struct sks_attrs_head *key1,
+			     struct sks_attrs_head *key2)
+{
+	struct sks_attrs_head *secret = NULL;
+	struct sks_attrs_head *private = NULL;
+	struct sks_attrs_head *public = NULL;
+	uint32_t max_key_size = 0;
+	uint32_t min_key_size = 0;
+	uint32_t key_length = 0;
+	uint32_t rv = 0;
+
+	switch (get_class(key1)) {
+	case SKS_CKO_SECRET_KEY:
+		secret = key1;
+		break;
+	case SKS_CKO_PUBLIC_KEY:
+		public = key1;
+		break;
+	case SKS_CKO_PRIVATE_KEY:
+		private = key1;
+		break;
+	default:
+		return SKS_CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+
+	if (key2) {
+		switch (get_class(key2)) {
+		case SKS_CKO_PUBLIC_KEY:
+			public = key2;
+			if (private == key1)
+				break;
+
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		case SKS_CKO_PRIVATE_KEY:
+			private = key2;
+			if (public == key1)
+				break;
+
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		default:
+			return SKS_CKR_ATTRIBUTE_VALUE_INVALID;
+		}
+
+		if (get_type(private) != get_type(public))
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	if (secret) {
+		switch (get_type(secret)) {
+		case SKS_CKK_AES:
+		case SKS_CKK_GENERIC_SECRET:
+		case SKS_CKK_MD5_HMAC:
+		case SKS_CKK_SHA_1_HMAC:
+		case SKS_CKK_SHA224_HMAC:
+		case SKS_CKK_SHA256_HMAC:
+		case SKS_CKK_SHA384_HMAC:
+		case SKS_CKK_SHA512_HMAC:
+			break;
+		default:
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		}
+
+		/* Get key size */
+		rv = get_u32_attribute(secret, SKS_CKA_VALUE_LEN, &key_length);
+		if (rv)
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+	if (public) {
+		switch (get_type(public)) {
+		case SKS_CKK_RSA:
+		case SKS_CKK_DSA:
+		case SKS_CKK_DH:
+			/* Get key size */
+			rv = get_u32_attribute(public, SKS_CKA_MODULUS_BITS,
+						&key_length);
+			if (rv)
+				return SKS_CKR_TEMPLATE_INCONSISTENT;
+			break;
+		case SKS_CKK_EC:
+			break;
+		default:
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		}
+	}
+	if (private) {
+		switch (get_type(private)) {
+		case SKS_CKK_RSA:
+		case SKS_CKK_DSA:
+		case SKS_CKK_DH:
+			/* Get key size, if key pair public carries bit size */
+			if (public)
+				break;
+
+			rv = get_u32_attribute(private, SKS_CKA_MODULUS_BITS,
+						&key_length);
+			if (rv)
+				return SKS_CKR_TEMPLATE_INCONSISTENT;
+			break;
+		case SKS_CKK_EC:
+			/* No need to get key size */
+			break;
+		default:
+			return SKS_CKR_TEMPLATE_INCONSISTENT;
+		}
+	}
+
+	/*
+	 * Check key size for symmetric keys and RSA keys
+	 * EC is bound to domains, no need to check here.
+	 */
+	switch (get_type(key1)) {
+	case SKS_CKK_EC:
+		return SKS_OK;
+	default:
+		break;
+	}
+
+	pkcs11_max_min_key_size(get_type(key1),
+				&max_key_size, &min_key_size, false);
+
+	if (key_length < min_key_size || key_length > max_key_size) {
+		EMSG("Length %" PRIu32 " vs range [%" PRIu32 " %" PRIu32 "]",
+			key_length, min_key_size, max_key_size);
+		return SKS_CKR_KEY_SIZE_RANGE;
+	}
+
+	return SKS_OK;
+}
+
+/* Check processing ID against attribute ALLOWED_PROCESSINGS if any */
+static bool parent_key_complies_allowed_processings(uint32_t proc_id,
+						    struct sks_attrs_head *head)
+{
+	char *attr = NULL;
+	uint32_t size = 0;
+	uint32_t proc = 0;
+	size_t count = 0;
+
+	/* Check only if restricted allowed mechanisms list is defined */
+	if (get_attribute_ptr(head, SKS_CKA_ALLOWED_MECHANISMS,
+			      (void *)&attr, &size) != SKS_OK) {
+		return true;
+	}
+
+	for (count = size / sizeof(uint32_t); count; count--) {
+		TEE_MemMove(&proc, attr, sizeof(uint32_t));
+		attr += sizeof(uint32_t);
+
+		if (proc == proc_id)
+			return true;
+	}
+
+	DMSG("can't find %s in allowed list", sks2str_proc(proc_id));
+	return false;
+}
+
+/*
+ * Check the attributes of the parent secret (key) used in the processing
+ * do match the target processing.
+ *
+ * @proc_id - SKS_CKM_xxx
+ * @subproc_id - boolean attribute encrypt or decrypt or sign or verify, if
+ *		 applicable to proc_id.
+ * @head - head of the attributes of parent object.
+ */
+uint32_t check_parent_attrs_against_processing(uint32_t proc_id,
+					       enum processing_func function,
+					       struct sks_attrs_head *head)
+{
+	uint32_t __maybe_unused rc = 0;
+	uint32_t key_class = get_class(head);
+	uint32_t key_type = get_type(head);
+
+	if (function == SKS_FUNCTION_ENCRYPT &&
+	    !get_bool(head, SKS_CKA_ENCRYPT)) {
+		DMSG("encrypt not permitted");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+	if (function == SKS_FUNCTION_DECRYPT &&
+	    !get_bool(head, SKS_CKA_DECRYPT)) {
+		DMSG("decrypt not permitted");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+	if (function == SKS_FUNCTION_SIGN &&
+	    !get_bool(head, SKS_CKA_SIGN)) {
+		DMSG("sign not permitted");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+	if (function == SKS_FUNCTION_VERIFY &&
+	    !get_bool(head, SKS_CKA_VERIFY)) {
+		DMSG("verify not permitted");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+	if (function == SKS_FUNCTION_WRAP &&
+	    !get_bool(head, SKS_CKA_WRAP)) {
+		DMSG("wrap not permitted");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+	if (function == SKS_FUNCTION_UNWRAP &&
+	    !get_bool(head, SKS_CKA_UNWRAP)) {
+		DMSG("unwrap not permitted");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+	if (function == SKS_FUNCTION_DERIVE &&
+	    !get_bool(head, SKS_CKA_DERIVE)) {
+		DMSG("derive not permitted");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+
+	/* Check processing complies for parent key family */
+	switch (proc_id) {
+	case SKS_CKM_AES_ECB:
+	case SKS_CKM_AES_CBC:
+	case SKS_CKM_AES_CBC_PAD:
+	case SKS_CKM_AES_CTS:
+	case SKS_CKM_AES_CTR:
+	case SKS_CKM_AES_GCM:
+	case SKS_CKM_AES_CCM:
+	case SKS_CKM_AES_CMAC:
+	case SKS_CKM_AES_CMAC_GENERAL:
+	case SKS_CKM_AES_XCBC_MAC:
+	case SKS_CKM_MTK_HSM_AES_ECB:
+	case SKS_CKM_MTK_HSM_AES_CBC:
+	case SKS_CKM_MTK_HSM_AES_CTR:
+	case SKS_CKM_MTK_HSM_AES_GCM:
+	case SKS_CKM_MTK_HSM_AES_CMAC:
+		if (key_class == SKS_CKO_SECRET_KEY &&
+		    key_type == SKS_CKK_AES)
+			break;
+
+		DMSG("%s invalid key %s/%s", sks2str_proc(proc_id),
+			sks2str_class(key_class), sks2str_key_type(key_type));
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+	case SKS_CKM_MD5_HMAC:
+	case SKS_CKM_SHA_1_HMAC:
+	case SKS_CKM_SHA224_HMAC:
+	case SKS_CKM_SHA256_HMAC:
+	case SKS_CKM_SHA384_HMAC:
+	case SKS_CKM_SHA512_HMAC:
+	case SKS_CKM_MTK_HSM_SHA256_HMAC:
+	case SKS_CKM_MTK_HSM_SHA384_HMAC:
+		if (key_class != SKS_CKO_SECRET_KEY)
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+		if (key_type == SKS_CKK_GENERIC_SECRET)
+			break;
+
+		switch (proc_id) {
+		case SKS_CKM_MD5_HMAC:
+			if (key_type == SKS_CKK_MD5_HMAC)
+				break;
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+		case SKS_CKM_SHA_1_HMAC:
+			if (key_type == SKS_CKK_SHA_1_HMAC)
+				break;
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+		case SKS_CKM_SHA224_HMAC:
+			if (key_type == SKS_CKK_SHA224_HMAC)
+				break;
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+		case SKS_CKM_SHA256_HMAC:
+		case SKS_CKM_MTK_HSM_SHA256_HMAC:
+			if (key_type == SKS_CKK_SHA256_HMAC)
+				break;
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+		case SKS_CKM_SHA384_HMAC:
+		case SKS_CKM_MTK_HSM_SHA384_HMAC:
+			if (key_type == SKS_CKK_SHA384_HMAC)
+				break;
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+		case SKS_CKM_SHA512_HMAC:
+			if (key_type == SKS_CKK_SHA512_HMAC)
+				break;
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+		default:
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+		}
+		break;
+
+	case SKS_CKM_ECDSA:
+	case SKS_CKM_ECDSA_SHA1:
+	case SKS_CKM_ECDSA_SHA224:
+	case SKS_CKM_ECDSA_SHA256:
+	case SKS_CKM_ECDSA_SHA384:
+	case SKS_CKM_ECDSA_SHA512:
+	case SKS_CKM_ECDH1_DERIVE:
+	case SKS_CKM_ECDH1_COFACTOR_DERIVE:
+	case SKS_CKM_ECMQV_DERIVE:
+	case SKS_CKM_ECDH_AES_KEY_WRAP:
+	case SKS_CKM_MTK_HSM_ECDSA:
+	case SKS_CKM_MTK_HSM_ECDSA_SHA1:
+	case SKS_CKM_MTK_HSM_ECDSA_SHA224:
+	case SKS_CKM_MTK_HSM_ECDSA_SHA256:
+	case SKS_CKM_MTK_HSM_ECDSA_SHA384:
+	case SKS_CKM_MTK_HSM_ECDSA_SHA512:
+		if (key_type != SKS_CKK_EC) {
+			EMSG("Invalid key %s for mechanism %s",
+				sks2str_type(key_type, key_class),
+				sks2str_proc(proc_id));
+			return SKS_CKR_KEY_TYPE_INCONSISTENT;
+		}
+		if (key_class != SKS_CKO_PUBLIC_KEY &&
+		     key_class != SKS_CKO_PRIVATE_KEY) {
+			EMSG("Invalid key class for mechanism %s",
+				sks2str_proc(proc_id));
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+		}
+		break;
+
+	case SKS_CKM_RSA_PKCS:
+	case SKS_CKM_RSA_9796:
+	case SKS_CKM_RSA_X_509:
+	case SKS_CKM_SHA1_RSA_PKCS:
+	case SKS_CKM_RSA_PKCS_OAEP:
+	case SKS_CKM_SHA1_RSA_PKCS_PSS:
+	case SKS_CKM_SHA256_RSA_PKCS:
+	case SKS_CKM_SHA384_RSA_PKCS:
+	case SKS_CKM_SHA512_RSA_PKCS:
+	case SKS_CKM_SHA256_RSA_PKCS_PSS:
+	case SKS_CKM_SHA384_RSA_PKCS_PSS:
+	case SKS_CKM_SHA512_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS:
+	case SKS_CKM_SHA224_RSA_PKCS_PSS:
+	case SKS_CKM_RSA_AES_KEY_WRAP:
+		if (key_type != SKS_CKK_RSA) {
+			EMSG("Invalid key %s for mechanism %s",
+				sks2str_type(key_type, key_class),
+				sks2str_proc(proc_id));
+			return SKS_CKR_KEY_TYPE_INCONSISTENT;
+		}
+		if (key_class != SKS_CKO_PUBLIC_KEY &&
+		     key_class != SKS_CKO_PRIVATE_KEY) {
+			EMSG("Invalid key class for mechanism %s",
+				sks2str_proc(proc_id));
+			return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+		}
+		break;
+
+	case SKS_CKM_MTK_HSM_SHA1:
+	case SKS_CKM_MTK_HSM_SHA224:
+	case SKS_CKM_MTK_HSM_SHA256:
+	case SKS_CKM_MTK_HSM_SHA384:
+	case SKS_CKM_MTK_HSM_SHA512:
+	case SKS_CKM_MTK_HSM_AES_KEY_GEN:
+	case SKS_CKM_MTK_HSM_EC_KEY_PAIR_GEN:
+	case SKS_CKM_MTK_HSM_EC_KEY_PAIR_IMPORT:
+		break;
+
+	default:
+		DMSG("Invalid processing 0x%" PRIx32 " (%s)", proc_id,
+			sks2str_proc(proc_id));
+		return SKS_CKR_MECHANISM_INVALID;
+	}
+	if (!parent_key_complies_allowed_processings(proc_id, head)) {
+		DMSG("Allowed mechanism failed");
+		return SKS_CKR_KEY_FUNCTION_NOT_PERMITTED;
+	}
+	return SKS_OK;
+}
+
+bool object_is_private(struct sks_attrs_head *head)
+{
+	if (get_class(head) == SKS_CKO_PRIVATE_KEY)
+		return true;
+
+	if (get_bool(head, SKS_CKA_PRIVATE))
+		return true;
+
+	return false;
+}
+
+/*
+ * Add a CKA ID attribute to an object or paired object if missing.
+ * If 2 objects are provided and at least 1 does not have a CKA_ID,
+ * the 2 objects will have the same CKA_ID attribute.
+ *
+ * @attrs1 - Object
+ * @attrs2 - Object paired to attrs1 or NULL
+ * Return an SKS return code
+ */
+uint32_t add_missing_attribute_id(struct sks_attrs_head **attrs1,
+				  struct sks_attrs_head **attrs2)
+{
+	uint32_t rv = 0;
+	void *id1 = NULL;
+	uint32_t id1_size = 0;
+	void *id2 = NULL;
+	uint32_t id2_size = 0;
+
+	rv = get_attribute_ptr(*attrs1, SKS_CKA_ID, &id1, &id1_size);
+	if (rv) {
+		if (rv != SKS_NOT_FOUND)
+			return rv;
+		id1 = NULL;
+	}
+
+	if (attrs2) {
+		rv = get_attribute_ptr(*attrs2, SKS_CKA_ID, &id2, &id2_size);
+		if (rv) {
+			if (rv != SKS_NOT_FOUND)
+				return rv;
+			id2 = NULL;
+		}
+
+		if (id1 && id2)
+			return SKS_OK;
+
+		if (id1 && !id2)
+			return add_attribute(attrs2, SKS_CKA_ID, id1, id1_size);
+
+		if (!id1 && id2)
+			return add_attribute(attrs1, SKS_CKA_ID, id2, id2_size);
+	} else {
+		if (id1)
+			return SKS_OK;
+	}
+
+	id1_size = SKS_CKA_DEFAULT_SIZE;
+	id1 = TEE_Malloc(id1_size, 0);
+	if (!id1)
+		return SKS_MEMORY;
+
+	TEE_GenerateRandom(id1, (uint32_t)id1_size);
+
+	rv = add_attribute(attrs1, SKS_CKA_ID, id1, id1_size);
+	if (rv == SKS_OK && attrs2)
+		rv = add_attribute(attrs2, SKS_CKA_ID, id1, id1_size);
+
+	TEE_Free(id1);
+
+	return rv;
+}
+
+bool attribute_is_exportable(struct sks_attribute_head *req_attr,
+			     struct sks_object *obj)
+{
+	uint8_t boolval = 0;
+	uint32_t boolsize = 0;
+	uint32_t rv = 0;
+
+	switch (req_attr->id) {
+	case SKS_CKA_PRIVATE_EXPONENT:
+	case SKS_CKA_PRIME_1:
+	case SKS_CKA_PRIME_2:
+	case SKS_CKA_EXPONENT_1:
+	case SKS_CKA_EXPONENT_2:
+	case SKS_CKA_COEFFICIENT:
+		boolsize = sizeof(boolval);
+		rv = get_attribute(obj->attributes, SKS_CKA_EXTRACTABLE,
+				   &boolval, &boolsize);
+		if (rv || boolval == SKS_FALSE)
+			return false;
+
+		boolsize = sizeof(boolval);
+		rv = get_attribute(obj->attributes, SKS_CKA_SENSITIVE,
+				   &boolval, &boolsize);
+		if (rv || boolval == SKS_TRUE)
+			return false;
+		break;
+	default:
+		break;
+	}
+
+	return true;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.h
new file mode 100644
index 0000000..dad8414
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_attributes.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __PKCS11_ATTRIBUTE_H
+#define __PKCS11_ATTRIBUTE_H
+
+#include <inttypes.h>
+
+#include "serializer.h"
+
+/*
+ * PKCS#11 directives on object attributes.
+ * Those with a '*' are optional, other must be defined, either by caller
+ * or by some known default value.
+ *
+ * [all] objects:	class
+ *
+ * [stored] objects:	persistent, need_authen, modifiable, copyable,
+ *			destroyable, label*.
+ *
+ * [data] objects:	[all], [stored], application_id*, object_id*, value.
+ *
+ * [key] objects:	[all], [stored], type, id*, start_date/end_date*,
+ *			derive, local, allowed_mechanisms*.
+ *
+ * [symm-key]:		[key], sensitive, encrypt, decrypt, sign, verify, wrap,
+ *			unwrap, extractable, wrap_with_trusted, trusted,
+ *			wrap_template, unwrap_template, derive_template.
+ */
+
+/*
+ * Utils to check compliance of attributes at various processing steps.
+ * Any processing operation is exclusively one of the following.
+ *
+ * Case 1: Create a secret from some local random value (C_CreateKey & friends)
+ * - client provides a attributes list template, pkcs11 complete with default
+ *   attribute values. Object is created if attributes are consistent and
+ *   comply token/session stte.
+ * - SKS sequence:
+ *   - check/set token/session state
+ *   - create a attribute list from client template and default values.
+ *   - check new secret attributes complies requested mechanism .
+ *   - check new secret attributes complies token/session state.
+ *   - Generate the value for the secret.
+ *   - Set some runtime attributes in the new secret.
+ *   - Register the new secret and return a handle for it.
+
+ *
+ * Case 2: Create a secret from a client clear data (C_CreateObject)
+ * - client provides a attributes list template, pkcs11 complete with default
+ *   attribute values. Object is created if attributes are consistent and
+ *   comply token/session state.
+ *   - check/set token/session state
+ *   - create a attribute list from client template and default values.
+ *   - check new secret attributes complies requested mechanism (raw-import).
+ *   - check new secret attributes complies token/session state.
+ *   - Set some runtime attributes in the new secret.
+ *   - Register the new secret and return a handle for it.
+
+ * Case 3: Use a secret for data processing
+ * - client provides a mechanism ID and the secret handle.
+ * - SKS checks mechanism and secret comply, if mechanism and token/session
+ *   state comply and last if secret and token/session state comply.
+ *   - check/set token/session state
+ *   - check secret's parent attributes complies requested processing.
+ *   - check secret's parent attributes complies token/session state.
+ *   - check new secret attributes complies secret's parent attributes.
+ *   - check new secret attributes complies requested mechanism.
+ *   - check new secret attributes complies token/session state.
+ *
+ * Case 4: Create a secret from a client template and a secret's parent
+ * (i.e derive a symmetric key)
+ * - client args: new-key template, mechanism ID, parent-key handle.
+ * - SKS create a new-key attribute list based on template + default values +
+ *   inheritance from the parent key attributes.
+ * - SKS checks:
+ *   - token/session state
+ *   - parent-key vs mechanism
+ *   - parent-key vs token/session state
+ *   - parent-key vs new-key
+ *   - new-key vs mechanism
+ *   - new-key vs token/session state
+ * - then do processing
+ * - then finalize object creation
+ */
+
+enum processing_func {
+	SKS_FUNCTION_DIGEST,
+	SKS_FUNCTION_GENERATE,
+	SKS_FUNCTION_GENERATE_PAIR,
+	SKS_FUNCTION_DERIVE,
+	SKS_FUNCTION_WRAP,
+	SKS_FUNCTION_UNWRAP,
+	SKS_FUNCTION_ENCRYPT,
+	SKS_FUNCTION_DECRYPT,
+	SKS_FUNCTION_SIGN,
+	SKS_FUNCTION_VERIFY,
+	SKS_FUNCTION_SIGN_RECOVER,
+	SKS_FUNCTION_VERIFY_RECOVER,
+	SKS_FUNCTION_IMPORT,
+	SKS_FUNCTION_COPY,
+	SKS_FUNCTION_MODIFY,
+	SKS_FUNCTION_DESTROY,
+};
+
+enum processing_step {
+	SKS_FUNC_STEP_INIT,
+	SKS_FUNC_STEP_ONESHOT,
+	SKS_FUNC_STEP_UPDATE,
+	SKS_FUNC_STEP_FINAL,
+};
+
+struct sks_attrs_head;
+struct pkcs11_session;
+
+/* Create an attribute list for a new object (TODO: add parent attribs) */
+uint32_t create_attributes_from_template(struct sks_attrs_head **out,
+					 void *template, size_t template_size,
+					 uint32_t proc_id,
+					 struct sks_attrs_head *parent,
+					 enum processing_func func);
+
+/*
+ * The various checks to be performed before a processing:
+ * - create an new object in the current token state
+ * - use a parent object in the processing
+ * - use a mechanism with provided configuration
+ */
+uint32_t check_created_attrs_against_token(struct pkcs11_session *session,
+					   struct sks_attrs_head *head);
+
+uint32_t check_created_attrs_against_parent_key(uint32_t proc_id,
+						struct sks_attrs_head *parent,
+						struct sks_attrs_head *head);
+
+uint32_t check_created_attrs_against_processing(uint32_t proc_id,
+						struct sks_attrs_head *head);
+
+uint32_t check_created_attrs(struct sks_attrs_head *key1,
+			     struct sks_attrs_head *key2);
+
+uint32_t check_parent_attrs_against_processing(uint32_t proc_id,
+					       enum processing_func func,
+					       struct sks_attrs_head *head);
+
+uint32_t check_access_attrs_against_token(struct pkcs11_session *session,
+					  struct sks_attrs_head *head);
+
+uint32_t check_mechanism_against_processing(struct pkcs11_session *session,
+					    uint32_t mechanism_type,
+					    enum processing_func function,
+					    enum processing_step step);
+
+int check_pkcs11_mechanism_flags(uint32_t mechanism_type, uint32_t flags);
+
+bool object_is_private(struct sks_attrs_head *head);
+
+void pkcs11_max_min_key_size(uint32_t key_type, uint32_t *max_key_size,
+			     uint32_t *min_key_size, bool bit_size_only);
+
+bool attribute_is_exportable(struct sks_attribute_head *req_attr,
+			     struct sks_object *obj);
+
+uint32_t add_missing_attribute_id(struct sks_attrs_head **attrs1,
+				  struct sks_attrs_head **attrs2);
+
+#endif /*__PKCS11_ATTRIBUTE_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_token.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_token.c
new file mode 100644
index 0000000..640af88
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_token.c
@@ -0,0 +1,1752 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#include <assert.h>
+#include <sks_ta.h>
+#include <string.h>
+#include <string_ext.h>
+#include <sys/queue.h>
+#include <tee_internal_api_extensions.h>
+#include <util.h>
+
+#include "attributes.h"
+#include "handle.h"
+#include "pkcs11_token.h"
+#include "pkcs11_attributes.h"
+#include "processing.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+#include "processing_mtk_key.h"
+
+/* ID is token index */
+#define TOKEN_COUNT	CFG_SKS_TA_TOKEN_COUNT
+
+/* Static allocation of tokens runtime instances (reset to 0 at load) */
+struct ck_token ck_token[TOKEN_COUNT];
+
+static struct client_list pkcs11_client_list;
+
+static void close_ck_session(struct pkcs11_session *session);
+
+/* Static allocation of tokens runtime instances */
+struct ck_token *get_token(unsigned int token_id)
+{
+	if (token_id >= TOKEN_COUNT)
+		return NULL;
+
+	return &ck_token[token_id];
+}
+
+unsigned int get_token_id(struct ck_token *token)
+{
+	assert(token >= ck_token && token < &ck_token[TOKEN_COUNT]);
+
+	return token - ck_token;
+}
+
+/* Client */
+struct pkcs11_client *tee_session2client(uintptr_t tee_session)
+{
+	struct pkcs11_client *client;
+
+	TAILQ_FOREACH(client, &pkcs11_client_list, link) {
+		if (client == (void *)tee_session)
+			return client;
+	}
+
+	return NULL;
+}
+
+uintptr_t register_client(void)
+{
+	struct pkcs11_client *client = NULL;
+
+	client = TEE_Malloc(sizeof(*client), TEE_MALLOC_FILL_ZERO);
+	if (!client)
+		return 0;
+
+	TAILQ_INSERT_HEAD(&pkcs11_client_list, client, link);
+	TAILQ_INIT(&client->session_list);
+	handle_db_init(&client->session_handle_db);
+
+	return (uintptr_t)(void *)client;
+}
+
+void unregister_client(uintptr_t tee_session)
+{
+	struct pkcs11_client *client = tee_session2client(tee_session);
+	struct pkcs11_session *session = NULL;
+	struct pkcs11_session *next = NULL;
+
+	if (!client) {
+		EMSG("Unexpected invalid TEE session handle");
+		return;
+	}
+
+	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next) {
+		close_ck_session(session);
+	}
+
+	TAILQ_REMOVE(&pkcs11_client_list, client, link);
+	handle_db_destroy(&client->session_handle_db);
+	TEE_Free(client);
+}
+
+static int pkcs11_token_init(unsigned int id)
+{
+	struct ck_token *token = init_token_db(id);
+
+	if (!token)
+		return 1;
+
+	if (token->state != PKCS11_TOKEN_RESET) {
+		/* Token is already in a valid state */
+		return 0;
+	}
+
+	/* Initialize the token runtime state */
+	token->state = PKCS11_TOKEN_READ_WRITE;
+	token->session_count = 0;
+	token->rw_session_count = 0;
+
+	return 0;
+}
+
+int pkcs11_init(void)
+{
+	unsigned int id = 0;
+
+	for (id = 0; id < TOKEN_COUNT; id++)
+		if (pkcs11_token_init(id))
+			return 1;
+
+	TAILQ_INIT(&pkcs11_client_list);
+
+	return 0;
+}
+
+void pkcs11_deinit(void)
+{
+	unsigned int id = 0;
+
+	for (id = 0; id < TOKEN_COUNT; id++)
+		close_persistent_db(get_token(id));
+}
+
+bool pkcs11_session_is_read_write(struct pkcs11_session *session)
+{
+	switch (session->state) {
+	case PKCS11_SESSION_PUBLIC_READ_WRITE:
+	case PKCS11_SESSION_USER_READ_WRITE:
+	case PKCS11_SESSION_SO_READ_WRITE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+bool pkcs11_session_is_security_officer(struct pkcs11_session *session)
+{
+	return session->state == PKCS11_SESSION_SO_READ_WRITE;
+}
+
+bool pkcs11_session_is_user(struct pkcs11_session *session)
+{
+	return session->state == PKCS11_SESSION_USER_READ_WRITE ||
+		session->state == PKCS11_SESSION_USER_READ_ONLY;
+}
+
+bool pkcs11_session_is_public(struct pkcs11_session *session)
+{
+	return session->state == PKCS11_SESSION_PUBLIC_READ_WRITE ||
+		session->state == PKCS11_SESSION_PUBLIC_READ_ONLY;
+}
+
+struct pkcs11_session *sks_handle2session(uint32_t handle,
+					  uintptr_t tee_session)
+{
+	struct pkcs11_client *client = tee_session2client(tee_session);
+
+	return handle_lookup(&client->session_handle_db, handle);
+}
+
+/*
+ * Currently not support dual operations.
+ */
+int set_processing_state(struct pkcs11_session *session,
+			 enum processing_func function,
+			 struct sks_object *obj1, struct sks_object *obj2)
+{
+	enum pkcs11_proc_state state;
+	struct active_processing *proc = NULL;
+
+	TEE_MemFill(&state, 0, sizeof(state));
+
+	if (session->processing)
+		return SKS_CKR_OPERATION_ACTIVE;
+
+	switch (function) {
+	case SKS_FUNCTION_ENCRYPT:
+		state = PKCS11_SESSION_ENCRYPTING;
+		break;
+	case SKS_FUNCTION_DECRYPT:
+		state = PKCS11_SESSION_DECRYPTING;
+		break;
+	case SKS_FUNCTION_SIGN:
+		state = PKCS11_SESSION_SIGNING;
+		break;
+	case SKS_FUNCTION_VERIFY:
+		state = PKCS11_SESSION_VERIFYING;
+		break;
+	case SKS_FUNCTION_DIGEST:
+		state = PKCS11_SESSION_DIGESTING;
+		break;
+	case SKS_FUNCTION_DERIVE:
+		state = PKCS11_SESSION_READY;
+		break;
+	default:
+		TEE_Panic(function);
+		return -1;
+	}
+
+	proc = TEE_Malloc(sizeof(*proc), TEE_MALLOC_FILL_ZERO);
+	if (!proc)
+		return SKS_MEMORY;
+
+	/* Boolean are default to false and pointers to NULL */
+	proc->state = state;
+	proc->tee_op_handle = TEE_HANDLE_NULL;
+
+	if (obj1 && get_bool(obj1->attributes, SKS_CKA_ALWAYS_AUTHENTICATE))
+		proc->always_authen = true;
+
+	if (obj2 && get_bool(obj2->attributes, SKS_CKA_ALWAYS_AUTHENTICATE))
+		proc->always_authen = true;
+
+	session->processing = proc;
+
+	return SKS_OK;
+}
+
+static void cipher_pin(TEE_ObjectHandle key_handle, uint8_t *buf, size_t len)
+{
+	uint8_t iv[16] = { 0 };
+	uint32_t size = len;
+	TEE_OperationHandle tee_op_handle = TEE_HANDLE_NULL;
+	TEE_Result res = TEE_ERROR_GENERIC;
+
+	res = TEE_AllocateOperation(&tee_op_handle,
+				    TEE_ALG_AES_CBC_NOPAD,
+				    TEE_MODE_ENCRYPT, 128);
+	if (res)
+		TEE_Panic(0);
+
+	res = TEE_SetOperationKey(tee_op_handle, key_handle);
+	if (res)
+		TEE_Panic(0);
+
+	TEE_CipherInit(tee_op_handle, iv, sizeof(iv));
+
+	res = TEE_CipherDoFinal(tee_op_handle, buf, len, buf, &size);
+	if (res || size != SKS_TOKEN_PIN_SIZE)
+		TEE_Panic(0);
+
+	TEE_FreeOperation(tee_op_handle);
+}
+
+/* ctrl=[slot-id][pin-size][pin][label], in=unused, out=unused */
+uint32_t entry_ck_token_initialize(TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t token_id = 0;
+	uint32_t pin_size = 0;
+	void *pin = NULL;
+	char label[SKS_TOKEN_LABEL_SIZE + 1] = { 0 };
+	struct ck_token *token;
+	uint8_t *cpin = NULL;
+	int pin_rc = 0;
+	struct pkcs11_client *client;
+	struct sks_object *obj = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	token = get_token(token_id);
+	if (!token)
+		return SKS_CKR_SLOT_ID_INVALID;
+
+	rv = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	if (pin_size < 8 || pin_size > SKS_TOKEN_PIN_SIZE)
+		return SKS_CKR_PIN_LEN_RANGE;
+
+	rv = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&ctrlargs, &label, SKS_TOKEN_LABEL_SIZE);
+	if (rv)
+		return rv;
+
+	if (token->db_main->flags & SKS_CKFT_SO_PIN_LOCKED) {
+		IMSG("SKSt%u: SO PIN locked", token_id);
+		return SKS_CKR_PIN_LOCKED;
+	}
+
+	TAILQ_FOREACH(client, &pkcs11_client_list, link) {
+		if (!TAILQ_EMPTY(&client->session_list)) {
+			return SKS_CKR_SESSION_EXISTS;
+		}
+	}
+
+	cpin = TEE_Malloc(SKS_TOKEN_PIN_SIZE, TEE_MALLOC_FILL_ZERO);
+	if (!cpin) {
+		return SKS_MEMORY;
+	}
+
+	TEE_MemMove(cpin, pin, pin_size);
+	cipher_pin(token->pin_hdl[0], cpin, SKS_TOKEN_PIN_SIZE);
+
+	if (!token->db_main->so_pin_size) {
+		TEE_MemMove(token->db_main->so_pin, cpin, SKS_TOKEN_PIN_SIZE);
+		token->db_main->so_pin_size = pin_size;
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      so_pin),
+				     sizeof(token->db_main->so_pin));
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      so_pin_size),
+				     sizeof(token->db_main->so_pin_size));
+
+		goto inited;
+	}
+
+	pin_rc = 0;
+	if (token->db_main->so_pin_size != pin_size)
+		pin_rc = 1;
+	if (buf_compare_ct(token->db_main->so_pin, cpin, SKS_TOKEN_PIN_SIZE))
+		pin_rc = 1;
+
+	if (pin_rc) {
+		token->db_main->flags |= SKS_CKFT_SO_PIN_COUNT_LOW;
+		token->db_main->so_pin_count++;
+
+		if (token->db_main->so_pin_count == 6)
+			token->db_main->flags |= SKS_CKFT_SO_PIN_FINAL_TRY;
+		if (token->db_main->so_pin_count == 7)
+			token->db_main->flags |= SKS_CKFT_SO_PIN_LOCKED;
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      flags),
+				     sizeof(token->db_main->flags));
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      so_pin_count),
+				     sizeof(token->db_main->so_pin_count));
+
+		TEE_Free(cpin);
+		return SKS_CKR_PIN_INCORRECT;
+	}
+
+	token->db_main->flags &= ~(SKS_CKFT_SO_PIN_COUNT_LOW |
+				   SKS_CKFT_SO_PIN_FINAL_TRY);
+	token->db_main->so_pin_count = 0;
+
+inited:
+	TEE_MemMove(token->db_main->label, label, SKS_TOKEN_LABEL_SIZE);
+	token->db_main->flags |= SKS_CKFT_TOKEN_INITIALIZED;
+	/* Reset user PIN */
+	token->db_main->user_pin_size = 0;
+	token->db_main->flags &= ~(SKS_CKFT_USER_PIN_INITIALIZED |
+				   SKS_CKFT_USER_PIN_COUNT_LOW |
+				   SKS_CKFT_USER_PIN_FINAL_TRY |
+				   SKS_CKFT_USER_PIN_LOCKED |
+				   SKS_CKFT_USER_PIN_TO_BE_CHANGED);
+
+	update_persistent_db(token, 0, sizeof(*token->db_main));
+
+	/* Remove all persistent objects */
+	if (token->db_objs && token->db_objs->count > 0) {
+		while (!LIST_EMPTY(&token->object_list)) {
+			obj = LIST_FIRST(&token->object_list);
+#ifdef DEBUG
+			MSG_RAW("[destroy] obj uuid %pUl", (void *)obj->uuid);
+#endif
+			mtk_delete_key(obj);
+			unregister_persistent_object(token, obj->uuid);
+			cleanup_persistent_object(obj, token);
+		}
+	}
+
+	label[SKS_TOKEN_LABEL_SIZE] = '\0';
+	IMSG("SKSt%" PRIu32 ": initialized \"%s\"", token_id, label);
+
+	TEE_Free(cpin);
+
+	return SKS_OK;
+}
+
+uint32_t entry_ck_slot_list(TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	const size_t out_size = sizeof(uint32_t) * TOKEN_COUNT;
+	uint32_t *id = NULL;
+	unsigned int n = 0;
+
+	if (ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < out_size) {
+		out->memref.size = out_size;
+		return SKS_SHORT_BUFFER;
+	}
+
+	/* FIXME: we could support unaligment buffers */
+	if ((uintptr_t)out->memref.buffer & 0x03UL)
+		return SKS_BAD_PARAM;
+
+	for (id = out->memref.buffer, n = 0; n < TOKEN_COUNT; n++, id++)
+		*id = (uint32_t)n;
+
+	out->memref.size = out_size;
+
+	return SKS_OK;
+}
+
+uint32_t entry_ck_slot_info(TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t token_id = 0;
+	struct ck_token *token = NULL;
+	const char desc[] = SKS_CRYPTOKI_SLOT_DESCRIPTION;
+	const char manuf[] = SKS_CRYPTOKI_SLOT_MANUFACTURER;
+	const char hwver[2] = SKS_CRYPTOKI_SLOT_HW_VERSION;
+	const char fwver[2] = SKS_CRYPTOKI_SLOT_FW_VERSION;
+	struct sks_slot_info info;
+	char dev_uuid[37]; /* UUID as string */
+	TEE_UUID dev_id;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+	TEE_MemFill(&info, 0, sizeof(info));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < sizeof(struct sks_slot_info)) {
+		out->memref.size = sizeof(struct sks_slot_info);
+		return SKS_SHORT_BUFFER;
+	}
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	token = get_token(token_id);
+	if (!token)
+		return SKS_CKR_SLOT_ID_INVALID;
+
+	TEE_MemFill(&info, 0, sizeof(info));
+
+	/* Set slot description to the device UUID if available */
+	if (TEE_GetPropertyAsUUID(TEE_PROPSET_TEE_IMPLEMENTATION,
+				"gpd.tee.deviceID", &dev_id) == TEE_SUCCESS) {
+		snprintf(dev_uuid, sizeof(dev_uuid),
+			"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+			dev_id.timeLow, dev_id.timeMid,
+			dev_id.timeHiAndVersion,
+			dev_id.clockSeqAndNode[0], dev_id.clockSeqAndNode[1],
+			dev_id.clockSeqAndNode[2], dev_id.clockSeqAndNode[3],
+			dev_id.clockSeqAndNode[4], dev_id.clockSeqAndNode[5],
+			dev_id.clockSeqAndNode[6], dev_id.clockSeqAndNode[7]);
+		PADDED_STRING_COPY(info.slotDescription, dev_uuid);
+	} else {
+		PADDED_STRING_COPY(info.slotDescription, desc);
+	}
+	PADDED_STRING_COPY(info.manufacturerID, manuf);
+
+	info.flags |= SKS_CKFS_TOKEN_PRESENT;
+	info.flags |= SKS_CKFS_REMOVABLE_DEVICE;
+	info.flags &= ~SKS_CKFS_HW_SLOT;
+
+	TEE_MemMove(&info.hardwareVersion, &hwver, sizeof(hwver));
+	TEE_MemMove(&info.firmwareVersion, &fwver, sizeof(fwver));
+
+	out->memref.size = sizeof(struct sks_slot_info);
+	TEE_MemMove(out->memref.buffer, &info, out->memref.size);
+
+	return SKS_OK;
+}
+
+uint32_t entry_ck_token_info(TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t token_id = 0;
+	struct ck_token *token = NULL;
+	const char manuf[] = SKS_CRYPTOKI_TOKEN_MANUFACTURER;
+	const char model[] = SKS_CRYPTOKI_TOKEN_MODEL;
+	const char hwver[] = SKS_CRYPTOKI_TOKEN_HW_VERSION;
+	const char fwver[] = SKS_CRYPTOKI_TOKEN_FW_VERSION;
+	char sernu[] = SKS_CRYPTOKI_TOKEN_SERIAL_NUMBER;
+	struct sks_token_info info;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+	TEE_MemFill(&info, 0, sizeof(info));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < sizeof(struct sks_token_info)) {
+		out->memref.size = sizeof(struct sks_token_info);
+		return SKS_SHORT_BUFFER;
+	}
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	token = get_token(token_id);
+	if (!token)
+		return SKS_CKR_SLOT_ID_INVALID;
+
+	if (snprintf(sernu + sizeof(sernu) - 2, 2, "%1d", token_id) >= 2)
+		TEE_Panic(0);
+
+	TEE_MemFill(&info, 0, sizeof(info));
+
+	PADDED_STRING_COPY(info.label, token->db_main->label);
+	PADDED_STRING_COPY(info.manufacturerID, manuf);
+	PADDED_STRING_COPY(info.model, model);
+	PADDED_STRING_COPY(info.serialNumber, sernu);
+
+	info.flags = token->db_main->flags;
+
+	/* TODO */
+	info.ulMaxSessionCount = ~0;
+	info.ulSessionCount = token->session_count;
+	info.ulMaxRwSessionCount = ~0;
+	info.ulRwSessionCount = token->rw_session_count;
+	/* TODO */
+	info.ulMaxPinLen = 128;
+	info.ulMinPinLen = 10;
+	/* TODO */
+	info.ulTotalPublicMemory = ~0;
+	info.ulFreePublicMemory = ~0;
+	info.ulTotalPrivateMemory = ~0;
+	info.ulFreePrivateMemory = ~0;
+
+	TEE_MemMove(&info.hardwareVersion, &hwver, sizeof(hwver));
+	TEE_MemMove(&info.firmwareVersion, &fwver, sizeof(hwver));
+
+	// TODO: get time and convert from reference into YYYYMMDDhhmmss/UTC
+	TEE_MemFill(info.utcTime, 0, sizeof(info.utcTime));
+
+	/* Return to caller with data */
+	out->memref.size = sizeof(struct sks_token_info);
+	TEE_MemMove(out->memref.buffer, &info, out->memref.size);
+
+	return SKS_OK;
+}
+
+uint32_t entry_ck_token_mecha_ids(TEE_Param *ctrl,
+				  TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t token_id = 0;
+	struct ck_token *token = NULL;
+	uint32_t mechanisms_count = (uint32_t)get_supported_mechanisms(NULL, 0);
+	size_t __maybe_unused count = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	token = get_token(token_id);
+	if (!token)
+		return SKS_CKR_SLOT_ID_INVALID;
+
+	if (out->memref.size < mechanisms_count * sizeof(uint32_t)) {
+		out->memref.size = mechanisms_count * sizeof(uint32_t);
+		return SKS_SHORT_BUFFER;
+	}
+
+	out->memref.size = sizeof(uint32_t) *
+		get_supported_mechanisms(out->memref.buffer, mechanisms_count);
+
+	assert(out->memref.size == mechanisms_count * sizeof(uint32_t));
+
+#ifdef DEBUG
+	for (count = 0; count < mechanisms_count; count++) {
+		IMSG("SKSt%" PRIu32 ": mechanism 0x%04" PRIx32 ": %s",
+			token_id, ((uint32_t *)out->memref.buffer)[count],
+			sks2str_proc(((uint32_t *)out->memref.buffer)[count]));
+	}
+#endif
+
+	return SKS_OK;
+}
+
+static uint32_t supported_mechanism_info_flag(uint32_t proc_id)
+{
+	uint32_t flags = 0;
+
+	switch (proc_id) {
+	case SKS_CKM_GENERIC_SECRET_KEY_GEN:
+	case SKS_CKM_AES_KEY_GEN:
+		flags = SKS_CKFM_GENERATE;
+		break;
+	case SKS_CKM_AES_ECB:
+	case SKS_CKM_AES_CBC:
+	case SKS_CKM_AES_CBC_PAD:
+	case SKS_CKM_AES_CTR:
+	case SKS_CKM_AES_CTS:
+	case SKS_CKM_AES_GCM:
+	case SKS_CKM_AES_CCM:
+		flags = SKS_CKFM_ENCRYPT | SKS_CKFM_DECRYPT |
+			SKS_CKFM_WRAP | SKS_CKFM_UNWRAP;
+		break;
+	case SKS_CKM_AES_GMAC:
+		flags = SKS_CKFM_SIGN | SKS_CKFM_VERIFY | SKS_CKFM_DERIVE;
+		break;
+	case SKS_CKM_AES_CMAC:
+	case SKS_CKM_AES_CMAC_GENERAL:
+	case SKS_CKM_MD5_HMAC:
+	case SKS_CKM_SHA_1_HMAC:
+	case SKS_CKM_SHA224_HMAC:
+	case SKS_CKM_SHA256_HMAC:
+	case SKS_CKM_SHA384_HMAC:
+	case SKS_CKM_SHA512_HMAC:
+	case SKS_CKM_AES_XCBC_MAC:
+		flags = SKS_CKFM_SIGN | SKS_CKFM_VERIFY;
+		break;
+	case SKS_CKM_AES_ECB_ENCRYPT_DATA:
+	case SKS_CKM_AES_CBC_ENCRYPT_DATA:
+		flags = SKS_CKFM_DERIVE;
+		break;
+	case SKS_CKM_EC_KEY_PAIR_GEN:
+	case SKS_CKM_RSA_PKCS_KEY_PAIR_GEN:
+		flags = SKS_CKFM_GENERATE_PAIR;
+		break;
+	case SKS_CKM_ECDSA:
+	case SKS_CKM_ECDSA_SHA1:
+	case SKS_CKM_ECDSA_SHA224:
+	case SKS_CKM_ECDSA_SHA256:
+	case SKS_CKM_ECDSA_SHA384:
+	case SKS_CKM_ECDSA_SHA512:
+		flags = SKS_CKFM_SIGN | SKS_CKFM_VERIFY;
+		break;
+	case SKS_CKM_ECDH1_DERIVE:
+	case SKS_CKM_ECDH1_COFACTOR_DERIVE:
+	case SKS_CKM_ECMQV_DERIVE:
+		flags = SKS_CKFM_DERIVE;
+		break;
+	case SKS_CKM_ECDH_AES_KEY_WRAP:
+		flags = SKS_CKFM_WRAP | SKS_CKFM_UNWRAP;
+		break;
+	case SKS_CKM_RSA_PKCS:
+	case SKS_CKM_RSA_X_509:
+		flags = SKS_CKFM_ENCRYPT | SKS_CKFM_DECRYPT |
+			SKS_CKFM_SIGN | SKS_CKFM_VERIFY |
+			SKS_CKFM_SIGN_RECOVER | SKS_CKFM_VERIFY_RECOVER |
+			SKS_CKFM_WRAP | SKS_CKFM_UNWRAP;
+		break;
+	case SKS_CKM_RSA_9796:
+		flags = SKS_CKFM_SIGN | SKS_CKFM_VERIFY |
+			SKS_CKFM_SIGN_RECOVER | SKS_CKFM_VERIFY_RECOVER;
+		break;
+
+	case SKS_CKM_RSA_PKCS_OAEP:
+		flags = SKS_CKFM_ENCRYPT | SKS_CKFM_DECRYPT |
+			SKS_CKFM_WRAP | SKS_CKFM_UNWRAP;
+		break;
+	case SKS_CKM_RSA_PKCS_PSS:
+	case SKS_CKM_SHA1_RSA_PKCS:
+	case SKS_CKM_SHA224_RSA_PKCS:
+	case SKS_CKM_SHA256_RSA_PKCS:
+	case SKS_CKM_SHA384_RSA_PKCS:
+	case SKS_CKM_SHA512_RSA_PKCS:
+	case SKS_CKM_SHA1_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS_PSS:
+	case SKS_CKM_SHA256_RSA_PKCS_PSS:
+	case SKS_CKM_SHA384_RSA_PKCS_PSS:
+	case SKS_CKM_SHA512_RSA_PKCS_PSS:
+		flags = SKS_CKFM_SIGN | SKS_CKFM_VERIFY;
+		break;
+	case SKS_CKM_RSA_AES_KEY_WRAP:
+		flags = SKS_CKFM_WRAP | SKS_CKFM_UNWRAP;
+		break;
+	default:
+		TEE_Panic(proc_id);
+		break;
+	}
+
+	assert(check_pkcs11_mechanism_flags(proc_id, flags) == 0);
+
+	return flags;
+}
+
+static void supported_mechanism_key_size(uint32_t proc_id,
+					 uint32_t *min_key_size,
+					 uint32_t *max_key_size,
+					 bool bit_size_only)
+{
+	uint32_t mult = bit_size_only ? 8 : 1;
+
+	switch (proc_id) {
+	case SKS_CKM_GENERIC_SECRET_KEY_GEN:
+		*min_key_size = 1;		/* in bits */
+		*max_key_size = 4096;		/* in bits */
+		break;
+	case SKS_CKM_MD5_HMAC:
+		*min_key_size = 16 * mult;
+		*max_key_size = 16 * mult;
+		break;
+	case SKS_CKM_SHA_1_HMAC:
+		*min_key_size = 20 * mult;
+		*max_key_size = 20 * mult;
+		break;
+	case SKS_CKM_SHA224_HMAC:
+		*min_key_size = 28 * mult;
+		*max_key_size = 28 * mult;
+		break;
+	case SKS_CKM_SHA256_HMAC:
+		*min_key_size = 32 * mult;
+		*max_key_size = 32 * mult;
+		break;
+	case SKS_CKM_SHA384_HMAC:
+		*min_key_size = 48 * mult;
+		*max_key_size = 48 * mult;
+		break;
+	case SKS_CKM_SHA512_HMAC:
+		*min_key_size = 64 * mult;
+		*max_key_size = 64 * mult;
+		break;
+	case SKS_CKM_AES_XCBC_MAC:
+		*min_key_size = 28 * mult;
+		*max_key_size = 28 * mult;
+		break;
+	case SKS_CKM_AES_KEY_GEN:
+	case SKS_CKM_AES_ECB:
+	case SKS_CKM_AES_CBC:
+	case SKS_CKM_AES_CBC_PAD:
+	case SKS_CKM_AES_CTR:
+	case SKS_CKM_AES_CTS:
+	case SKS_CKM_AES_GCM:
+	case SKS_CKM_AES_CCM:
+	case SKS_CKM_AES_GMAC:
+	case SKS_CKM_AES_CMAC:
+	case SKS_CKM_AES_CMAC_GENERAL:
+		*min_key_size = 16 * mult;
+		*max_key_size = 32 * mult;
+		break;
+	case SKS_CKM_EC_KEY_PAIR_GEN:
+	case SKS_CKM_ECDSA:
+	case SKS_CKM_ECDSA_SHA1:
+	case SKS_CKM_ECDSA_SHA224:
+	case SKS_CKM_ECDSA_SHA256:
+	case SKS_CKM_ECDSA_SHA384:
+	case SKS_CKM_ECDSA_SHA512:
+	case SKS_CKM_ECDH1_DERIVE:
+	case SKS_CKM_ECDH1_COFACTOR_DERIVE:
+	case SKS_CKM_ECMQV_DERIVE:
+	case SKS_CKM_ECDH_AES_KEY_WRAP:
+		*min_key_size = 160;	/* in bits */
+		*max_key_size = 521;	/* in bits */
+		break;
+	case SKS_CKM_RSA_PKCS_KEY_PAIR_GEN:
+	case SKS_CKM_RSA_PKCS:
+	case SKS_CKM_RSA_9796:
+	case SKS_CKM_RSA_X_509:
+	case SKS_CKM_SHA1_RSA_PKCS:
+	case SKS_CKM_RSA_PKCS_OAEP:
+	case SKS_CKM_SHA1_RSA_PKCS_PSS:
+	case SKS_CKM_SHA256_RSA_PKCS:
+	case SKS_CKM_SHA384_RSA_PKCS:
+	case SKS_CKM_SHA512_RSA_PKCS:
+	case SKS_CKM_SHA256_RSA_PKCS_PSS:
+	case SKS_CKM_SHA384_RSA_PKCS_PSS:
+	case SKS_CKM_SHA512_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS:
+	case SKS_CKM_SHA224_RSA_PKCS_PSS:
+		*min_key_size = 256;	/* in bits */
+		*max_key_size = 4096;	/* in bits */
+		break;
+	default:
+		*min_key_size = 0;
+		*max_key_size = 0;
+		break;
+	}
+}
+
+uint32_t entry_ck_token_mecha_info(TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t token_id = 0;
+	uint32_t type = 0;
+	struct ck_token *token = NULL;
+	struct sks_mechanism_info *info = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&ctrlargs, &type, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	token = get_token(token_id);
+	if (!token)
+		return SKS_CKR_SLOT_ID_INVALID;
+
+	if (!mechanism_is_supported(type))
+		return SKS_CKR_MECHANISM_INVALID;
+
+	if (out->memref.size < sizeof(info)) {
+		out->memref.size = sizeof(info);
+		return SKS_SHORT_BUFFER;
+	}
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	info = (struct sks_mechanism_info *)out->memref.buffer;
+
+	info->flags = supported_mechanism_info_flag(type);
+
+	supported_mechanism_key_size(type, &info->min_key_size,
+					&info->max_key_size, false);
+
+	out->memref.size = sizeof(struct sks_mechanism_info);
+
+	IMSG("SKSt%" PRIu32 ": mechanism 0x%" PRIx32 " info", token_id, type);
+
+	return SKS_OK;
+}
+
+/* Select the read-only/read-write state for session login state */
+static void set_session_state(struct pkcs11_client *client,
+			      struct pkcs11_session *session, bool readonly)
+{
+	struct pkcs11_session *sess = NULL;
+	enum pkcs11_session_state state = PKCS11_SESSION_RESET;
+
+	/*
+	 * No need to check all client session, only the first session on
+	 * target token gives client login configuration.
+	 */
+	TAILQ_FOREACH(sess, &client->session_list, link) {
+		assert(sess != session);
+
+		if (sess->token != session->token)
+			continue;
+
+		switch (sess->state) {
+		case PKCS11_SESSION_PUBLIC_READ_WRITE:
+		case PKCS11_SESSION_PUBLIC_READ_ONLY:
+			state = PKCS11_SESSION_PUBLIC_READ_WRITE;
+			break;
+		case PKCS11_SESSION_USER_READ_WRITE:
+		case PKCS11_SESSION_USER_READ_ONLY:
+			state = PKCS11_SESSION_USER_READ_WRITE;
+			break;
+		case PKCS11_SESSION_SO_READ_WRITE:
+			state = PKCS11_SESSION_SO_READ_WRITE;
+			break;
+		default:
+			TEE_Panic(0);
+		}
+		break;
+	 }
+
+	switch (state) {
+	case PKCS11_SESSION_USER_READ_WRITE:
+		session->state = readonly ? PKCS11_SESSION_USER_READ_ONLY :
+					  PKCS11_SESSION_USER_READ_WRITE;
+		break;
+	case PKCS11_SESSION_SO_READ_WRITE:
+		/* SO cannot open read-only sessions */
+		if (readonly)
+			TEE_Panic(0);
+
+		session->state = PKCS11_SESSION_PUBLIC_READ_ONLY;
+		break;
+	default:
+		session->state = readonly ? PKCS11_SESSION_PUBLIC_READ_ONLY :
+					  PKCS11_SESSION_PUBLIC_READ_WRITE;
+		break;
+	}
+}
+
+static void session_login_user(struct pkcs11_session *session)
+{
+	struct pkcs11_client *client = tee_session2client(session->tee_session);
+	struct pkcs11_session *sess = NULL;
+
+	TAILQ_FOREACH(sess, &client->session_list, link) {
+		if (sess->token != session->token)
+			continue;
+
+		if (pkcs11_session_is_read_write(sess))
+			sess->state = PKCS11_SESSION_USER_READ_WRITE;
+		else
+			sess->state = PKCS11_SESSION_USER_READ_ONLY;
+	}
+}
+
+static void session_login_so(struct pkcs11_session *session)
+{
+	struct pkcs11_client *client = tee_session2client(session->tee_session);
+	struct pkcs11_session *sess = NULL;
+
+	TAILQ_FOREACH(sess, &client->session_list, link) {
+		if (sess->token != session->token)
+			continue;
+
+		if (pkcs11_session_is_read_write(sess))
+			sess->state = PKCS11_SESSION_SO_READ_WRITE;
+		else
+			TEE_Panic(0);
+	}
+}
+
+static void session_logout(struct pkcs11_session *session)
+{
+	struct pkcs11_client *client = tee_session2client(session->tee_session);
+	struct pkcs11_session *sess = NULL;
+	struct sks_object *obj = NULL;
+
+	TAILQ_FOREACH(sess, &client->session_list, link) {
+		if (sess->token != session->token)
+			continue;
+
+		LIST_FOREACH(obj, &sess->object_list, link) {
+			if (!object_is_private(obj->attributes))
+				continue;
+
+			destroy_object(sess, obj, true);
+			handle_put(&sess->object_handle_db,
+				   sks_object2handle(obj, sess));
+		}
+
+		if (pkcs11_session_is_read_write(sess))
+			sess->state = PKCS11_SESSION_PUBLIC_READ_WRITE;
+		else
+			sess->state = PKCS11_SESSION_PUBLIC_READ_ONLY;
+	}
+}
+
+/* ctrl=[slot-id], in=unused, out=[session-handle] */
+static uint32_t open_ck_session(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out, bool readonly)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t token_id = 0;
+	struct ck_token *token = NULL;
+	struct pkcs11_session *session = NULL;
+	struct pkcs11_client *client = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < sizeof(uint32_t)) {
+		out->memref.size = sizeof(uint32_t);
+		return SKS_SHORT_BUFFER;
+	}
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	token = get_token(token_id);
+	if (!token)
+		return SKS_CKR_SLOT_ID_INVALID;
+
+	if (!readonly && token->state == PKCS11_TOKEN_READ_ONLY) {
+		return SKS_CKR_TOKEN_WRITE_PROTECTED;
+	}
+
+	client = tee_session2client(tee_session);
+	if (!client) {
+		EMSG("Unexpected invalid TEE session handle");
+		return SKS_FAILED;
+	}
+
+	if (readonly) {
+		TAILQ_FOREACH(session, &client->session_list, link) {
+			if (session->state == PKCS11_SESSION_SO_READ_WRITE) {
+				return SKS_CKR_SESSION_READ_WRITE_SO_EXISTS;
+			}
+		}
+	}
+
+	session = TEE_Malloc(sizeof(*session), TEE_MALLOC_FILL_ZERO);
+	if (!session)
+		return SKS_MEMORY;
+
+	session->handle = handle_get(&client->session_handle_db, session);
+	if (!session->handle) {
+		TEE_Free(session);
+		return SKS_MEMORY;
+	}
+
+	session->tee_session = tee_session;
+	session->token = token;
+	session->client = client;
+
+	LIST_INIT(&session->object_list);
+	handle_db_init(&session->object_handle_db);
+
+	set_session_state(client, session, readonly);
+
+	TAILQ_INSERT_HEAD(&client->session_list, session, link);
+
+	session->token->session_count++;
+	if (!readonly)
+		session->token->rw_session_count++;
+
+	*(uint32_t *)out->memref.buffer = session->handle;
+	out->memref.size = sizeof(uint32_t);
+
+	IMSG("SKSs%" PRIu32 ": open", session->handle);
+
+	return SKS_OK;
+}
+
+/* ctrl=[slot-id], in=unused, out=[session-handle] */
+uint32_t entry_ck_token_ro_session(uintptr_t tee_session, TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out)
+{
+	return open_ck_session(tee_session, ctrl, in, out, true);
+}
+
+/* ctrl=[slot-id], in=unused, out=[session-handle] */
+uint32_t entry_ck_token_rw_session(uintptr_t tee_session, TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out)
+{
+	return open_ck_session(tee_session, ctrl, in, out, false);
+}
+
+static void close_ck_session(struct pkcs11_session *session)
+{
+	release_active_processing(session);
+
+	/* No need to put object handles, the whole database is destroyed */
+	while (!LIST_EMPTY(&session->object_list)) {
+		destroy_object(session, LIST_FIRST(&session->object_list),
+				true);
+	}
+
+	release_session_find_obj_context(session);
+
+	TAILQ_REMOVE(&session->client->session_list, session, link);
+	handle_put(&session->client->session_handle_db, session->handle);
+	handle_db_destroy(&session->object_handle_db);
+
+	// If no more session, next opened one will simply be Public login
+
+	session->token->session_count--;
+	if (pkcs11_session_is_read_write(session))
+		session->token->rw_session_count--;
+
+	TEE_Free(session);
+
+	IMSG("SKSs%" PRIu32 ": close", session->handle);
+}
+
+/* ctrl=[session-handle], in=unused, out=unused */
+uint32_t entry_ck_token_close_session(uintptr_t tee_session, TEE_Param *ctrl,
+				      TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out || ctrl->memref.size < sizeof(uint32_t))
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	close_ck_session(session);
+
+	return SKS_OK;
+}
+
+uint32_t entry_ck_token_close_all(uintptr_t tee_session, TEE_Param *ctrl,
+				  TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t token_id = 0;
+	struct ck_token *token = NULL;
+	struct pkcs11_session *session = NULL;
+	struct pkcs11_session *next = NULL;
+	struct pkcs11_client *client = tee_session2client(tee_session);
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	token = get_token(token_id);
+	if (!token)
+		return SKS_CKR_SLOT_ID_INVALID;
+
+	IMSG("SKSt%" PRIu32 ": close sessions", token_id);
+
+	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next) {
+		if (session->token == token)
+			close_ck_session(session);
+	}
+
+	return SKS_OK;
+}
+
+/* ctrl=[session-handle], in=unused, out=[session-info] */
+uint32_t entry_ck_token_session_info(uintptr_t tee_session, TEE_Param *ctrl,
+				  TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_session_info info;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+	TEE_MemFill(&info, 0, sizeof(info));
+
+	if (!ctrl || in || !out || ctrl->memref.size < sizeof(uint32_t))
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	if (out->memref.size < sizeof(struct sks_session_info)) {
+		out->memref.size = sizeof(struct sks_session_info);
+		return SKS_SHORT_BUFFER;
+	}
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	info.slot_id = get_token_id(session->token);
+	switch (session->state) {
+	case PKCS11_SESSION_PUBLIC_READ_WRITE:
+		info.state = SKS_CKSS_RW_PUBLIC_SESSION;
+		break;
+	case PKCS11_SESSION_PUBLIC_READ_ONLY:
+		info.state = SKS_CKSS_RO_PUBLIC_SESSION;
+		break;
+	case PKCS11_SESSION_USER_READ_WRITE:
+		info.state = SKS_CKSS_RW_USER_FUNCTIONS;
+		break;
+	case PKCS11_SESSION_USER_READ_ONLY:
+		info.state = SKS_CKSS_RO_USER_FUNCTIONS;
+		break;
+	case PKCS11_SESSION_SO_READ_WRITE:
+		info.state = SKS_CKSS_RW_SO_FUNCTIONS;
+		break;
+	default:
+		TEE_Panic(0);
+	}
+	info.flags = SKS_CKFS_SERIAL_SESSION;
+	if (session->state == PKCS11_SESSION_USER_READ_WRITE ||
+			session->state == PKCS11_SESSION_PUBLIC_READ_WRITE)
+		info.flags |= SKS_CKFS_RW_SESSION;
+	info.error_code = 0;
+
+	/* Return to caller with data */
+	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
+
+	return SKS_OK;
+}
+
+static uint32_t set_pin(struct pkcs11_session *session,
+			uint8_t *new_pin, size_t new_pin_size,
+			uint32_t user_type)
+{
+	uint8_t *cpin = NULL;
+	uint32_t *pin_count = NULL;
+	uint32_t *pin_size = NULL;
+	uint8_t *pin = NULL;
+	TEE_ObjectHandle pin_key_hdl;
+	uint32_t flag_mask = 0;
+
+	TEE_MemFill(&pin_key_hdl, 0, sizeof(pin_key_hdl));
+
+	if (session->token->db_main->flags & SKS_CKFT_WRITE_PROTECTED)
+		return SKS_CKR_TOKEN_WRITE_PROTECTED;
+
+	if (!pkcs11_session_is_read_write(session))
+		return SKS_CKR_SESSION_READ_ONLY;
+
+	if (new_pin_size < 8 || new_pin_size > SKS_TOKEN_PIN_SIZE)
+		return SKS_CKR_PIN_LEN_RANGE;
+
+	switch (user_type) {
+	case SKS_CKU_SO:
+		pin = session->token->db_main->so_pin;
+		pin_size = &session->token->db_main->so_pin_size;
+		pin_count = &session->token->db_main->so_pin_count;
+		pin_key_hdl = session->token->pin_hdl[0];
+		flag_mask = SKS_CKFT_SO_PIN_COUNT_LOW |
+				SKS_CKFT_SO_PIN_FINAL_TRY |
+				SKS_CKFT_SO_PIN_LOCKED |
+				SKS_CKFT_SO_PIN_TO_BE_CHANGED;
+		break;
+	case SKS_CKU_USER:
+		pin = session->token->db_main->user_pin;
+		pin_size = &session->token->db_main->user_pin_size;
+		pin_count = &session->token->db_main->user_pin_count;
+		pin_key_hdl = session->token->pin_hdl[1];
+		flag_mask = SKS_CKFT_USER_PIN_COUNT_LOW |
+				SKS_CKFT_USER_PIN_FINAL_TRY |
+				SKS_CKFT_USER_PIN_LOCKED |
+				SKS_CKFT_USER_PIN_TO_BE_CHANGED;
+		break;
+	default:
+		return SKS_FAILED;
+	}
+
+	cpin = TEE_Malloc(SKS_TOKEN_PIN_SIZE, TEE_MALLOC_FILL_ZERO);
+	if (!cpin)
+		return SKS_MEMORY;
+
+	TEE_MemMove(cpin, new_pin, new_pin_size);
+
+	cipher_pin(pin_key_hdl, cpin, SKS_TOKEN_PIN_SIZE);
+
+	TEE_MemMove(pin, cpin, SKS_TOKEN_PIN_SIZE);
+	*pin_size = new_pin_size;
+	*pin_count = 0;
+
+	session->token->db_main->flags &= ~flag_mask;
+
+	if (user_type == SKS_CKU_USER)
+		session->token->db_main->flags |= SKS_CKFT_USER_PIN_INITIALIZED;
+
+	// Paranoia: Check unmodified old content is still valid
+	update_persistent_db(session->token,
+			     0, sizeof(*session->token->db_main));
+
+	TEE_Free(cpin);
+
+	return SKS_OK;
+}
+
+/* ctrl=[session-handle][pin-size]{pin-arrays], in=unused, out=unused */
+uint32_t entry_init_pin(uintptr_t tee_session, TEE_Param *ctrl,
+			TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	uint32_t pin_size = 0;
+	void *pin = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	if (!pkcs11_session_is_security_officer(session))
+		return SKS_CKR_USER_NOT_LOGGED_IN;
+
+	rv = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
+	if (rv)
+		return rv;
+
+	assert(session->token->db_main->flags & SKS_CKFT_TOKEN_INITIALIZED);
+
+	IMSG("SKSs%" PRIu32 ": init PIN", session_handle);
+
+	return set_pin(session, pin, pin_size, SKS_CKU_USER);
+}
+
+static uint32_t check_so_pin(struct pkcs11_session *session,
+			     uint8_t *pin, size_t pin_size)
+{
+	struct ck_token *token = session->token;
+	uint8_t *cpin = NULL;
+	int pin_rc = 0;
+
+	/* Note: intentional return code USER_PIN_NOT_INITIALIZED */
+	if (!token->db_main->so_pin_size ||
+	    !(token->db_main->flags & SKS_CKFT_TOKEN_INITIALIZED))
+		return SKS_CKR_USER_PIN_NOT_INITIALIZED;
+
+	if (token->db_main->flags & SKS_CKFT_SO_PIN_LOCKED)
+		return SKS_CKR_PIN_LOCKED;
+
+	cpin = TEE_Malloc(SKS_TOKEN_PIN_SIZE, TEE_MALLOC_FILL_ZERO);
+	if (!cpin)
+		return SKS_MEMORY;
+
+	if (pin_size > SKS_TOKEN_PIN_SIZE) {
+		TEE_Free(cpin);
+		return SKS_BAD_PARAM;
+	}
+
+	TEE_MemMove(cpin, pin, pin_size);
+	cipher_pin(token->pin_hdl[0], cpin, SKS_TOKEN_PIN_SIZE);
+
+	pin_rc = 0;
+
+	if (token->db_main->so_pin_size != pin_size)
+		pin_rc = 1;
+
+	if (buf_compare_ct(token->db_main->so_pin, cpin, SKS_TOKEN_PIN_SIZE))
+		pin_rc = 1;
+
+	TEE_Free(cpin);
+
+	if (pin_rc) {
+		token->db_main->flags |= SKS_CKFT_SO_PIN_COUNT_LOW;
+		token->db_main->so_pin_count++;
+
+		if (token->db_main->so_pin_count == 6)
+			token->db_main->flags |= SKS_CKFT_SO_PIN_FINAL_TRY;
+		if (token->db_main->so_pin_count == 7)
+			token->db_main->flags |= SKS_CKFT_SO_PIN_LOCKED;
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      flags),
+				     sizeof(token->db_main->flags));
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      so_pin_count),
+				     sizeof(token->db_main->so_pin_count));
+
+		if (token->db_main->flags & SKS_CKFT_SO_PIN_LOCKED)
+			return SKS_CKR_PIN_LOCKED;
+
+		return SKS_CKR_PIN_INCORRECT;
+	}
+
+	if (token->db_main->so_pin_count) {
+		token->db_main->so_pin_count = 0;
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      so_pin_count),
+				     sizeof(token->db_main->so_pin_count));
+	}
+
+	if (token->db_main->flags & (SKS_CKFT_SO_PIN_COUNT_LOW |
+					SKS_CKFT_SO_PIN_FINAL_TRY)) {
+		token->db_main->flags &= ~(SKS_CKFT_SO_PIN_COUNT_LOW |
+					   SKS_CKFT_SO_PIN_FINAL_TRY);
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      flags),
+				     sizeof(token->db_main->flags));
+	}
+
+	return SKS_OK;
+}
+
+static uint32_t check_user_pin(struct pkcs11_session *session,
+				uint8_t *pin, size_t pin_size)
+{
+	struct ck_token *token = session->token;
+	uint8_t *cpin = NULL;
+	int pin_rc = 0;
+
+	if (!token->db_main->user_pin_size ||
+	    !(token->db_main->flags & SKS_CKFT_USER_PIN_INITIALIZED))
+		return SKS_CKR_USER_PIN_NOT_INITIALIZED;
+
+	if (token->db_main->flags & SKS_CKFT_USER_PIN_LOCKED)
+		return SKS_CKR_PIN_LOCKED;
+
+	cpin = TEE_Malloc(SKS_TOKEN_PIN_SIZE, TEE_MALLOC_FILL_ZERO);
+	if (!cpin)
+		return SKS_MEMORY;
+
+	if (pin_size > SKS_TOKEN_PIN_SIZE) {
+		TEE_Free(cpin);
+		return SKS_BAD_PARAM;
+	}
+
+	TEE_MemMove(cpin, pin, pin_size);
+	cipher_pin(token->pin_hdl[1], cpin, SKS_TOKEN_PIN_SIZE);
+
+	pin_rc = 0;
+
+	if (token->db_main->user_pin_size != pin_size)
+		pin_rc = 1;
+
+	if (buf_compare_ct(token->db_main->user_pin, cpin, SKS_TOKEN_PIN_SIZE))
+		pin_rc = 1;
+
+	TEE_Free(cpin);
+
+	if (pin_rc) {
+		token->db_main->flags |= SKS_CKFT_USER_PIN_COUNT_LOW;
+		token->db_main->user_pin_count++;
+
+		if (token->db_main->user_pin_count == 6)
+			token->db_main->flags |= SKS_CKFT_USER_PIN_FINAL_TRY;
+		if (token->db_main->user_pin_count == 7)
+			token->db_main->flags |= SKS_CKFT_USER_PIN_LOCKED;
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      flags),
+				     sizeof(token->db_main->flags));
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      user_pin_count),
+				     sizeof(token->db_main->user_pin_count));
+
+		if (token->db_main->flags & SKS_CKFT_USER_PIN_LOCKED)
+			return SKS_CKR_PIN_LOCKED;
+
+		return SKS_CKR_PIN_INCORRECT;
+	}
+
+	if (token->db_main->user_pin_count) {
+		token->db_main->user_pin_count = 0;
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      user_pin_count),
+				     sizeof(token->db_main->user_pin_count));
+	}
+
+	if (token->db_main->flags & (SKS_CKFT_USER_PIN_COUNT_LOW |
+					SKS_CKFT_USER_PIN_FINAL_TRY)) {
+		token->db_main->flags &= ~(SKS_CKFT_USER_PIN_COUNT_LOW |
+				   SKS_CKFT_USER_PIN_FINAL_TRY);
+
+		update_persistent_db(token,
+				     offsetof(struct token_persistent_main,
+					      flags),
+				     sizeof(token->db_main->flags));
+	}
+
+	return SKS_OK;
+}
+
+/* ctrl=[session][old-size]{old-pin][pin-size]{pin], in=unused, out=unused */
+uint32_t entry_set_pin(uintptr_t tee_session, TEE_Param *ctrl,
+			TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	uint32_t old_pin_size = 0;
+	uint32_t pin_size = 0;
+	void *old_pin = NULL;
+	void *pin = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&ctrlargs, &old_pin_size, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get_ptr(&ctrlargs, &old_pin, old_pin_size);
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	if (!pkcs11_session_is_read_write(session))
+		return SKS_CKR_SESSION_READ_ONLY;
+
+	if (pkcs11_session_is_security_officer(session)) {
+		if (!(session->token->db_main->flags &
+		      SKS_CKFT_TOKEN_INITIALIZED))
+			return SKS_ERROR;
+
+		rv = check_so_pin(session, old_pin, old_pin_size);
+		if (rv)
+			return rv;
+
+		return set_pin(session, pin, pin_size, SKS_CKU_SO);
+	}
+
+	if (!(session->token->db_main->flags & SKS_CKFT_USER_PIN_INITIALIZED))
+		return SKS_ERROR;
+
+	rv = check_user_pin(session, old_pin, old_pin_size);
+	if (rv)
+		return rv;
+
+	IMSG("SKSs%" PRIu32 ": set PIN", session_handle);
+
+	return set_pin(session, pin, pin_size, SKS_CKU_USER);
+}
+
+/* ctrl=[session][user_type][pin-size]{pin], in=unused, out=unused */
+uint32_t entry_login(uintptr_t tee_session, TEE_Param *ctrl,
+		     TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct pkcs11_session *sess = NULL;
+	struct pkcs11_client *client = NULL;
+	uint32_t user_type = 0;
+	uint32_t pin_size = 0;
+	void *pin = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	rv = serialargs_get(&ctrlargs, &user_type, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
+	if (rv)
+		return rv;
+
+	client = tee_session2client(tee_session);
+
+	switch (user_type) {
+	case SKS_CKU_SO:
+		if (pkcs11_session_is_security_officer(session))
+			return SKS_CKR_USER_ALREADY_LOGGED_IN;
+
+		if (pkcs11_session_is_user(session))
+			return SKS_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
+
+		TAILQ_FOREACH(sess, &client->session_list, link)
+			if (sess->token == session->token &&
+			    !pkcs11_session_is_read_write(sess))
+				return SKS_CKR_SESSION_READ_ONLY_EXISTS;
+
+		TAILQ_FOREACH(client, &pkcs11_client_list, link) {
+			TAILQ_FOREACH(sess, &client->session_list, link) {
+				if (sess->token == session->token &&
+				    !pkcs11_session_is_public(sess))
+					return SKS_CKR_USER_TOO_MANY_TYPES;
+			}
+		}
+
+		rv = check_so_pin(session, pin, pin_size);
+		if (rv == SKS_OK)
+			session_login_so(session);
+
+		break;
+
+	case SKS_CKU_USER:
+		if (pkcs11_session_is_security_officer(session))
+			return SKS_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
+
+		if (pkcs11_session_is_user(session))
+			return SKS_CKR_USER_ALREADY_LOGGED_IN;
+
+		// TODO: check all client: if SO or user logged, we can return
+		// CKR_USER_TOO_MANY_TYPES.
+
+		rv = check_user_pin(session, pin, pin_size);
+		if (rv == SKS_OK)
+			session_login_user(session);
+
+		break;
+
+	case SKS_CKU_CONTEXT_SPECIFIC:
+		if (!session_is_active(session) ||
+		    !session->processing->always_authen)
+			return SKS_CKR_OPERATION_NOT_INITIALIZED;
+
+		if (pkcs11_session_is_public(session))
+			return SKS_CKR_FUNCTION_FAILED;
+
+		assert(pkcs11_session_is_user(session) ||
+			pkcs11_session_is_security_officer(session));
+
+		if (pkcs11_session_is_security_officer(session))
+			rv = check_so_pin(session, pin, pin_size);
+		else
+			rv = check_user_pin(session, pin, pin_size);
+
+		session->processing->relogged = (rv == SKS_OK);
+
+		if (rv == SKS_CKR_PIN_LOCKED)
+			session_logout(session);
+
+		break;
+
+	default:
+		return SKS_CKR_USER_TYPE_INVALID;
+	}
+
+	if (!rv)
+		IMSG("SKSs%" PRIu32 ": login", session_handle);
+
+	return rv;
+}
+
+/* ctrl=[session], in=unused, out=unused */
+uint32_t entry_logout(uintptr_t tee_session, TEE_Param *ctrl,
+		      TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	if (pkcs11_session_is_public(session))
+		return SKS_CKR_USER_NOT_LOGGED_IN;
+
+	session_logout(session);
+
+	IMSG("SKSs%" PRIu32 ": logout", session_handle);
+
+	return SKS_OK;
+}
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_token.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_token.h
new file mode 100644
index 0000000..cf2e8fa
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/pkcs11_token.h
@@ -0,0 +1,348 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+#ifndef __SKS_PKCS11_TOKEN_H__
+#define __SKS_PKCS11_TOKEN_H__
+
+#include <sys/queue.h>
+#include <tee_internal_api.h>
+
+#include "handle.h"
+#include "object.h"
+#include "pkcs11_attributes.h"
+
+/* Hard coded description */
+#define SKS_CRYPTOKI_TOKEN_LABEL		"op-tee pkcs#11 token (dev...)"
+#define SKS_CRYPTOKI_TOKEN_MANUFACTURER		"Linaro"
+#define SKS_CRYPTOKI_TOKEN_MODEL		"OP-TEE SKS TA"
+#define SKS_CRYPTOKI_TOKEN_SERIAL_NUMBER	"0000000000000000"
+#define SKS_CRYPTOKI_TOKEN_HW_VERSION		{ 0, 0 }
+#define SKS_CRYPTOKI_TOKEN_FW_VERSION		{ 0, 0 }
+
+#define SKS_CRYPTOKI_SLOT_DESCRIPTION		"OP-TEE SKS TA"
+#define SKS_CRYPTOKI_SLOT_MANUFACTURER		SKS_CRYPTOKI_TOKEN_MANUFACTURER
+#define SKS_CRYPTOKI_SLOT_HW_VERSION		SKS_CRYPTOKI_TOKEN_HW_VERSION
+#define SKS_CRYPTOKI_SLOT_FW_VERSION		SKS_CRYPTOKI_TOKEN_FW_VERSION
+
+#define PADDED_STRING_COPY(_dst, _src) \
+	do { \
+		TEE_MemFill((char *)(_dst), ' ', sizeof(_dst)); \
+		TEE_MemMove((char *)(_dst), (_src), \
+			    MIN(strlen((char *)(_src)), sizeof(_dst))); \
+	} while (0)
+
+enum pkcs11_token_state {
+	PKCS11_TOKEN_RESET = 0,
+	PKCS11_TOKEN_READ_WRITE,
+	PKCS11_TOKEN_READ_ONLY,
+};
+
+enum pkcs11_session_state {
+	PKCS11_SESSION_RESET = 0,
+	PKCS11_SESSION_PUBLIC_READ_WRITE,
+	PKCS11_SESSION_PUBLIC_READ_ONLY,
+	PKCS11_SESSION_USER_READ_WRITE,
+	PKCS11_SESSION_USER_READ_ONLY,
+	PKCS11_SESSION_SO_READ_WRITE,
+};
+
+TAILQ_HEAD(client_list, pkcs11_client);
+TAILQ_HEAD(session_list, pkcs11_session);
+
+#define SKS_MAX_USERS			2
+#define SKS_TOKEN_PIN_SIZE		128
+
+/*
+ * Persistent state of the token
+ *
+ * @version - currently unused...
+ * @label - pkcs11 formatted token label, set by client
+ * @flags - pkcs11 token flags
+ * @so_pin_count - counter on security officer login failure
+ * @so_pin_size - byte size of the provisioned SO PIN
+ * @so_pin - stores the SO PIN
+ * @user_pin_count - counter on user login failure
+ * @user_pin_size - byte size of the provisioned user PIN
+ * @user_pin - stores the user PIN
+ */
+struct token_persistent_main {
+	uint32_t version;
+
+	uint8_t label[SKS_TOKEN_LABEL_SIZE];
+	uint32_t flags;
+
+	uint32_t so_pin_count;
+	uint32_t so_pin_size;
+	uint8_t so_pin[SKS_TOKEN_PIN_SIZE];
+
+	uint32_t user_pin_count;
+	uint32_t user_pin_size;
+	uint8_t user_pin[SKS_TOKEN_PIN_SIZE];
+};
+
+/*
+ * Persistent objects in the token
+ *
+ * @count - number of object stored in the token
+ * @uudis - start of object references/UUIDs (@count items)
+ */
+struct token_persistent_objs {
+	uint32_t count;
+	TEE_UUID uuids[];
+};
+
+/*
+ * Runtime state of the token, complies with pkcs11
+ *
+ * @login_state - Pkcs11 login is public, user, SO or custom
+ * @db_hld - TEE handle on the persistent database object or TEE_HANDLE_NULL
+ * @pin_hld - TEE handles on PIN ciphering keys
+ * @db_main - Volatile copy of the persistent main database
+ * @session_count - Counter for opened Pkcs11 sessions
+ * @rw_session_count - Count for opened Pkcs11 read/write sessions
+ * @session_state - Login state of the token
+ * @session_list - Head of the list of the sessions owned by the token
+ */
+struct ck_token {
+	enum pkcs11_token_state state;
+	uint32_t session_count;
+	uint32_t rw_session_count;
+
+	struct object_list object_list;
+
+	TEE_ObjectHandle db_hdl;	/* Opened handle to persistent database */
+	TEE_ObjectHandle pin_hdl[SKS_MAX_USERS];	/* Opened handle to PIN keys */
+	struct token_persistent_main *db_main;		/* Copy persistent database */
+	struct token_persistent_objs *db_objs;		/* Copy persistent database */
+};
+
+/*
+ * A session can enter a processing state (encrypt, decrypt, digest, ...
+ * only from the initialized state. A session must return the initialized
+ * state (from a processing finalization request) before entering another
+ * processing state.
+ */
+enum pkcs11_proc_state {
+	PKCS11_SESSION_READY = 0,		/* No active processing/operation */
+	PKCS11_SESSION_ENCRYPTING,
+	PKCS11_SESSION_DECRYPTING,
+	PKCS11_SESSION_DIGESTING,
+	PKCS11_SESSION_DIGESTING_ENCRYPTING,	/* case C_DigestEncryptUpdate */
+	PKCS11_SESSION_DECRYPTING_DIGESTING,	/* case C_DecryptDigestUpdate */
+	PKCS11_SESSION_SIGNING,
+	PKCS11_SESSION_SIGNING_ENCRYPTING,	/* case C_SignEncryptUpdate */
+	PKCS11_SESSION_VERIFYING,
+	PKCS11_SESSION_DECRYPTING_VERIFYING,	/* case C_DecryptVerifyUpdate */
+	PKCS11_SESSION_SIGNING_RECOVER,
+	PKCS11_SESSION_VERIFYING_RECOVER,
+};
+
+/*
+ * Context of the active processing in the session
+ *
+ * @state - ongoing active processing function or ready state
+ * @mecha_type - mechanism type of the active processing
+ * @updated - true once an active operation is updated
+ * @relogged - true once client logged since last operation update
+ * @always_authen - true if user need to login before each use
+ * @tee_op_handle - handle on active crypto operation or TEE_HANDLE_NULL
+ * @extra_ctx - context for the active processing
+ */
+#define AES_BLOCK_SIZE          (16)
+#define SHA_MAX_OUTPUT_SIZE     (64)
+#define SHA_MAX_BLOCK_SIZE      (128)
+typedef struct
+{
+	uint8_t		algorithm;
+	uint8_t		CBC_IV[AES_BLOCK_SIZE];
+	uint8_t		CTR[AES_BLOCK_SIZE];
+	uint8_t		CMAC_Buf[AES_BLOCK_SIZE];
+	uint8_t		SHA_IV[SHA_MAX_OUTPUT_SIZE];
+	uint8_t		SHA_buf[SHA_MAX_BLOCK_SIZE];
+	uint32_t	SHA_remain_len;
+	uint8_t		isFirstUpdate;
+	uint8_t		H[AES_BLOCK_SIZE];
+	uint8_t		J0[AES_BLOCK_SIZE];
+	uint8_t		S[AES_BLOCK_SIZE];
+	uint32_t	add_len;
+	uint32_t	total_len;
+
+	vaddr_t		key1;
+	uint32_t	key1_len;
+	uint32_t	key1_id;
+	vaddr_t		key2;
+	uint32_t	key2_len;
+	uint32_t	key2_id;
+
+} MTK_HSM_State;
+
+struct active_processing {
+	enum pkcs11_proc_state state;
+	uint32_t mecha_type;
+	bool always_authen;
+	bool relogged;
+	bool updated;
+	// TODO: end time for object usage
+	TEE_OperationHandle tee_op_handle;
+	TEE_OperationHandle extra_op_handle;
+	MTK_HSM_State *mtk_hsm_handle;
+	void *extra_ctx;
+};
+
+/*
+ * Pkcs11 objects search context
+ *
+ * @attributes - matching attributes list searched (null if no search)
+ * @count - number of matching handle found
+ * @handles - array of handle of matching objects (published handles)
+ * @next - index of the next object handle to return to FindObject
+ * @temp_start - index of the trailing not yet published handles
+ */
+struct pkcs11_find_objects {
+	void *attributes;
+	size_t count;
+	uint32_t *handles;
+	size_t next;
+	size_t temp_start;
+};
+
+/*
+ * Structure tracking client applications
+ *
+ * TODO: rename pkcs11_client into sks_client
+ *
+ * @link - chained list of registered client applications
+ * @sessions - list of the PKCS11 sessions opened by the client application
+ */
+struct pkcs11_client {
+	TAILQ_ENTRY(pkcs11_client) link;
+	struct session_list session_list;
+	struct handle_db session_handle_db;
+};
+
+/*
+ * Structure tracking the PKCS#11 sessions
+ *
+ * @link - list of the session belonging to a client
+ * @tee_session - TEE session handle used by PKCS11 session client
+ * @client - client the session belongs to (FIXME: redundant with tee_session)
+ * @token - token this session belongs to
+ * @handle - identifier of the session published to the client
+ * @object_list - entry of the session objects list
+ * @object_handle_db - database for object handles published by the session
+ * @state - R/W SO, R/W user, RO user, R/W public, RO public.
+ * @find_ctx - point to active search context (null if no active search)
+ */
+struct pkcs11_session {
+	TAILQ_ENTRY(pkcs11_session) link;
+	uintptr_t tee_session;
+	struct pkcs11_client *client;
+	struct ck_token *token;
+	uint32_t handle;
+	struct object_list object_list;
+	struct handle_db object_handle_db;
+	enum pkcs11_session_state state;
+	struct active_processing *processing;
+	struct pkcs11_find_objects *find_ctx;
+};
+
+/* Initialize static token instance(s) from default/persistent database */
+int pkcs11_init(void);
+void pkcs11_deinit(void);
+
+/* Return token instance from token identifier */
+struct ck_token *get_token(unsigned int token_id);
+
+/* Return token identified from token instance address */
+unsigned int get_token_id(struct ck_token *token);
+
+/* Initialize target token database */
+struct ck_token *init_token_db(unsigned int token_id);
+
+/* Persistent database update */
+int update_persistent_db(struct ck_token *token, size_t offset, size_t size);
+void close_persistent_db(struct ck_token *token);
+
+/* Token persistent objects */
+uint32_t create_object_uuid(struct ck_token *token, struct sks_object *obj);
+void destroy_object_uuid(struct ck_token *token, struct sks_object *obj);
+uint32_t unregister_persistent_object(struct ck_token *token, TEE_UUID *uuid);
+uint32_t register_persistent_object(struct ck_token *token, TEE_UUID *uuid);
+uint32_t get_persistent_objects_list(struct ck_token *token,
+				     TEE_UUID *array, size_t *size);
+
+/*
+ * Pkcs11 session support
+ */
+struct pkcs11_client *tee_session2client(uintptr_t tee_session);
+uintptr_t register_client(void);
+void unregister_client(uintptr_t tee_session);
+
+void ck_token_close_tee_session(uintptr_t tee_session);
+struct pkcs11_session *sks_handle2session(uint32_t handle,
+					  uintptr_t tee_session);
+
+static inline bool session_is_active(struct pkcs11_session *session)
+{
+	return session->processing != NULL;
+}
+
+int set_processing_state(struct pkcs11_session *session,
+			 enum processing_func function,
+			 struct sks_object *obj1, struct sks_object *obj2);
+
+bool pkcs11_session_is_read_write(struct pkcs11_session *session);
+bool pkcs11_session_is_public(struct pkcs11_session *session);
+bool pkcs11_session_is_user(struct pkcs11_session *session);
+bool pkcs11_session_is_security_officer(struct pkcs11_session *session);
+
+static inline
+struct object_list *pkcs11_get_session_objects(struct pkcs11_session *session)
+{
+	return &session->object_list;
+}
+
+static inline
+struct ck_token *pkcs11_session2token(struct pkcs11_session *session)
+{
+	return session->token;
+}
+
+/*
+ * Entry point for the TA commands
+ */
+uint32_t entry_ck_slot_list(TEE_Param *ctrl, TEE_Param *in, TEE_Param *out);
+uint32_t entry_ck_slot_info(TEE_Param *ctrl, TEE_Param *in, TEE_Param *out);
+uint32_t entry_ck_token_info(TEE_Param *ctrl, TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_ck_token_initialize(TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_ck_token_mecha_ids(TEE_Param *ctrl,
+				  TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_ck_token_mecha_info(TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_ck_token_ro_session(uintptr_t teesess, TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out);
+uint32_t entry_ck_token_rw_session(uintptr_t teesess, TEE_Param *ctrl,
+				   TEE_Param *in, TEE_Param *out);
+uint32_t entry_ck_token_close_session(uintptr_t teesess, TEE_Param *ctrl,
+				      TEE_Param *in, TEE_Param *out);
+uint32_t entry_ck_token_close_all(uintptr_t teesess, TEE_Param *ctrl,
+				  TEE_Param *in, TEE_Param *out);
+uint32_t entry_ck_token_session_info(uintptr_t tee_session, TEE_Param *ctrl,
+				  TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_init_pin(uintptr_t tee_session, TEE_Param *ctrl,
+			TEE_Param *in, TEE_Param *out);
+uint32_t entry_set_pin(uintptr_t tee_session, TEE_Param *ctrl,
+		       TEE_Param *in, TEE_Param *out);
+uint32_t entry_login(uintptr_t tee_session, TEE_Param *ctrl,
+		     TEE_Param *in, TEE_Param *out);
+uint32_t entry_logout(uintptr_t tee_session, TEE_Param *ctrl,
+		      TEE_Param *in, TEE_Param *out);
+
+#endif /*__SKS_PKCS11_TOKEN_H__*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.c
new file mode 100644
index 0000000..c051855
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.c
@@ -0,0 +1,1875 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#include <assert.h>
+#include <sks_internal_abi.h>
+#include <sks_ta.h>
+#include <string.h>
+#include <tee_api_defines.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <util.h>
+
+#include "attributes.h"
+#include "object.h"
+#include "pkcs11_token.h"
+#include "pkcs11_attributes.h"
+#include "processing.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+#include "processing_mtk_hsm.h"
+#include "processing_mtk_key.h"
+
+static uint32_t get_ready_session(struct pkcs11_session **sess,
+				  uint32_t session_handle,
+				  uintptr_t tee_session)
+{
+	struct pkcs11_session *session = NULL;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	if (session_is_active(session))
+		return SKS_CKR_OPERATION_ACTIVE;
+
+	*sess = session;
+
+	return SKS_OK;
+}
+
+static bool func_matches_state(enum processing_func function,
+				enum pkcs11_proc_state state)
+{
+	switch (function) {
+	case SKS_FUNCTION_ENCRYPT:
+		return (state == PKCS11_SESSION_ENCRYPTING ||
+			state == PKCS11_SESSION_DIGESTING_ENCRYPTING ||
+			state == PKCS11_SESSION_SIGNING_ENCRYPTING);
+	case SKS_FUNCTION_DECRYPT:
+		return (state == PKCS11_SESSION_DECRYPTING ||
+			state == PKCS11_SESSION_DECRYPTING_DIGESTING ||
+			state == PKCS11_SESSION_DECRYPTING_VERIFYING);
+	case SKS_FUNCTION_DIGEST:
+		return (state == PKCS11_SESSION_DIGESTING ||
+			state == PKCS11_SESSION_DIGESTING_ENCRYPTING);
+	case SKS_FUNCTION_SIGN:
+		return (state == PKCS11_SESSION_SIGNING ||
+			state == PKCS11_SESSION_SIGNING_ENCRYPTING);
+	case SKS_FUNCTION_VERIFY:
+		return (state == PKCS11_SESSION_VERIFYING ||
+			state == PKCS11_SESSION_DECRYPTING_VERIFYING);
+	case SKS_FUNCTION_SIGN_RECOVER:
+		return state == PKCS11_SESSION_SIGNING_RECOVER;
+	case SKS_FUNCTION_VERIFY_RECOVER:
+		return state == PKCS11_SESSION_SIGNING_RECOVER;
+	default:
+		TEE_Panic(function);
+		return false;
+	}
+}
+
+static uint32_t get_active_session(struct pkcs11_session **sess,
+				  uint32_t session_handle,
+				  uintptr_t tee_session,
+				  enum processing_func function)
+{
+	struct pkcs11_session *session = NULL;
+	uint32_t rv = SKS_CKR_OPERATION_NOT_INITIALIZED;
+
+	session = sks_handle2session(session_handle, tee_session);
+	if (!session)
+		return SKS_CKR_SESSION_HANDLE_INVALID;
+
+	if (session->processing &&
+	    func_matches_state(function, session->processing->state)) {
+		*sess = session;
+		rv = SKS_OK;
+	}
+
+	return rv;
+}
+
+void release_active_processing(struct pkcs11_session *session)
+{
+	if (!session->processing)
+		return;
+
+	switch (session->processing->mecha_type) {
+	case SKS_CKM_AES_CTR:
+		tee_release_ctr_operation(session->processing);
+		break;
+	case SKS_CKM_AES_GCM:
+		tee_release_gcm_operation(session->processing);
+		break;
+	case SKS_CKM_AES_CCM:
+		tee_release_ccm_operation(session->processing);
+		break;
+	case SKS_CKM_SHA1_RSA_PKCS_PSS:
+	case SKS_CKM_SHA256_RSA_PKCS_PSS:
+	case SKS_CKM_SHA384_RSA_PKCS_PSS:
+	case SKS_CKM_SHA512_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS_PSS:
+		tee_release_rsa_pss_operation(session->processing);
+		break;
+	default:
+		break;
+	}
+
+	if (session->processing->mtk_hsm_handle != TEE_HANDLE_NULL) {
+		TEE_Free(session->processing->mtk_hsm_handle);
+		session->processing->mtk_hsm_handle = TEE_HANDLE_NULL;
+	}
+
+	if (session->processing->tee_op_handle != TEE_HANDLE_NULL) {
+		TEE_FreeOperation(session->processing->tee_op_handle);
+		session->processing->tee_op_handle = TEE_HANDLE_NULL;
+	}
+
+	if (session->processing->extra_op_handle != TEE_HANDLE_NULL) {
+		TEE_FreeOperation(session->processing->extra_op_handle);
+		session->processing->extra_op_handle = TEE_HANDLE_NULL;
+	}
+
+	TEE_Free(session->processing);
+	session->processing = NULL;
+}
+
+uint32_t entry_import_object(uintptr_t tee_session,
+			     TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_attrs_head *head = NULL;
+	struct sks_object_head *template = NULL;
+	size_t template_size = 0;
+	uint32_t obj_handle = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	/*
+	 * Collect the arguments of the request
+	 */
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < sizeof(uint32_t)) {
+		out->memref.size = sizeof(uint32_t);
+		return SKS_SHORT_BUFFER;
+	}
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_ready_session(&session, session_handle, tee_session);
+	if (rv)
+		return rv;
+
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		goto bail;
+
+	template_size = sizeof(*template) + template->attrs_size;
+
+	/*
+	 * Prepare a clean initial state for the requested object attributes.
+	 * Free temporary template once done.
+	 */
+	rv = create_attributes_from_template(&head, template, template_size,
+					     SKS_UNDEFINED_ID, NULL,
+					     SKS_FUNCTION_IMPORT);
+	TEE_Free(template);
+	template = NULL;
+	if (rv)
+		goto bail;
+
+	/*
+	 * Check target object attributes match target processing
+	 * Check target object attributes match token state
+	 */
+	rv = check_created_attrs_against_processing(SKS_PROCESSING_IMPORT,
+						    head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_token(session, head);
+	if (rv)
+		goto bail;
+
+	/*
+	 * TODO: test object (will check all expected attributes are in place
+	 */
+
+	/*
+	 * At this stage the object is almost created: all its attributes are
+	 * referenced in @head, including the key value and are assume
+	 * reliable. Now need to register it and get a handle for it.
+	 */
+	rv = create_object(session, head, &obj_handle);
+	if (rv)
+		goto bail;
+
+	/*
+	 * Now obj_handle (through the related struct sks_object instance)
+	 * owns the serialised buffer that holds the object attributes.
+	 * We reset attrs->buffer to NULL as serializer object is no more
+	 * the attributes buffer owner.
+	 */
+	head = NULL;
+
+	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(uint32_t));
+	out->memref.size = sizeof(uint32_t);
+
+	IMSG("SKSs%" PRIu32 ": import object 0x%" PRIx32,
+	     session_handle, obj_handle);
+
+bail:
+	TEE_Free(template);
+	TEE_Free(head);
+
+	return rv;
+}
+
+size_t get_object_key_bit_size(struct sks_object *obj)
+{
+	void *a_ptr = NULL;
+	uint32_t a_size = 0;
+	struct sks_attrs_head *attrs = obj->attributes;
+
+	switch (get_type(attrs)) {
+	case SKS_CKK_AES:
+	case SKS_CKK_GENERIC_SECRET:
+	case SKS_CKK_MD5_HMAC:
+	case SKS_CKK_SHA_1_HMAC:
+	case SKS_CKK_SHA224_HMAC:
+	case SKS_CKK_SHA256_HMAC:
+	case SKS_CKK_SHA384_HMAC:
+	case SKS_CKK_SHA512_HMAC:
+		if (get_attribute_ptr(attrs, SKS_CKA_VALUE, NULL, &a_size))
+			return 0;
+
+		return a_size * 8;
+
+	case SKS_CKK_RSA:
+		if (get_attribute_ptr(attrs, SKS_CKA_MODULUS, NULL, &a_size))
+			return 0;
+
+		return a_size * 8;
+
+	case SKS_CKK_EC:
+		if (get_attribute_ptr(attrs, SKS_CKA_EC_PARAMS,
+					&a_ptr, &a_size))
+			return 0;
+
+		return ec_params2tee_keysize(a_ptr, a_size);
+
+	default:
+		TEE_Panic(0);
+		return 0;
+	}
+}
+
+static uint32_t generate_random_key_value(struct sks_attrs_head **head)
+{
+	uint32_t rv = 0;
+	void *data;
+	uint32_t data_size;
+	uint32_t value_len;
+	void *value;
+	int keyid = 0;
+
+	if (!*head)
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+
+	rv = get_attribute_ptr(*head, SKS_CKA_VALUE_LEN, &data, &data_size);
+	if (rv || data_size != sizeof(uint32_t)) {
+		DMSG("%s", rv ? "No attribute value_len found" :
+			"Invalid size for attribute VALUE_LEN");
+		return SKS_CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+	TEE_MemMove(&value_len, data, data_size);
+
+	if (get_type(*head) == SKS_CKK_GENERIC_SECRET)
+		value_len = (value_len + 7) / 8;
+
+	value = TEE_Malloc(value_len, TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!value)
+		return SKS_MEMORY;
+
+	TEE_GenerateRandom(value, value_len);
+
+	rv = add_attribute(head, SKS_CKA_VALUE, value, value_len);
+
+	TEE_Free(value);
+
+	return rv;
+}
+
+static uint32_t generate_hsm_key(struct sks_attrs_head **head)
+{
+	uint32_t rv = 0;
+	void *data;
+	uint32_t data_size;
+	uint32_t value_len;
+	void *value;
+	int keyid = 0;
+
+	if (!*head)
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+
+	rv = get_attribute_ptr(*head, SKS_CKA_VALUE_LEN, &data, &data_size);
+	if (rv || data_size != sizeof(uint32_t)) {
+		DMSG("%s", rv ? "No attribute value_len found" :
+			"Invalid size for attribute VALUE_LEN");
+		return SKS_CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+	TEE_MemMove(&value_len, data, data_size);
+
+	if (get_type(*head) == SKS_CKK_GENERIC_SECRET)
+		value_len = (value_len + 7) / 8;
+
+	rv = mtk_generate_symmetric_key(value_len, &keyid);
+	if (rv)
+		return SKS_CKR_GENERAL_ERROR;
+
+	rv = add_attribute(head, SKS_CKA_HSM_KEY_ID, &keyid, sizeof(keyid));
+	if (rv)
+		return SKS_CKR_GENERAL_ERROR;
+
+	rv = add_attribute(head, SKS_CKA_HSM_KEY_LEN, &value_len, sizeof(value_len));
+	if (rv )
+		return SKS_CKR_GENERAL_ERROR;
+
+	return rv;
+}
+
+uint32_t entry_generate_secret(uintptr_t tee_session,
+			       TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_attribute_head *proc_params = NULL;
+	struct sks_attrs_head *head = NULL;
+	struct sks_object_head *template = NULL;
+	size_t template_size = 0;
+	uint32_t obj_handle = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < sizeof(uint32_t)) {
+		out->memref.size = sizeof(uint32_t);
+		return SKS_SHORT_BUFFER;
+	}
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_ready_session(&session, session_handle, tee_session);
+	if (rv)
+		return rv;
+
+	rv = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params);
+	if (rv)
+		goto bail;
+
+	switch (proc_params->id) {
+	case SKS_CKM_GENERIC_SECRET_KEY_GEN:
+	case SKS_CKM_AES_KEY_GEN:
+	case SKS_CKM_MTK_HSM_AES_KEY_GEN:
+		break;
+	default:
+		rv = SKS_CKR_MECHANISM_INVALID;
+		goto bail;
+	}
+
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		goto bail;
+
+	template_size = sizeof(*template) + template->attrs_size;
+
+	rv = check_mechanism_against_processing(session, proc_params->id,
+						SKS_FUNCTION_GENERATE,
+						SKS_FUNC_STEP_INIT);
+	if (rv)
+		goto bail;
+
+	/*
+	 * Prepare a clean initial state for the requested object attributes.
+	 * Free temporary template once done.
+	 */
+	rv = create_attributes_from_template(&head, template, template_size,
+					     proc_params->id, NULL,
+					     SKS_FUNCTION_GENERATE);
+	if (rv)
+		goto bail;
+
+	TEE_Free(template);
+	template = NULL;
+
+	rv = check_created_attrs(head, NULL);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_processing(proc_params->id, head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_token(session, head);
+	if (rv)
+		goto bail;
+
+	/* TODO : Not finished */
+	// rv = check_key_object_not_generated(session, head);
+	// if (rv)
+	// {
+	// 	IMSG("[%s][%d] check_key_object_not_generated\n", __FUNCTION__, __LINE__);
+	// 	goto bail;
+	// }
+
+	/*
+	 * Execute target processing and add value as attribute SKS_CKA_VALUE.
+	 * Symm key generation: depends on target processing to be used.
+	 */
+	switch (proc_params->id) {
+	case SKS_CKM_GENERIC_SECRET_KEY_GEN:
+	case SKS_CKM_AES_KEY_GEN:
+		/* Generate random of size specified by attribute VALUE_LEN */
+		rv = generate_random_key_value(&head);
+		if (rv)
+			goto bail;
+		break;
+
+	case SKS_CKM_MTK_HSM_AES_KEY_GEN:
+		rv = generate_hsm_key(&head);
+		if (rv)
+			goto bail;
+		break;
+	default:
+		rv = SKS_CKR_MECHANISM_INVALID;
+		goto bail;
+	}
+
+	TEE_Free(proc_params);
+	proc_params = NULL;
+
+	/*
+	 * Object is ready, register it and return a handle.
+	 */
+	rv = create_object(session, head, &obj_handle);
+	if (rv)
+		goto bail;
+
+	/*
+	 * Now obj_handle (through the related struct sks_object instance)
+	 * owns the serialized buffer that holds the object attributes.
+	 * We reset attrs->buffer to NULL as serializer object is no more
+	 * the attributes buffer owner.
+	 */
+	head = NULL;
+
+	TEE_MemMove(out->memref.buffer, &obj_handle, sizeof(uint32_t));
+	out->memref.size = sizeof(uint32_t);
+
+	IMSG("SKSs%" PRIu32 ": generate secret 0x%" PRIx32,
+	     session_handle, obj_handle);
+
+bail:
+	TEE_Free(proc_params);
+	TEE_Free(template);
+	TEE_Free(head);
+
+	return rv;
+}
+
+uint32_t alloc_get_tee_attribute_data(TEE_ObjectHandle tee_obj,
+					     uint32_t attribute,
+					     void **data, size_t *size)
+{
+	TEE_Result res = TEE_ERROR_GENERIC;
+	void *ptr = NULL;
+	uint32_t sz = 0;
+
+	res = TEE_GetObjectBufferAttribute(tee_obj, attribute, NULL, &sz);
+	if (res != TEE_ERROR_SHORT_BUFFER)
+		return SKS_FAILED;
+
+	ptr = TEE_Malloc(sz, TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!ptr)
+		return SKS_MEMORY;
+
+	res = TEE_GetObjectBufferAttribute(tee_obj, attribute, ptr, &sz);
+	if (res) {
+		TEE_Free(ptr);
+	} else {
+		*data = ptr;
+		*size = sz;
+	}
+
+	return tee2sks_error(res);
+}
+
+uint32_t tee2sks_add_attribute(struct sks_attrs_head **head, uint32_t sks_id,
+				TEE_ObjectHandle tee_obj, uint32_t tee_id)
+{
+	uint32_t rv = 0;
+	void *a_ptr = NULL;
+	size_t a_size = 0;
+
+	rv = alloc_get_tee_attribute_data(tee_obj, tee_id, &a_ptr, &a_size);
+	if (rv)
+		goto bail;
+
+	rv = add_attribute(head, sks_id, a_ptr, a_size);
+
+	TEE_Free(a_ptr);
+
+bail:
+	if (rv)
+		EMSG("Failed TEE attribute 0x%" PRIx32 "for %s (0x%" PRIx32 ")",
+				tee_id, sks2str_attr(sks_id), sks_id);
+	return rv;
+}
+
+uint32_t entry_generate_key_pair(uintptr_t teesess,
+				 TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_attribute_head *proc_params = NULL;
+	struct sks_attrs_head *pub_head = NULL;
+	struct sks_attrs_head *priv_head = NULL;
+	struct sks_object_head *template = NULL;
+	size_t template_size = 0;
+	uint32_t pubkey_handle = 0;
+	uint32_t privkey_handle = 0;
+	uint32_t *hdl_ptr = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < 2 * sizeof(uint32_t))
+		return SKS_SHORT_BUFFER;
+
+	// FIXME: cleaner way to test alignment of out buffer
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_ready_session(&session, session_handle, teesess);
+	if (rv)
+		return rv;
+
+	/* Get mechanism parameters */
+	rv = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params);
+	if (rv)
+		goto bail;
+
+	rv = check_mechanism_against_processing(session, proc_params->id,
+						SKS_FUNCTION_GENERATE_PAIR,
+						SKS_FUNC_STEP_INIT);
+	if (rv)
+		goto bail;
+
+	switch (proc_params->id) {
+	case SKS_CKM_EC_KEY_PAIR_GEN:
+	case SKS_CKM_RSA_PKCS_KEY_PAIR_GEN:
+	case SKS_CKM_MTK_HSM_EC_KEY_PAIR_GEN:
+		break;
+	default:
+		rv = SKS_CKR_MECHANISM_INVALID;
+		goto bail;
+	}
+
+	/* Get and check public key attributes */
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		goto bail;
+
+	template_size = sizeof(*template) + template->attrs_size;
+
+	rv = create_attributes_from_template(&pub_head, template, template_size,
+					     proc_params->id, NULL,
+					     SKS_FUNCTION_GENERATE_PAIR);
+	if (rv)
+		goto bail;
+
+	TEE_Free(template);
+	template = NULL;
+
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		goto bail;
+
+	template_size = sizeof(*template) + template->attrs_size;
+
+	rv = create_attributes_from_template(&priv_head, template, template_size,
+					     proc_params->id, NULL,
+					     SKS_FUNCTION_GENERATE_PAIR);
+	if (rv)
+		goto bail;
+
+	TEE_Free(template);
+	template = NULL;
+
+	/* Generate CKA_ID for keys if not specified by the templates */
+	rv = add_missing_attribute_id(&pub_head, &priv_head);
+	if (rv)
+		goto bail;
+
+	/* Check created object against processing and token state */
+	rv = check_created_attrs(pub_head, priv_head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_processing(proc_params->id, pub_head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_processing(proc_params->id, priv_head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_token(session, pub_head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_token(session, priv_head);
+	if (rv)
+		goto bail;
+
+	/* Generate key pair */
+	switch (proc_params->id) {
+	case SKS_CKM_EC_KEY_PAIR_GEN:
+		rv = generate_ec_keys(proc_params, &pub_head, &priv_head);
+		break;
+	case SKS_CKM_MTK_HSM_EC_KEY_PAIR_GEN:
+		rv = generate_hsm_ec_keys(proc_params, &pub_head, &priv_head);
+		break;
+	case SKS_CKM_RSA_PKCS_KEY_PAIR_GEN:
+		rv = generate_rsa_keys(proc_params, &pub_head, &priv_head);
+		break;
+	default:
+		rv = SKS_CKR_MECHANISM_INVALID;
+		break;
+	}
+	if (rv)
+		goto bail;
+
+	TEE_Free(proc_params);
+	proc_params = NULL;
+
+	/*
+	 * Object is ready, register it and return a handle.
+	 */
+	rv = create_object(session, pub_head, &pubkey_handle);
+	if (rv)
+		goto bail;
+
+	rv = create_object(session, priv_head, &privkey_handle);
+	if (rv)
+		goto bail;
+
+	/*
+	 * Now obj_handle (through the related struct sks_object instance)
+	 * owns the serialized buffer that holds the object attributes.
+	 * We reset attrs->buffer to NULL as serializer object is no more
+	 * the attributes buffer owner.
+	 */
+	pub_head = NULL;
+	priv_head = NULL;
+	hdl_ptr = (uint32_t *)out->memref.buffer;
+
+	TEE_MemMove(hdl_ptr, &pubkey_handle, sizeof(uint32_t));
+	TEE_MemMove(hdl_ptr + 1, &privkey_handle, sizeof(uint32_t));
+	out->memref.size = 2 * sizeof(uint32_t);
+
+	IMSG("SKSs%" PRIu32 ": create key pair 0x%" PRIx32 "/0x%" PRIx32,
+	     session_handle, privkey_handle, pubkey_handle);
+
+bail:
+	TEE_Free(proc_params);
+	TEE_Free(template);
+	TEE_Free(pub_head);
+	TEE_Free(priv_head);
+
+	return rv;
+}
+
+uint32_t entry_digesting_init(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out,
+				enum processing_func function)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_attribute_head *proc_params = NULL;
+	struct sks_object *obj = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_ready_session(&session, session_handle, tee_session);
+	if (rv)
+		return rv;
+
+	rv = set_processing_state(session, function, obj, NULL);
+	if (rv)
+		return rv;
+
+	rv = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params);
+	if (rv)
+		goto bail;
+
+	if (proc_params->id & SKS_CKM_MTK_HSM_EXT)
+	{
+		switch (proc_params->id)
+		{
+		case SKS_CKM_MTK_HSM_SHA1:
+		case SKS_CKM_MTK_HSM_SHA224:
+		case SKS_CKM_MTK_HSM_SHA256:
+		case SKS_CKM_MTK_HSM_SHA384:
+		case SKS_CKM_MTK_HSM_SHA512:
+			rv = mtk_SHA_init(session, proc_params);
+			break;
+
+		default:
+			rv = SKS_BAD_PARAM;
+			break;
+		}
+
+		if (rv == SKS_OK) {
+			session->processing->mecha_type = proc_params->id;
+			DMSG("SKSs%" PRIu32 ": init processing %s %s",
+			session_handle, sks2str_proc(proc_params->id),
+			sks2str_function(function));
+		} else {
+			EMSG(" entry_digesting_init FAIL!!  \n");
+		}
+
+		goto bail;
+	}
+
+
+bail:
+	if (rv && session)
+		release_active_processing(session);
+
+	TEE_Free(proc_params);
+
+	return rv;
+}
+
+uint32_t entry_digesting_step(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out,
+				enum processing_func function,
+				enum processing_step step)
+{
+
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	uint32_t mecha_type = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_active_session(&session, session_handle, tee_session,
+				function);
+	if (rv)
+		return rv;
+
+	mecha_type = session->processing->mecha_type;
+	if (mecha_type & SKS_CKM_MTK_HSM_EXT)
+	{
+		switch (mecha_type)
+		{
+		case SKS_CKM_MTK_HSM_SHA1:
+		case SKS_CKM_MTK_HSM_SHA224:
+		case SKS_CKM_MTK_HSM_SHA256:
+		case SKS_CKM_MTK_HSM_SHA384:
+		case SKS_CKM_MTK_HSM_SHA512:
+			rv = mtk_SHA_step(mecha_type, session, in, out, function, step);
+			break;
+
+		default:
+			rv = SKS_BAD_PARAM;
+			break;
+		}
+
+		goto bail;
+	}
+
+bail:
+	switch (step) {
+	case SKS_FUNC_STEP_UPDATE:
+		if (rv != SKS_OK && rv != SKS_SHORT_BUFFER)
+			release_active_processing(session);
+		break;
+	default:
+		/* ONESHOT and FINAL terminates processing on success */
+		if (rv != SKS_SHORT_BUFFER)
+			release_active_processing(session);
+		break;
+	}
+
+	return rv;
+}
+
+
+/*
+ * entry_processing_init - Generic entry for initializing a processing
+ *
+ * @ctrl = [session-handle]
+ * @in = input data or none
+ * @out = output data or none
+ * @function - encrypt, decrypt, sign, verify, digest, ...
+ *
+ * The generic part come that all the commands uses the same
+ * input/output invocation parameters format (ctrl/in/out).
+ */
+uint32_t entry_processing_init(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out,
+				enum processing_func function)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_attribute_head *proc_params = NULL;
+	uint32_t key_handle = 0;
+	struct sks_object *obj = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_ready_session(&session, session_handle, tee_session);
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&ctrlargs, &key_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	obj = sks_handle2object(key_handle, session);
+	if (!obj)
+		return SKS_CKR_KEY_HANDLE_INVALID;
+
+	rv = set_processing_state(session, function, obj, NULL);
+	if (rv)
+		return rv;
+
+	rv = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params);
+	if (rv)
+		goto bail;
+
+	rv = check_mechanism_against_processing(session, proc_params->id,
+						function, SKS_FUNC_STEP_INIT);
+	if (rv)
+		goto bail;
+
+	rv = check_parent_attrs_against_processing(proc_params->id, function,
+						   obj->attributes);
+	if (rv)
+		goto bail;
+
+	// rv = check_access_attrs_against_token(session, obj->attributes);
+	// if (rv)
+	// {
+	// 	IMSG("[%s][%d] rv %ld\n", __FUNCTION__, __LINE__, rv);
+	// 	goto bail;
+	// }
+
+	if (proc_params->id & SKS_CKM_MTK_HSM_EXT)
+	{
+		switch (proc_params->id)
+		{
+		case SKS_CKM_MTK_HSM_AES_ECB:
+			rv = mtk_AES_ECB_init(session, proc_params, obj);
+			break;
+
+		case SKS_CKM_MTK_HSM_AES_CBC:
+			rv = mtk_AES_CBC_init(session, proc_params, obj);
+			break;
+
+		case SKS_CKM_MTK_HSM_AES_CTR:
+			rv = mtk_AES_CTR_init(session, proc_params, obj);
+			break;
+
+		case SKS_CKM_MTK_HSM_AES_GCM:
+			rv = mtk_AES_GCM_init(session, proc_params, obj);
+			break;
+
+		case SKS_CKM_MTK_HSM_AES_CMAC:
+			rv = mtk_AES_CMAC_init(session, proc_params, obj);
+			break;
+
+		case SKS_CKM_MTK_HSM_SHA256_HMAC:
+		case SKS_CKM_MTK_HSM_SHA384_HMAC:
+			rv = mtk_HMAC_init(session, proc_params, obj);
+			break;
+
+		case SKS_CKM_MTK_HSM_ECDSA:
+			rv = mtk_ECDSA_init(session, proc_params, obj);
+			break;
+
+		case SKS_CKM_MTK_HSM_ECDSA_SHA1:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA224:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA256:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA384:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA512:
+			rv = mtk_ECDSA_SHA_init(session, proc_params, obj);
+			break;
+
+		default:
+			rv = SKS_BAD_PARAM;
+			break;
+		}
+
+		if (rv == SKS_OK) {
+			session->processing->mecha_type = proc_params->id;
+			DMSG("SKSs%" PRIu32 ": init processing %s %s",
+			session_handle, sks2str_proc(proc_params->id),
+			sks2str_function(function));
+		} else {
+			EMSG(" entry_processing_init FAIL!!  \n");
+		}
+
+		goto bail;
+	}
+
+	rv = SKS_CKR_MECHANISM_INVALID;
+	if (processing_is_tee_symm(proc_params->id)) {
+		rv = init_symm_operation(session, function, proc_params, obj);
+	}
+	if (processing_is_tee_asymm(proc_params->id)) {
+		rv = init_asymm_operation(session, function, proc_params, obj);
+	}
+	if (rv == SKS_OK) {
+		session->processing->mecha_type = proc_params->id;
+		IMSG("SKSs%" PRIu32 ": init processing %s %s",
+		     session_handle, sks2str_proc(proc_params->id),
+		     sks2str_function(function));
+	}
+
+bail:
+	if (rv && session)
+		release_active_processing(session);
+
+	TEE_Free(proc_params);
+
+	return rv;
+}
+
+/*
+ * entry_processing_step - Generic entry on active processing
+ *
+ * @ctrl = [session-handle]
+ * @in = input data or none
+ * @out = output data or none
+ * @function - encrypt, decrypt, sign, verify, digest, ...
+ * @step - update, oneshot, final
+ *
+ * The generic part come that all the commands uses the same
+ * input/output invocation parameters format (ctrl/in/out).
+ */
+uint32_t entry_processing_step(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out,
+				enum processing_func function,
+				enum processing_step step)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	uint32_t mecha_type = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_active_session(&session, session_handle, tee_session,
+				function);
+	if (rv)
+		return rv;
+
+	// TODO: check user authen and object activation dates
+	rv = check_mechanism_against_processing(session, mecha_type,
+						function, step);
+	if (rv)
+		goto bail;
+
+
+	mecha_type = session->processing->mecha_type;
+	rv = check_mechanism_against_processing(session, mecha_type,
+						function, step);
+	if (rv)
+		goto bail;
+
+	if (mecha_type & SKS_CKM_MTK_HSM_EXT)
+	{
+		switch (mecha_type)
+		{
+		case SKS_CKM_MTK_HSM_AES_ECB:
+			rv = mtk_AES_ECB_step(session, in, out, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_AES_CBC:
+			rv = mtk_AES_CBC_step(session, in, out, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_AES_CTR:
+			rv = mtk_AES_CTR_step(session, in, out, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_AES_GCM:
+			rv = mtk_AES_GCM_step(session, in, out, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_AES_CMAC:
+			rv = mtk_AES_CMAC_step(session, in, out, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_SHA256_HMAC:
+			rv = mtk_SHA256_HMAC_step(session, in, out, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_SHA384_HMAC:
+			rv = mtk_SHA384_HMAC_step(session, in, out, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_ECDSA:
+			rv = mtk_ECDSA_step(session, in, out, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_ECDSA_SHA1:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA224:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA256:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA384:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA512:
+			rv = mtk_ECDSA_SHA_step(session, in, out, function, step);
+			break;
+
+		default:
+			rv = SKS_BAD_PARAM;
+			break;
+		}
+
+		if (rv == SKS_OK) {
+			DMSG("SKSs%" PRIu32 ": init processing %s %s",
+			session_handle, sks2str_proc(mecha_type),
+			sks2str_function(function));
+		} else {
+			EMSG(" entry_processing_step FAIL!!  \n");
+		}
+
+		goto bail;
+	}
+
+	rv = SKS_CKR_MECHANISM_INVALID;
+	if (processing_is_tee_symm(mecha_type)) {
+		rv = step_symm_operation(session, function, step, in, out);
+	}
+	if (processing_is_tee_asymm(mecha_type)) {
+		rv = step_asymm_operation(session, function, step, in, out);
+	}
+	if (rv == SKS_OK) {
+		session->processing->updated = true;
+		IMSG("SKSs%" PRIu32 ": processing %s %s",
+		     session_handle, sks2str_proc(mecha_type),
+		     sks2str_function(function));
+	}
+
+bail:
+	switch (step) {
+	case SKS_FUNC_STEP_UPDATE:
+		if (rv != SKS_OK && rv != SKS_SHORT_BUFFER)
+			release_active_processing(session);
+		break;
+	default:
+		/* ONESHOT and FINAL terminates processing on success */
+		if (rv != SKS_SHORT_BUFFER)
+			release_active_processing(session);
+		break;
+	}
+
+	return rv;
+}
+
+/*
+ * entry_verify_oneshot - Generic entry on active processing
+ *
+ * @ctrl = [session-handle]
+ * @in = input data or none
+ * @out = output data or none
+ * @function - encrypt, decrypt, sign, verify, digest, ...
+ * @step - update, oneshot, final
+ *
+ * The generic part come that all the commands uses the same
+ * input/output invocation parameters format (ctrl/in/out).
+ */
+uint32_t entry_verify_oneshot(uintptr_t tee_session, TEE_Param *ctrl,
+				  TEE_Param *in, TEE_Param *in2,
+				  enum processing_func function,
+				  enum processing_step step)
+
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	uint32_t mecha_type = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	assert(function == SKS_FUNCTION_VERIFY);
+	if (!ctrl)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_active_session(&session, session_handle, tee_session,
+				function);
+	if (rv)
+		return rv;
+
+	// TODO: check user authen and object activation dates
+	rv = check_mechanism_against_processing(session, mecha_type,
+						function, step);
+	if (rv)
+		goto bail;
+
+
+	mecha_type = session->processing->mecha_type;
+	rv = check_mechanism_against_processing(session, mecha_type,
+						function, step);
+	if (rv)
+		goto bail;
+
+	if (mecha_type & SKS_CKM_MTK_HSM_EXT)
+	{
+		switch (mecha_type)
+		{
+		case SKS_CKM_MTK_HSM_AES_CMAC:
+			rv = mtk_AES_CMAC_step(session, in, in2, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_SHA256_HMAC:
+			rv = mtk_SHA256_HMAC_step(session, in, in2, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_SHA384_HMAC:
+			rv = mtk_SHA384_HMAC_step(session, in, in2, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_ECDSA:
+			rv = mtk_ECDSA_step(session, in, in2, function, step);
+			break;
+
+		case SKS_CKM_MTK_HSM_ECDSA_SHA1:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA224:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA256:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA384:
+		case SKS_CKM_MTK_HSM_ECDSA_SHA512:
+			rv = mtk_ECDSA_SHA_step(session, in, in2, function, step);
+			break;
+
+		default:
+			rv = SKS_BAD_PARAM;
+			break;
+		}
+
+		goto bail;
+	}
+
+	rv = SKS_CKR_MECHANISM_INVALID;
+	if (processing_is_tee_symm(mecha_type)) {
+		rv = step_symm_operation(session, function, step, in, in2);
+	}
+	if (processing_is_tee_asymm(mecha_type)) {
+		rv = step_asymm_operation(session, function, step, in, in2);
+	}
+
+	IMSG("SKSs%" PRIu32 ": verify %s %s: %s", session_handle,
+	     sks2str_proc(mecha_type), sks2str_function(function),
+	     sks2str_rc(rv));
+
+bail:
+	if (rv != SKS_SHORT_BUFFER)
+		release_active_processing(session);
+
+	return rv;
+}
+
+uint32_t entry_derive_key(uintptr_t tee_session, TEE_Param *ctrl,
+			  TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_attribute_head *proc_params = NULL;
+	uint32_t parent_handle = 0;
+	struct sks_object *parent_obj;
+	struct sks_attrs_head *head = NULL;
+	struct sks_object_head *template = NULL;
+	size_t template_size = 0;
+	uint32_t out_handle = 0;
+	uint32_t __maybe_unused mecha_id = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < sizeof(uint32_t)) {
+		out->memref.size = sizeof(uint32_t);
+		return SKS_SHORT_BUFFER;
+	}
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_ready_session(&session, session_handle, tee_session);
+	if (rv)
+		return rv;
+
+	rv = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params);
+	if (rv)
+		goto bail;
+
+	rv = serialargs_get(&ctrlargs, &parent_handle, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	parent_obj = sks_handle2object(parent_handle, session);
+	if (!parent_obj) {
+		rv = SKS_CKR_KEY_HANDLE_INVALID;
+		goto bail;
+	}
+
+	rv = set_processing_state(session, SKS_FUNCTION_DERIVE,
+				  parent_obj, NULL);
+	if (rv)
+		goto bail;
+
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		goto bail;
+
+	template_size = sizeof(*template) + template->attrs_size;
+
+	rv = check_mechanism_against_processing(session, proc_params->id,
+						SKS_FUNCTION_DERIVE,
+						SKS_FUNC_STEP_INIT);
+	if (rv)
+		goto bail;
+
+	rv = create_attributes_from_template(&head, template, template_size,
+					     proc_params->id, parent_obj->attributes,
+					     SKS_FUNCTION_DERIVE);
+	if (rv)
+		goto bail;
+
+	TEE_Free(template);
+	template = NULL;
+
+	rv = check_created_attrs(head, NULL);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_processing(proc_params->id, head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_token(session, head);
+	if (rv)
+		goto bail;
+
+	// TODO: check_created_against_parent(session, parent, child);
+	// This can handle DERVIE_TEMPLATE attributes from the parent key.
+
+	rv = SKS_CKR_MECHANISM_INVALID;
+	if (processing_is_tee_symm(proc_params->id)) {
+		rv = init_symm_operation(session, SKS_FUNCTION_DERIVE,
+					 proc_params, parent_obj);
+		if (rv)
+			goto bail;
+
+		rv = do_symm_derivation(session, proc_params,
+					parent_obj, &head);
+	}
+	if (processing_is_tee_asymm(proc_params->id)) {
+		rv = init_asymm_operation(session, SKS_FUNCTION_DERIVE,
+					  proc_params, parent_obj);
+		if (rv)
+			goto bail;
+
+		rv = do_asymm_derivation(session, proc_params, &head);
+	}
+	if (rv)
+		goto bail;
+
+#if 0
+	/* Exaustive list */
+	switch (proc_params->id) {
+	case SKS_CKM_ECDH1_DERIVE:	<--------------------------- TODO
+	//case SKS_CKM_ECDH1_COFACTOR_DERIVE:
+	case SKS_CKM_DH_PKCS_DERIVE:	<--------------------------- TODO
+	case SKS_CKM_X9_42_DH_DERIVE:
+	case SKS_CKM_X9_42_DH_HYBRID_DERIVE:
+	case SKS_CKM_X9_42_MQV_DERIVE:
+	case SKS_CKM_AES_GMAC
+	case SKS_CKM_AES_ECB_ENCRYPT_DATA	<------------------- TODO
+	case SKS_CKM_AES_CBC_ENCRYPT_DATA	<------------------- TODO
+	case SKS_CKM_SHA1_KEY_DERIVATION
+	case SKS_CKM_SHA224_KEY_DERIVATION
+	case SKS_CKM_SHA256_KEY_DERIVATION
+	case SKS_CKM_SHA384_KEY_DERIVATION
+	case SKS_CKM_SHA512_KEY_DERIVATION
+	case SKS_CKM_SHA512_224_KEY_DERIVATION
+	case SKS_CKM_SHA512_256_KEY_DERIVATION
+	case SKS_CKM_SHA512_T_KEY_DERIVATION
+	// Exhaustive list is made of Camelia, Aria, Seed, KIP, GOSTR3410,
+	// DES, 3DES, SSL3, TLS12, TLS-KDF, WTLS and concatenate  mechanisms.
+	case SKS_CKM_ECMQV_DERIVE:
+	}
+#endif
+
+	mecha_id = proc_params->id;
+	TEE_Free(proc_params);
+	proc_params = NULL;
+
+	/*
+	 * Object is ready, register it and return a handle.
+	 */
+	rv = create_object(session, head, &out_handle);
+	if (rv)
+		goto bail;
+
+	/*
+	 * Now out_handle (through the related struct sks_object instance)
+	 * owns the serialized buffer that holds the object attributes.
+	 * We reset attrs->buffer to NULL as serializer object is no more
+	 * the attributes buffer owner.
+	 */
+	head = NULL;
+
+	TEE_MemMove(out->memref.buffer, &out_handle, sizeof(uint32_t));
+	out->memref.size = sizeof(uint32_t);
+
+	IMSG("SKSs%" PRIu32 ": derive key Ox%" PRIx32 ", %s",
+	     session_handle, out_handle, sks2str_proc(mecha_id));
+
+bail:
+	release_active_processing(session);
+	TEE_Free(proc_params);
+	TEE_Free(template);
+	TEE_Free(head);
+
+	return rv;
+}
+
+
+uint32_t entry_generate_random(uintptr_t teesess, TEE_Param *ctrl,
+                               TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = SKS_OK;
+
+
+	if (!ctrl || !out)
+		return SKS_BAD_PARAM;
+
+	rv = mtk_generate_random(out);
+
+	return rv;
+}
+
+static uint32_t import_hsm_symmetric_key(struct sks_attrs_head **head, uint8_t *keyblob, int *blobsize)
+{
+	uint32_t rv = 0;
+	int keyid = 0;
+	uint8_t *pkeybuffer = NULL;
+	int value_size = 0;
+	// int size = 0;
+
+	if (!*head || !keyblob)
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+
+	rv = get_attribute_ptr(*head, SKS_CKA_VALUE, &pkeybuffer, &value_size);
+	if (rv) {
+		EMSG("[%s][%d] rv : %d\n", __FUNCTION__, __LINE__, rv);
+		return SKS_CKR_GENERAL_ERROR;
+	}
+
+	rv = mtk_import_key(pkeybuffer, value_size, &keyid, keyblob, blobsize, KEY_ALGO_ID_AES);
+	if (rv)
+		return SKS_CKR_GENERAL_ERROR;
+
+	IMSG("[%s][%d] keyid : 0x%x\n", __FUNCTION__, __LINE__, keyid);
+
+	rv = add_attribute(head, SKS_CKA_HSM_KEY_ID, &keyid, sizeof(keyid));
+	if (rv)
+		return SKS_CKR_GENERAL_ERROR;
+
+	rv = add_attribute(head, SKS_CKA_HSM_KEY_LEN, &value_size, sizeof(value_size));
+	if (rv )
+		return SKS_CKR_GENERAL_ERROR;
+
+
+	return rv;
+}
+
+
+uint32_t entry_import_key(uintptr_t tee_session,
+			     TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_attrs_head *head = NULL;
+	struct sks_object_head *template = NULL;
+	size_t template_size = 0;
+	uint32_t obj_handle = 0;
+	uint32_t key_type;
+	uint8_t *blobbuf = NULL;
+	uint32_t blobbufsize = 0;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	/*
+	 * Collect the arguments of the request
+	 */
+
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_ready_session(&session, session_handle, tee_session);
+	if (rv)
+		return rv;
+
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		goto bail;
+
+	template_size = sizeof(*template) + template->attrs_size;
+
+	/*
+	 * Prepare a clean initial state for the requested object attributes.
+	 * Free temporary template once done.
+	 */
+	rv = create_attributes_from_template(&head, template, template_size,
+					     SKS_UNDEFINED_ID, NULL,
+					     SKS_FUNCTION_IMPORT);
+	TEE_Free(template);
+	template = NULL;
+	if (rv)
+		goto bail;
+
+	/*
+	 * Check target object attributes match target processing
+	 * Check target object attributes match token state
+	 */
+	rv = check_created_attrs_against_processing(SKS_PROCESSING_IMPORT,
+						    head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_token(session, head);
+	if (rv)
+		goto bail;
+
+
+	blobbuf = out->memref.buffer;
+	blobbufsize = out->memref.size;
+	key_type = get_type(head);
+	switch (key_type)
+	{
+	case SKS_CKK_AES:
+	case SKS_CKK_GENERIC_SECRET:
+	case SKS_CKK_SHA_1_HMAC:
+	case SKS_CKK_SHA224_HMAC:
+	case SKS_CKK_SHA256_HMAC:
+	case SKS_CKK_SHA384_HMAC:
+	case SKS_CKK_SHA512_HMAC:
+		rv = import_hsm_symmetric_key(&head, blobbuf, &blobbufsize);
+		break;
+	default:
+		EMSG("[%s][%d] unknown keytype : %d\n", __FUNCTION__, __LINE__, key_type);
+		rv = SKS_CKR_KEY_TYPE_INCONSISTENT;
+		break;
+	}
+
+	if (rv)
+		goto bail;
+	/*
+	 * At this stage the object is almost created: all its attributes are
+	 * referenced in @head, including the key value and are assume
+	 * reliable. Now need to register it and get a handle for it.
+	 */
+	rv = create_object(session, head, &obj_handle);
+	if (rv)
+		goto bail;
+
+	/*
+	 * Now obj_handle (through the related struct sks_object instance)
+	 * owns the serialised buffer that holds the object attributes.
+	 * We reset attrs->buffer to NULL as serializer object is no more
+	 * the attributes buffer owner.
+	 */
+	head = NULL;
+
+	out->memref.size = blobbufsize;
+
+	IMSG("SKSs%" PRIu32 ": import object 0x%" PRIx32,
+	     session_handle, obj_handle);
+bail:
+	TEE_Free(template);
+	TEE_Free(head);
+
+
+	return rv;
+}
+
+uint32_t entry_import_key_pair(uintptr_t teesess,
+			     TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_attribute_head *proc_params = NULL;
+	struct sks_attrs_head *pub_head = NULL;
+	struct sks_attrs_head *priv_head = NULL;
+	struct sks_object_head *template = NULL;
+	size_t template_size = 0;
+	uint32_t pubkey_handle = 0;
+	uint32_t privkey_handle = 0;
+	uint32_t *hdl_ptr = NULL;
+	uint32_t blobbuflength;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+	if (!ctrl || in || !out)
+		return SKS_BAD_PARAM;
+
+	if (out->memref.size < MAX_BLOB_SIZE)
+		return SKS_SHORT_BUFFER;
+
+	blobbuflength = out->memref.size;
+
+	// FIXME: cleaner way to test alignment of out buffer
+	if ((uintptr_t)out->memref.buffer & 0x3UL)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_ready_session(&session, session_handle, teesess);
+	if (rv)
+		return rv;
+
+	/* Get mechanism parameters */
+	rv = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params);
+	if (rv)
+		goto bail;
+
+	switch (proc_params->id) {
+	case SKS_CKM_MTK_HSM_EC_KEY_PAIR_IMPORT:
+		break;
+	default:
+		rv = SKS_CKR_MECHANISM_INVALID;
+		goto bail;
+	}
+
+	/* Get and check public key attributes */
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		goto bail;
+
+	template_size = sizeof(*template) + template->attrs_size;
+	rv = create_attributes_from_template(&pub_head, template, template_size,
+										proc_params->id, NULL,
+										SKS_FUNCTION_GENERATE_PAIR);
+	if (rv)
+		goto bail;
+
+	TEE_Free(template);
+	template = NULL;
+
+	rv = serialargs_alloc_get_attributes(&ctrlargs, &template);
+	if (rv)
+		goto bail;
+
+	template_size = sizeof(*template) + template->attrs_size;
+	rv = create_attributes_from_template(&priv_head, template, template_size,
+										proc_params->id, NULL,
+										SKS_FUNCTION_GENERATE_PAIR);
+	if (rv)
+		goto bail;
+
+	TEE_Free(template);
+	template = NULL;
+
+	/* Generate CKA_ID for keys if not specified by the templates */
+	rv = add_missing_attribute_id(&pub_head, &priv_head);
+	if (rv)
+		goto bail;
+
+	/* Check created object against processing and token state */
+	rv = check_created_attrs(pub_head, priv_head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_processing(proc_params->id, pub_head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_processing(proc_params->id, priv_head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_token(session, pub_head);
+	if (rv)
+		goto bail;
+
+	rv = check_created_attrs_against_token(session, priv_head);
+	if (rv)
+		goto bail;
+
+	rv = import_hsm_ecc_keypair(&pub_head, &priv_head, out->memref.buffer, &blobbuflength);
+	if (rv)
+		goto bail;
+
+	TEE_Free(proc_params);
+	proc_params = NULL;
+
+	/*
+	 * Object is ready, register it and return a handle.
+	 */
+	rv = create_object(session, pub_head, &pubkey_handle);
+	if (rv)
+		goto bail;
+
+	rv = create_object(session, priv_head, &privkey_handle);
+	if (rv)
+		goto bail;
+
+	/*
+	 * Now obj_handle (through the related struct sks_object instance)
+	 * owns the serialized buffer that holds the object attributes.
+	 * We reset attrs->buffer to NULL as serializer object is no more
+	 * the attributes buffer owner.
+	 */
+	pub_head = NULL;
+	priv_head = NULL;
+
+	out->memref.size = blobbuflength;
+
+	IMSG("SKSs%" PRIu32 ": create key pair 0x%" PRIx32 "/0x%" PRIx32,
+		session_handle, privkey_handle, pubkey_handle);
+
+bail:
+	TEE_Free(proc_params);
+	TEE_Free(template);
+	TEE_Free(pub_head);
+	TEE_Free(priv_head);
+
+	return rv;
+}
+
+
+uint32_t entry_export_key_pair(uintptr_t teesess,
+			     TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	uint32_t mecha_type = 0;
+
+	uint8_t *keyblob;
+	uint32_t keybloblength;
+	uint8_t *pubkey;
+	uint32_t pubkeylength;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || !in || !out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	rv = get_ready_session(&session, session_handle, teesess);
+	if (rv)
+		goto bail;
+
+	keyblob = (uint8_t *)in->memref.buffer;
+	keybloblength = in->memref.size;
+	pubkey = (uint8_t *)out->memref.buffer;
+	pubkeylength = out->memref.size;
+
+	rv = mtk_export_key(keyblob, keybloblength, pubkey, &pubkeylength);
+	if (rv)
+		goto bail;
+
+	out->memref.size = pubkeylength;
+bail:
+
+	return rv;
+}
+
+
+uint32_t entry_utils(uintptr_t teesess,
+                     TEE_Param *ctrl, TEE_Param *in, TEE_Param *out)
+{
+	uint32_t rv = 0;
+	struct serialargs ctrlargs;
+	uint32_t session_handle = 0;
+	struct pkcs11_session *session = NULL;
+	struct sks_attribute_head *proc_params = NULL;
+	struct sks_object *obj = NULL;
+
+	TEE_MemFill(&ctrlargs, 0, sizeof(ctrlargs));
+
+	if (!ctrl || in || out)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
+
+	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = get_ready_session(&session, session_handle, teesess);
+	if (rv)
+		return rv;
+
+	rv = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params);
+	if (rv)
+		goto bail;
+
+	if (proc_params->id & SKS_CKM_MTK_HSM_EXT)
+	{
+		switch (proc_params->id)
+		{
+		case SKS_CKM_MTK_HSM_DUMP_LOG:
+			rv = mtk_dump_hsm_log();
+			break;
+
+		default:
+			rv = SKS_BAD_PARAM;
+			break;
+		}
+
+		if (rv == SKS_OK) {
+			DMSG("SKSs%" PRIu32 ": init processing %s %s",
+			     session_handle, sks2str_proc(proc_params->id),
+			     sks2str_function(function));
+		} else {
+			EMSG(" entry_utils FAIL!!  \n");
+		}
+
+		goto bail;
+	}
+
+
+bail:
+	if (rv && session)
+		release_active_processing(session);
+
+	TEE_Free(proc_params);
+
+	return rv;
+}
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.h
new file mode 100644
index 0000000..dc7525f
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing.h
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#ifndef __SKS_PROCESSING_H__
+#define __SKS_PROCESSING_H__
+
+#include <tee_internal_api.h>
+#include <pkcs11_attributes.h>
+
+struct pkcs11_session;
+struct sks_object;
+struct active_processing;
+
+/*
+ * Entry points from SKS TA invocation commands
+ */
+
+uint32_t entry_import_object(uintptr_t teesess, TEE_Param *ctrl,
+			     TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_generate_secret(uintptr_t teesess, TEE_Param *ctrl,
+			       TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_generate_key_pair(uintptr_t teesess, TEE_Param *ctrl,
+				 TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_digesting_init(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out,
+				enum processing_func function);
+uint32_t entry_digesting_step(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out,
+				enum processing_func function,
+				enum processing_step step);
+
+uint32_t entry_processing_init(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out,
+				enum processing_func function);
+
+uint32_t entry_processing_step(uintptr_t tee_session, TEE_Param *ctrl,
+				TEE_Param *in, TEE_Param *out,
+				enum processing_func function,
+				enum processing_step step);
+
+/* verify_oneshot is specific since it get 2 input data buffers */
+uint32_t entry_verify_oneshot(uintptr_t tee_session, TEE_Param *ctrl,
+				  TEE_Param *in1, TEE_Param *in2,
+				  enum processing_func function,
+				  enum processing_step step);
+
+uint32_t entry_derive_key(uintptr_t teesess, TEE_Param *ctrl,
+			  TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_generate_random(uintptr_t teesess, TEE_Param *ctrl,
+			  TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_import_key(uintptr_t tee_session,
+			     TEE_Param *ctrl, TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_import_key_pair(uintptr_t tee_session,
+			     TEE_Param *ctrl, TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_export_key_pair(uintptr_t teesess,
+			     TEE_Param *ctrl, TEE_Param *in, TEE_Param *out);
+
+uint32_t entry_utils(uintptr_t teesess,
+			     TEE_Param *ctrl, TEE_Param *in, TEE_Param *out);
+
+/*
+ * Util
+ */
+size_t get_object_key_bit_size(struct sks_object *obj);
+
+void release_active_processing(struct pkcs11_session *session);
+
+uint32_t alloc_get_tee_attribute_data(TEE_ObjectHandle tee_obj,
+					     uint32_t attribute,
+					     void **data, size_t *size);
+
+uint32_t tee2sks_add_attribute(struct sks_attrs_head **head, uint32_t sks_id,
+				TEE_ObjectHandle tee_obj, uint32_t tee_id);
+
+/*
+ * Symmetric crypto algorithm specific functions
+ */
+bool processing_is_tee_symm(uint32_t proc_id);
+
+uint32_t init_symm_operation(struct pkcs11_session *session,
+				enum processing_func function,
+				struct sks_attribute_head *proc_params,
+				struct sks_object *key);
+
+uint32_t step_symm_operation(struct pkcs11_session *session,
+				enum processing_func function,
+				enum processing_step step,
+				TEE_Param *io1, TEE_Param *io2);
+
+void tee_release_ctr_operation(struct active_processing *processing);
+uint32_t tee_init_ctr_operation(struct active_processing *processing,
+				    void *proc_params, size_t params_size);
+
+uint32_t tee_ae_decrypt_update(struct active_processing *processing,
+			       void *in, size_t in_size);
+
+uint32_t tee_ae_decrypt_final(struct active_processing *processing,
+			      void *out, uint32_t *out_size);
+
+uint32_t tee_ae_encrypt_final(struct active_processing *processing,
+			      void *out, uint32_t *out_size);
+
+void tee_release_ccm_operation(struct active_processing *processing);
+uint32_t tee_init_ccm_operation(struct active_processing *processing,
+				    void *proc_params, size_t params_size);
+
+void tee_release_gcm_operation(struct active_processing *processing);
+uint32_t tee_init_gcm_operation(struct active_processing *processing,
+				    void *proc_params, size_t params_size);
+
+/*  Asymmetric key operations util */
+bool processing_is_tee_asymm(uint32_t proc_id);
+
+uint32_t init_asymm_operation(struct pkcs11_session *session,
+				enum processing_func function,
+				struct sks_attribute_head *proc_params,
+				struct sks_object *obj);
+
+uint32_t do_symm_derivation(struct pkcs11_session *session,
+			     struct sks_attribute_head *proc_params,
+			     struct sks_object *parent_key,
+			     struct sks_attrs_head **head);
+
+uint32_t step_asymm_operation(struct pkcs11_session *session,
+			      enum processing_func function,
+			      enum processing_step step,
+			      TEE_Param *io1, TEE_Param *io2);
+
+uint32_t do_asymm_derivation(struct pkcs11_session *session,
+			     struct sks_attribute_head *proc_params,
+			     struct sks_attrs_head **head);
+
+
+/*
+ * Elliptic curve crypto algorithm specific functions
+ */
+uint32_t load_tee_ec_key_attrs(TEE_Attribute **tee_attrs, size_t *tee_count,
+				struct sks_object *obj);
+
+size_t ec_params2tee_keysize(void *attr, size_t size);
+
+uint32_t ec_params2tee_curve(void *attr, size_t size);
+
+uint32_t sks2tee_algo_ecdh(uint32_t *tee_id,
+			   struct sks_attribute_head *proc_params,
+			   struct sks_object *obj);
+
+uint32_t sks2tee_ecdh_param_pub(struct sks_attribute_head *proc_params,
+			        void **pub_data, size_t *pub_size);
+
+uint32_t sks2tee_algo_ecdsa(uint32_t *tee_id,
+			   struct sks_attribute_head *proc_params,
+			   struct sks_object *obj);
+
+uint32_t generate_ec_keys(struct sks_attribute_head *proc_params,
+			  struct sks_attrs_head **pub_head,
+			  struct sks_attrs_head **priv_head);
+
+uint32_t generate_hsm_ec_keys(struct sks_attribute_head *proc_params,
+			  struct sks_attrs_head **pub_head,
+			  struct sks_attrs_head **priv_head);
+
+uint32_t import_hsm_ecc_keypair(
+					struct sks_attrs_head **pub,
+					struct sks_attrs_head **priv,
+					uint8_t *keyblob,
+					int *blobsize);
+/*
+ * RSA crypto algorithm specific functions
+ */
+uint32_t load_tee_rsa_key_attrs(TEE_Attribute **tee_attrs, size_t *tee_count,
+				struct sks_object *obj);
+
+uint32_t sks2tee_proc_params_rsa_pss(struct active_processing *processing,
+				     struct sks_attribute_head *proc_params);
+
+void tee_release_rsa_pss_operation(struct active_processing *processing);
+
+uint32_t sks2tee_algo_rsa_pss(uint32_t *tee_id,
+				struct sks_attribute_head *proc_params);
+
+uint32_t sks2tee_algo_rsa_oaep(uint32_t *tee_id,
+				struct sks_attribute_head *proc_params);
+
+uint32_t tee_init_rsa_aes_key_wrap_operation(struct active_processing *proc,
+					     void *proc_params,
+					     size_t params_size);
+
+uint32_t generate_rsa_keys(struct sks_attribute_head *proc_params,
+			   struct sks_attrs_head **pub_head,
+			   struct sks_attrs_head **priv_head);
+
+#endif /*__SKS_PROCESSING_H__*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_aes.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_aes.c
new file mode 100644
index 0000000..abade0a
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_aes.c
@@ -0,0 +1,659 @@
+/*
+ * Copyright (c) 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <assert.h>
+#include <compiler.h>
+#include <util.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+
+#include "pkcs11_token.h"
+#include "processing.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+uint32_t tee_init_ctr_operation(struct active_processing *processing,
+				    void *proc_params, size_t params_size)
+{
+	struct serialargs args;
+	uint32_t rv = 0;
+	/* CTR parameters */
+	uint32_t incr_counter = 0;
+	void *counter_bits = NULL;
+
+	TEE_MemFill(&args, 0, sizeof(args));
+
+	if (!proc_params)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&args, proc_params, params_size);
+
+	rv = serialargs_get(&args, &incr_counter, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	rv = serialargs_get_ptr(&args, &counter_bits, 16);
+	if (rv)
+		goto bail;
+
+	if (incr_counter != 1) {
+		DMSG("Supports only 1 bit increment counter: %d",
+						incr_counter);
+		rv = SKS_CKR_MECHANISM_PARAM_INVALID;
+		goto bail;
+	}
+
+	TEE_CipherInit(processing->tee_op_handle, counter_bits, 16);
+
+	rv = SKS_OK;
+
+bail:
+	return rv;
+}
+
+void tee_release_ctr_operation(struct active_processing *processing __unused)
+{
+}
+
+/*
+ * Authenticated ciphering: (CCM / GCM)
+ *
+ * As per PKCS#11, CCM/GCM decrypt shall not revealed the data until the
+ * decryption is completed and the mac verified. The SKS TA must retain the
+ * ciphered data until the CCM finalization. To do so, arrays of decrypted
+ * data are allocated during AE update processing and copied into client
+ * buffer at AE finalization.
+ *
+ * As per PKCS#11, CCM/GCM decrypt expect the tag/mac data to be provided
+ * inside the input data for DecryptUpdate() and friends. But the DecryptFinal
+ * API does not provide input data reference hence we do not know which is the
+ * last call to DecryptUpdate() where last bytes are not ciphered data but the
+ * requested tag/mac byte. To handle this, the TA saves the last input data
+ * bytes (length is defined by the tag byte size) in the AE context and
+ * waits the DecryptFinal() to either treat these as data bytes or tag/mac
+ * bytes. Refer to pending_tag and pending_size in struct ae_aes_context.
+ */
+
+/*
+ * @size - byte size of the allocated buffer
+ * @data - pointer to allocated data
+ */
+struct out_data_ref {
+	size_t size;
+	void *data;
+};
+
+/*
+ * @tag_byte_len - tag size in byte
+ * @pending_tag - Input data that could be the appended tag
+ * @pending_size - Size of pending input data that could be the tag
+ * @out_data - Pointer to an array of output data references.
+ * @out_count - Number of buffer references in out_data
+ */
+struct ae_aes_context {
+	size_t tag_byte_len;
+	char *pending_tag;
+	size_t pending_size;
+	struct out_data_ref *out_data;
+	size_t out_count;
+};
+
+static void release_ae_aes_context(struct ae_aes_context *ctx)
+{
+	size_t n = 0;
+
+	for (n = 0; n < ctx->out_count; n++) {
+		TEE_Free(ctx->out_data[n].data);
+	}
+
+	TEE_Free(ctx->out_data);
+	ctx->out_data = NULL;
+	ctx->out_count = 0;
+
+	TEE_Free(ctx->pending_tag);
+	ctx->pending_tag = NULL;
+}
+
+uint32_t tee_ae_decrypt_update(struct active_processing *processing,
+			       void *in, size_t in_size)
+{
+	struct ae_aes_context *ctx = processing->extra_ctx;
+	size_t data_len = 0;
+	uint32_t size = 0;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t rv = 0;
+	char *ct = NULL;
+	uint32_t ct_size = 0;
+	void *ptr = NULL;
+
+	if (!in_size)
+		return SKS_OK;
+
+	if (!in)
+		return SKS_BAD_PARAM;
+
+	/*
+	 * Save the last input bytes in case they are the tag
+	 * bytes and not ciphered data bytes to be decrypted.
+	 */
+
+	if (ctx->pending_size + in_size <= ctx->tag_byte_len) {
+		/*
+		 * Data bytes are all potential tag bytes.
+		 * We only need to update the pending_tag buffer,
+		 * and cannot treat any byte as data byte.
+		 */
+		TEE_MemMove(ctx->pending_tag + ctx->pending_size, in, in_size);
+
+		ctx->pending_size += in_size;
+
+		return SKS_OK;
+	}
+
+	/* Size of data that are not potential tag in pending and input data */
+	data_len = in_size + ctx->pending_size - ctx->tag_byte_len;
+
+	if (ctx->pending_size &&
+	    (ctx->pending_size + in_size) >= ctx->tag_byte_len) {
+		/* Process pending tag bytes that are effective data byte */
+		uint32_t len = MIN(data_len, ctx->pending_size);
+
+		res = TEE_AEUpdate(processing->tee_op_handle,
+				   ctx->pending_tag, len, NULL, &ct_size);
+
+		// TODO: explain this
+		if (res != TEE_ERROR_SHORT_BUFFER &&
+		    (res != TEE_SUCCESS || ct_size)) {
+			rv = SKS_ERROR;
+			goto bail;
+		}
+
+		/*
+		 * If output data to store (not revealed yet), redo with
+		 * an allocated temporary reference.
+		 */
+		if (ct_size) {
+			ct = TEE_Malloc(ct_size, TEE_USER_MEM_HINT_NO_FILL_ZERO);
+			if (!ct) {
+				rv = SKS_MEMORY;
+				goto bail;
+			}
+
+			res = TEE_AEUpdate(processing->tee_op_handle,
+					   ctx->pending_tag, len, ct, &ct_size);
+			if (res) {
+				rv = tee2sks_error(res);
+				goto bail;
+			}
+
+			/* Finally, no out data? Release temp buffer. */
+			if (!ct_size) {
+				TEE_Free(ct);
+				ct = NULL;
+				DMSG_RAW("\nWe expected some data!\n\n");
+			}
+		}
+
+		/* Save potential tag bytes for later */
+		TEE_MemMove(ctx->pending_tag, ctx->pending_tag + len,
+			    ctx->pending_size - len);
+
+		ctx->pending_size -= len;
+		data_len -= len;
+	}
+
+	if (data_len) {
+		/* Process input data that are not potential tag bytes */
+		size = 0;
+		res = TEE_AEUpdate(processing->tee_op_handle,
+				   in, data_len, NULL, &size);
+
+		if (res != TEE_ERROR_SHORT_BUFFER &&
+		    (res != TEE_SUCCESS || size)) {
+			rv = SKS_ERROR;
+			goto bail;
+		}
+
+		if (size) {
+			ptr = TEE_Realloc(ct, ct_size + size);
+			if (!ptr) {
+				rv = SKS_MEMORY;
+				goto bail;
+			}
+			ct = ptr;
+
+			res = TEE_AEUpdate(processing->tee_op_handle,
+					   in, data_len, ct + ct_size, &size);
+			if (res) {
+				rv = tee2sks_error(res);
+				goto bail;
+			}
+
+			ct_size += size;
+		}
+	}
+
+	/* Update pending tag in context if any */
+	data_len = in_size - data_len;
+	if (data_len > (ctx->tag_byte_len - ctx->pending_size)) {
+		/* This could be asserted */
+		rv = SKS_ERROR;
+		goto bail;
+	}
+
+	if (data_len) {
+		TEE_MemMove(ctx->pending_tag + ctx->pending_size,
+			    (char *)in + in_size - data_len, data_len);
+
+		ctx->pending_size += data_len;
+	}
+
+	/* Save output data reference in the context */
+	if (ct_size) {
+		ptr = TEE_Realloc(ctx->out_data, (ctx->out_count + 1) *
+				  sizeof(struct out_data_ref));
+		if (!ptr) {
+			rv = SKS_MEMORY;
+			goto bail;
+		}
+		ctx->out_data = ptr;
+		ctx->out_data[ctx->out_count].size = ct_size;
+		ctx->out_data[ctx->out_count].data = ct;
+		ctx->out_count++;
+	}
+
+	rv = SKS_OK;
+
+bail:
+	if (rv) {
+		TEE_Free(ct);
+	}
+
+	return rv;
+}
+
+static uint32_t reveale_ae_data(struct ae_aes_context *ctx,
+				void *out, uint32_t *out_size)
+{
+	size_t n = 0;
+	uint32_t req_size = 0;
+	char *out_ptr = out;
+
+	for (req_size = 0, n = 0; n < ctx->out_count; n++)
+		req_size += ctx->out_data[n].size;
+
+	if (*out_size < req_size) {
+		*out_size = req_size;
+		return SKS_SHORT_BUFFER;
+	}
+
+	if (!out_ptr)
+		return SKS_BAD_PARAM;
+
+	for (n = 0; n < ctx->out_count; n++) {
+		TEE_MemMove(out_ptr,
+			    ctx->out_data[n].data, ctx->out_data[n].size);
+
+		TEE_Free(ctx->out_data[n].data);
+		out_ptr += ctx->out_data[n].size;
+	}
+
+	TEE_Free(ctx->out_data);
+	ctx->out_data = NULL;
+	ctx->out_count = 0;
+
+	*out_size = req_size;
+
+	return SKS_OK;
+}
+
+uint32_t tee_ae_decrypt_final(struct active_processing *processing,
+			      void *out, uint32_t *out_size)
+{
+	struct ae_aes_context *ctx = processing->extra_ctx;
+	uint32_t rv = 0;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t data_size = 0;
+	void *data_ptr = NULL;
+
+	if (!out_size) {
+		DMSG("Expect at least a buffer for the output data");
+		return SKS_BAD_PARAM;
+	}
+
+	/* Final is already completed, only need to output the data */
+	if (!ctx->pending_tag)
+		return reveale_ae_data(ctx, out, out_size);
+
+	if (ctx->pending_size != ctx->tag_byte_len) {
+		DMSG("Not enough samples: %zu/%zu",
+			ctx->pending_size, ctx->tag_byte_len);
+		return SKS_FAILED;	// FIXME: CKR_ENCRYPTED_DATA_LEN_RANGE
+	}
+
+	data_size = 0;
+	res = TEE_AEDecryptFinal(processing->tee_op_handle,
+				 NULL, 0, NULL, &data_size,
+				 ctx->pending_tag, ctx->tag_byte_len);
+
+	if (res == TEE_ERROR_SHORT_BUFFER) {
+		data_ptr = TEE_Malloc(data_size,
+				      TEE_USER_MEM_HINT_NO_FILL_ZERO);
+		if (!data_ptr) {
+			rv = SKS_MEMORY;
+			goto bail;
+		}
+
+		res = TEE_AEDecryptFinal(processing->tee_op_handle,
+					 NULL, 0, data_ptr, &data_size,
+					 ctx->pending_tag, ctx->tag_byte_len);
+
+		if (!data_size) {
+			TEE_Free(data_ptr);
+			data_ptr = NULL;
+			DMSG_RAW("\nIs this expected from the Core API?\n\n");
+		}
+	}
+
+	/* AE decryption is completed */
+	TEE_Free(ctx->pending_tag);
+	ctx->pending_tag = NULL;
+
+	rv = tee2sks_error(res);
+	if (rv)
+		goto bail;
+
+	if (data_ptr) {
+		void *tmp_ptr = NULL;
+
+		tmp_ptr = TEE_Realloc(ctx->out_data,
+					(ctx->out_count + 1) *
+					sizeof(struct out_data_ref));
+		if (!tmp_ptr) {
+			rv = SKS_MEMORY;
+			goto bail;
+		}
+		ctx->out_data = tmp_ptr;
+		ctx->out_data[ctx->out_count].size = data_size;
+		ctx->out_data[ctx->out_count].data = data_ptr;
+		ctx->out_count++;
+
+		data_ptr = NULL;
+	}
+
+	rv = reveale_ae_data(ctx, out, out_size);
+
+bail:
+	TEE_Free(data_ptr);
+
+	return rv;
+}
+
+uint32_t tee_ae_encrypt_final(struct active_processing *processing,
+			      void *out, uint32_t *out_size)
+{
+	struct ae_aes_context *ctx = processing->extra_ctx;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint8_t *tag = NULL;
+	uint32_t tag_len = 0;
+	uint32_t size = 0;
+
+	if (!out || !out_size)
+		return SKS_BAD_PARAM;
+
+	/* Check the required sizes (warning: 2 output len: data + tag) */
+	res = TEE_AEEncryptFinal(processing->tee_op_handle,
+				 NULL, 0, NULL, &size,
+				 &tag, &tag_len);
+
+	if (tag_len != ctx->tag_byte_len ||
+	    (res != TEE_SUCCESS && res != TEE_ERROR_SHORT_BUFFER)) {
+		EMSG("Unexpected tag length %u/%zu or rc 0x%" PRIx32,
+			tag_len, ctx->tag_byte_len, res);
+		return SKS_ERROR;
+	}
+
+	if (*out_size < size + tag_len) {
+		*out_size = size + tag_len;
+		return SKS_SHORT_BUFFER;
+	}
+
+	/* Process data and tag input the client output buffer */
+	tag = (uint8_t *)out + size;
+
+	res = TEE_AEEncryptFinal(processing->tee_op_handle,
+				 NULL, 0, out, &size, tag, &tag_len);
+
+	if (tag_len != ctx->tag_byte_len) {
+		EMSG("Unexpected tag length");
+		return SKS_ERROR;
+	}
+
+	if (!res)
+		*out_size = size + tag_len;
+
+	return tee2sks_error(res);
+}
+
+uint32_t tee_init_ccm_operation(struct active_processing *processing,
+				void *proc_params, size_t params_size)
+{
+	uint32_t rv = 0;
+	struct ae_aes_context *params = NULL;
+	struct serialargs args;
+	/* CCM parameters */
+	uint32_t data_len = 0;
+	uint32_t nonce_len = 0;
+	void *nonce = NULL;
+	uint32_t aad_len = 0;
+	void *aad = NULL;
+	uint32_t mac_len = 0;
+
+	TEE_MemFill(&args, 0, sizeof(args));
+
+	if (!proc_params)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&args, proc_params, params_size);
+
+	rv = serialargs_get(&args, &data_len, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	rv = serialargs_get(&args, &nonce_len, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	// TODO: no need to copy nonce into secure world
+	rv = serialargs_alloc_and_get(&args, &nonce, nonce_len);
+	if (rv)
+		goto bail;
+
+	rv = serialargs_get(&args, &aad_len, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	// TODO: no need to copy aad into secure world
+	rv = serialargs_alloc_and_get(&args, &aad, aad_len);
+	if (rv)
+		goto bail;
+
+	rv = serialargs_get(&args, &mac_len, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	/* As per pkcs#11 mechanism specification */
+	if (data_len > 28 ||
+	    !nonce_len || nonce_len > 15 ||
+	    aad_len > 256 ||
+	    mac_len < 4 || mac_len > 16 || mac_len & 1) {
+		DMSG("Invalid parameters: data_len %" PRIu32
+			", nonce_len %" PRIu32 ", aad_len %" PRIu32
+			", mac_len %" PRIu32, data_len, nonce_len,
+			aad_len, mac_len);
+		rv = SKS_CKR_MECHANISM_PARAM_INVALID;
+		goto bail;
+	}
+
+	params = TEE_Malloc(sizeof(struct ae_aes_context),
+			    TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!params) {
+		rv = SKS_MEMORY;
+		goto bail;
+	}
+
+	params->tag_byte_len = mac_len;
+	params->out_count = 0;
+	params->pending_size = 0;
+	params->out_data = TEE_Malloc(sizeof(struct out_data_ref),
+				      TEE_MALLOC_FILL_ZERO);
+	params->pending_tag = TEE_Malloc(mac_len,
+					 TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!params->out_data || !params->pending_tag) {
+		rv = SKS_MEMORY;
+		goto bail;
+	}
+
+	TEE_AEInit(processing->tee_op_handle, nonce, nonce_len, mac_len * 8,
+					   aad_len, data_len);
+	if (aad_len)
+		TEE_AEUpdateAAD(processing->tee_op_handle, aad, aad_len);
+
+	/* Session processing owns the active processing params */
+	assert(!processing->extra_ctx);
+	processing->extra_ctx = params;
+
+	rv = SKS_OK;
+
+bail:
+	TEE_Free(nonce);
+	TEE_Free(aad);
+	if (rv && params) {
+		TEE_Free(params->out_data);
+		TEE_Free(params->pending_tag);
+		TEE_Free(params);
+	}
+	return rv;
+}
+
+void tee_release_ccm_operation(struct active_processing *processing)
+{
+	struct ae_aes_context *ctx = processing->extra_ctx;
+
+	release_ae_aes_context(ctx);
+	TEE_Free(processing->extra_ctx);
+	processing->extra_ctx = NULL;
+}
+
+/*
+ * GCM
+ */
+uint32_t tee_init_gcm_operation(struct active_processing *processing,
+				    void *proc_params, size_t params_size)
+{
+	struct serialargs args;
+	uint32_t rv = 0;
+	uint32_t tag_len = 0;
+	struct ae_aes_context *params = NULL;
+	/* GCM parameters */
+	uint32_t iv_len = 0;
+	void *iv = NULL;
+	uint32_t aad_len = 0;
+	void *aad = NULL;
+	uint32_t tag_bitlen = 0;
+
+	TEE_MemFill(&args, 0, sizeof(args));
+
+	if (!proc_params)
+		return SKS_BAD_PARAM;
+
+	serialargs_init(&args, proc_params, params_size);
+
+	rv = serialargs_get(&args, &iv_len, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	// TODO: no need to copy iv into secure world
+	rv = serialargs_alloc_and_get(&args, &iv, iv_len);
+	if (rv)
+		goto bail;
+
+	rv = serialargs_get(&args, &aad_len, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	// TODO: no need to copy aad into secure world
+	rv = serialargs_alloc_and_get(&args, &aad, aad_len);
+	if (rv)
+		goto bail;
+
+	rv = serialargs_get(&args, &tag_bitlen, sizeof(uint32_t));
+	if (rv)
+		goto bail;
+
+	tag_len = ROUNDUP(tag_bitlen, 8) / 8;
+
+	/* As per pkcs#11 mechanism specification */
+	if (tag_bitlen > 128 ||
+	    !iv_len || iv_len > 256) {
+		DMSG("Invalid parameters: tag_bit_len %" PRIu32
+			", iv_len %" PRIu32, tag_bitlen, iv_len);
+		rv = SKS_CKR_MECHANISM_PARAM_INVALID;
+		goto bail;
+	}
+
+	params = TEE_Malloc(sizeof(struct ae_aes_context),
+			    TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!params) {
+		rv = SKS_MEMORY;
+		goto bail;
+	}
+
+	/* Store the byte round up byte length for the tag */
+	params->tag_byte_len = tag_len;
+	params->out_count = 0;
+	params->pending_size = 0;
+	params->out_data = TEE_Malloc(sizeof(struct out_data_ref),
+				      TEE_MALLOC_FILL_ZERO);
+	params->pending_tag = TEE_Malloc(tag_len,
+					 TEE_USER_MEM_HINT_NO_FILL_ZERO);
+
+	if (!params->out_data || !params->pending_tag) {
+		rv = SKS_MEMORY;
+		goto bail;
+	}
+
+	/* Session processing owns the active processing params */
+	assert(!processing->extra_ctx);
+	processing->extra_ctx = params;
+
+	TEE_AEInit(processing->tee_op_handle, iv, iv_len, tag_bitlen, 0, 0);
+
+	if (aad_len)
+		TEE_AEUpdateAAD(processing->tee_op_handle, aad, aad_len);
+
+	rv = SKS_OK;
+
+bail:
+	TEE_Free(iv);
+	TEE_Free(aad);
+	if (rv && params) {
+		TEE_Free(params->out_data);
+		TEE_Free(params->pending_tag);
+		TEE_Free(params);
+	}
+
+	return rv;
+}
+
+void tee_release_gcm_operation(struct active_processing *processing)
+{
+	struct ae_aes_context *ctx = processing->extra_ctx;
+
+	release_ae_aes_context(ctx);
+	TEE_Free(processing->extra_ctx);
+	processing->extra_ctx = NULL;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_asymm.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_asymm.c
new file mode 100644
index 0000000..aeb4eba
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_asymm.c
@@ -0,0 +1,839 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2018, Linaro Limited
+ */
+
+#include <assert.h>
+#include <compiler.h>
+#include <utee_defines.h>
+#include <tee_api_defines.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+
+#include "attributes.h"
+#include "pkcs11_token.h"
+#include "processing.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+bool processing_is_tee_asymm(uint32_t proc_id)
+{
+	switch (proc_id) {
+	/* RSA flavors */
+	case SKS_CKM_RSA_PKCS:
+	case SKS_CKM_RSA_PKCS_OAEP:
+	case SKS_CKM_SHA1_RSA_PKCS:
+	case SKS_CKM_SHA224_RSA_PKCS:
+	case SKS_CKM_SHA256_RSA_PKCS:
+	case SKS_CKM_SHA384_RSA_PKCS:
+	case SKS_CKM_SHA512_RSA_PKCS:
+	case SKS_CKM_SHA1_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS_PSS:
+	case SKS_CKM_SHA256_RSA_PKCS_PSS:
+	case SKS_CKM_SHA384_RSA_PKCS_PSS:
+	case SKS_CKM_SHA512_RSA_PKCS_PSS:
+	/* EC flavors */
+	case SKS_CKM_ECDSA:
+	case SKS_CKM_ECDSA_SHA1:
+	case SKS_CKM_ECDSA_SHA224:
+	case SKS_CKM_ECDSA_SHA256:
+	case SKS_CKM_ECDSA_SHA384:
+	case SKS_CKM_ECDSA_SHA512:
+	case SKS_CKM_ECDH1_DERIVE:
+	case SKS_CKM_ECDH1_COFACTOR_DERIVE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static uint32_t sks2tee_algorithm(uint32_t *tee_id,
+				  enum processing_func function,
+				  struct sks_attribute_head *proc_params,
+				  struct sks_object *obj)
+{
+	static const uint32_t sks2tee_algo[][2] = {
+		/* RSA flavors */
+		{ SKS_CKM_RSA_PKCS, TEE_ALG_RSAES_PKCS1_V1_5
+				/* TEE_ALG_RSASSA_PKCS1_V1_5 on signatures */ },
+		{ SKS_CKM_RSA_PKCS_OAEP, 1 }, /* Need to look into params */
+		{ SKS_CKM_SHA1_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA1 },
+		{ SKS_CKM_SHA224_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA224 },
+		{ SKS_CKM_SHA256_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA256 },
+		{ SKS_CKM_SHA384_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA384 },
+		{ SKS_CKM_SHA512_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA512 },
+		{ SKS_CKM_SHA1_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1 },
+		{ SKS_CKM_SHA224_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224 },
+		{ SKS_CKM_SHA256_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256 },
+		{ SKS_CKM_SHA384_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384 },
+		{ SKS_CKM_SHA512_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512 },
+		/* EC flavors (Must find key size from the object) */
+		{ SKS_CKM_ECDSA, 1 },
+		{ SKS_CKM_ECDSA_SHA1, 1 },
+		{ SKS_CKM_ECDSA_SHA224, 1 },
+		{ SKS_CKM_ECDSA_SHA256, 1 },
+		{ SKS_CKM_ECDSA_SHA384, 1 },
+		{ SKS_CKM_ECDSA_SHA512, 1 },
+		{ SKS_CKM_ECDH1_DERIVE, 1 },
+		{ SKS_CKM_ECDH1_COFACTOR_DERIVE, 1 },
+	};
+	size_t end = sizeof(sks2tee_algo) / (2 * sizeof(uint32_t));
+	size_t n = 0;
+	uint32_t rv = 0;
+
+	for (n = 0; n < end; n++) {
+		if (proc_params->id == sks2tee_algo[n][0]) {
+			*tee_id = sks2tee_algo[n][1];
+			break;
+		}
+	}
+
+	switch (proc_params->id) {
+	case SKS_CKM_RSA_X_509:
+	case SKS_CKM_RSA_9796:
+	case SKS_CKM_RSA_PKCS_PSS:
+		EMSG("%s not supported by GPD TEE, need an alternative...",
+			sks2str_proc(proc_params->id));
+		break;
+	default:
+		break;
+	}
+
+	if (n == end)
+		return SKS_NOT_IMPLEMENTED;
+
+	switch (proc_params->id) {
+	case SKS_CKM_SHA1_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS_PSS:
+	case SKS_CKM_SHA256_RSA_PKCS_PSS:
+	case SKS_CKM_SHA384_RSA_PKCS_PSS:
+	case SKS_CKM_SHA512_RSA_PKCS_PSS:
+		rv = sks2tee_algo_rsa_pss(tee_id, proc_params);
+		break;
+	case SKS_CKM_RSA_PKCS_OAEP:
+		rv = sks2tee_algo_rsa_oaep(tee_id, proc_params);
+		break;
+	case SKS_CKM_ECDH1_DERIVE:
+		rv = sks2tee_algo_ecdh(tee_id, proc_params, obj);
+		break;
+	case SKS_CKM_ECDH1_COFACTOR_DERIVE:
+		return SKS_NOT_IMPLEMENTED;
+	case SKS_CKM_ECDSA:
+	case SKS_CKM_ECDSA_SHA1:
+	case SKS_CKM_ECDSA_SHA224:
+	case SKS_CKM_ECDSA_SHA256:
+	case SKS_CKM_ECDSA_SHA384:
+	case SKS_CKM_ECDSA_SHA512:
+		rv = sks2tee_algo_ecdsa(tee_id, proc_params, obj);
+		break;
+	default:
+		rv = SKS_OK;
+		break;
+	}
+
+	if (*tee_id == TEE_ALG_RSAES_PKCS1_V1_5 &&
+	    (function == SKS_FUNCTION_SIGN || function == SKS_FUNCTION_VERIFY))
+		*tee_id = TEE_ALG_RSASSA_PKCS1_V1_5;
+
+	return rv;
+}
+
+static uint32_t sks2tee_algo_id(uint32_t sks_id)
+{
+	static const uint32_t sks2tee_algo[][2] = {
+		/* RSA flavors */
+		{ SKS_CKM_RSA_PKCS, TEE_ALG_RSAES_PKCS1_V1_5
+				/* TEE_ALG_RSASSA_PKCS1_V1_5 on signatures */ },
+		{ SKS_CKM_RSA_PKCS_OAEP, 1 }, /* Need to look into params */
+		{ SKS_CKM_SHA1_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA1 },
+		{ SKS_CKM_SHA224_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA224 },
+		{ SKS_CKM_SHA256_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA256 },
+		{ SKS_CKM_SHA384_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA384 },
+		{ SKS_CKM_SHA512_RSA_PKCS, TEE_ALG_RSASSA_PKCS1_V1_5_SHA512 },
+		{ SKS_CKM_SHA1_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1 },
+		{ SKS_CKM_SHA224_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224 },
+		{ SKS_CKM_SHA256_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256 },
+		{ SKS_CKM_SHA384_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384 },
+		{ SKS_CKM_SHA512_RSA_PKCS_PSS,
+					TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512 },
+		/* EC flavors (Must find key size from the object) */
+		{ SKS_CKM_ECDSA, 1 },
+		{ SKS_CKM_ECDSA_SHA1, 1 },
+		{ SKS_CKM_ECDSA_SHA224, 1 },
+		{ SKS_CKM_ECDSA_SHA256, 1 },
+		{ SKS_CKM_ECDSA_SHA384, 1 },
+		{ SKS_CKM_ECDSA_SHA512, 1 },
+		{ SKS_CKM_ECDH1_DERIVE, 1 },
+		{ SKS_CKM_ECDH1_COFACTOR_DERIVE, 1 },
+	};
+	size_t end = sizeof(sks2tee_algo) / (2 * sizeof(uint32_t));
+	size_t n = 0;
+
+	for (n = 0; n < end; n++) {
+		if (sks_id == sks2tee_algo[n][0]) {
+			return sks2tee_algo[n][1];
+		}
+	}
+
+	switch (sks_id) {
+	case SKS_CKM_RSA_X_509:
+	case SKS_CKM_RSA_9796:
+	case SKS_CKM_RSA_PKCS_PSS:
+		EMSG("%s not supported by GPD TEE, need an alternative...",
+			sks2str_proc(sks_id));
+		break;
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+static uint32_t sks2tee_key_type(uint32_t *tee_type, struct sks_object *obj,
+				 enum processing_func function)
+{
+	uint32_t class = get_class(obj->attributes);
+	uint32_t type = get_type(obj->attributes);
+
+	switch (class) {
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+		break;
+	default:
+		TEE_Panic(class);
+		break;
+	}
+
+	switch (type) {
+	case SKS_CKK_EC:
+		if (class == SKS_CKO_PRIVATE_KEY) {
+			*tee_type = (function == SKS_FUNCTION_DERIVE) ?
+					TEE_TYPE_ECDH_KEYPAIR :
+					TEE_TYPE_ECDSA_KEYPAIR;
+		} else {
+			*tee_type = (function == SKS_FUNCTION_DERIVE) ?
+					TEE_TYPE_ECDH_PUBLIC_KEY :
+					TEE_TYPE_ECDSA_PUBLIC_KEY;
+		}
+		break;
+	case SKS_CKK_RSA:
+		if (class == SKS_CKO_PRIVATE_KEY) {
+			*tee_type = TEE_TYPE_RSA_KEYPAIR;
+		} else {
+			*tee_type = TEE_TYPE_RSA_PUBLIC_KEY;
+		}
+		break;
+	default:
+		TEE_Panic(type);
+		break;
+	}
+
+	return SKS_OK;
+}
+
+static uint32_t allocate_tee_operation(struct pkcs11_session *session,
+					enum processing_func function,
+					struct sks_attribute_head *proc_params,
+					struct sks_object *obj)
+{
+	uint32_t size = (uint32_t)get_object_key_bit_size(obj);
+	uint32_t algo = 0;
+	uint32_t mode = 0;
+	TEE_Result res = TEE_ERROR_GENERIC;
+
+	assert(session->processing->tee_op_handle == TEE_HANDLE_NULL);
+
+	if (sks2tee_algorithm(&algo, function, proc_params, obj))
+		return SKS_FAILED;
+
+	sks2tee_mode(&mode, function);
+
+	res = TEE_AllocateOperation(&session->processing->tee_op_handle,
+				    algo, mode, size);
+	switch (res) {
+	case TEE_ERROR_NOT_SUPPORTED:
+		return SKS_CKR_MECHANISM_INVALID;
+	case TEE_SUCCESS:
+		break;
+	default:
+		EMSG("TEE_AllocateOp. failed %" PRIx32 " %" PRIx32 " %" PRIx32,
+			algo, mode, size);
+	}
+
+	return tee2sks_error(res);
+}
+
+static uint32_t load_tee_key(struct pkcs11_session *session,
+				struct sks_object *obj,
+				enum processing_func function)
+{
+	TEE_Attribute *tee_attrs = NULL;
+	size_t tee_attrs_count = 0;
+	size_t object_size = 0;
+	uint32_t rv = 0;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t __maybe_unused class = get_class(obj->attributes);
+	uint32_t type = get_type(obj->attributes);
+
+	assert(class == SKS_CKO_PUBLIC_KEY || class == SKS_CKO_PRIVATE_KEY);
+
+	if (obj->key_handle != TEE_HANDLE_NULL) {
+		switch (type) {
+		case SKS_CKK_RSA:
+			/* RSA loaded keys can be reused */
+			assert((obj->key_type == TEE_TYPE_RSA_PUBLIC_KEY &&
+				class == SKS_CKO_PUBLIC_KEY) ||
+			       (obj->key_type == TEE_TYPE_RSA_KEYPAIR &&
+				class == SKS_CKO_PRIVATE_KEY));
+			goto key_ready;
+		case SKS_CKK_EC:
+			/* Reuse EC TEE key only if already DSA or DH */
+			switch (obj->key_type) {
+			case TEE_TYPE_ECDSA_PUBLIC_KEY:
+			case TEE_TYPE_ECDSA_KEYPAIR:
+				if (function != SKS_FUNCTION_DERIVE)
+					goto key_ready;
+				break;
+			case TEE_TYPE_ECDH_PUBLIC_KEY:
+			case TEE_TYPE_ECDH_KEYPAIR:
+				if (function == SKS_FUNCTION_DERIVE)
+					goto key_ready;
+				break;
+			default:
+				assert(0);
+				break;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+
+		TEE_FreeTransientObject(obj->key_handle);
+		obj->key_handle = TEE_HANDLE_NULL;
+	}
+
+	rv = sks2tee_key_type(&obj->key_type, obj, function);
+	if (rv)
+		return rv;
+
+	object_size = get_object_key_bit_size(obj);
+	if (!object_size)
+		return SKS_ERROR;
+
+	switch (type) {
+	case SKS_CKK_RSA:
+		rv = load_tee_rsa_key_attrs(&tee_attrs, &tee_attrs_count, obj);
+		break;
+	case SKS_CKK_EC:
+		rv = load_tee_ec_key_attrs(&tee_attrs, &tee_attrs_count, obj);
+		break;
+	default:
+		break;
+	}
+	if (rv)
+		return rv;
+
+	res = TEE_AllocateTransientObject(obj->key_type, object_size,
+					  &obj->key_handle);
+	if (res) {
+		DMSG("TEE_AllocateTransientObject failed, 0x%" PRIx32, res);
+		return tee2sks_error(res);
+	}
+
+	res = TEE_PopulateTransientObject(obj->key_handle,
+					  tee_attrs, tee_attrs_count);
+
+	TEE_Free(tee_attrs);
+
+	if (res) {
+		DMSG("TEE_PopulateTransientObject failed, 0x%" PRIx32, res);
+		goto error;
+	}
+
+key_ready:
+	res = TEE_SetOperationKey(session->processing->tee_op_handle,
+				  obj->key_handle);
+	if (res) {
+		DMSG("TEE_SetOperationKey failed, 0x%" PRIx32, res);
+		goto error;
+	}
+
+	return tee2sks_error(res);
+
+error:
+	TEE_FreeTransientObject(obj->key_handle);
+	obj->key_handle = TEE_HANDLE_NULL;
+	return tee2sks_error(res);
+}
+
+static uint32_t tee_algo_to_tee_hash(uint32_t algo)
+{
+	switch (algo) {
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1:
+	case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1:
+	case TEE_ALG_SHA1:
+	case TEE_ALG_DSA_SHA1:
+	case TEE_ALG_HMAC_SHA1:
+		return TEE_ALG_SHA1;
+
+	case TEE_ALG_RSASSA_PKCS1_V1_5_MD5:
+	case TEE_ALG_MD5:
+	case TEE_ALG_HMAC_MD5:
+		return TEE_ALG_MD5;
+
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224:
+	case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224:
+	case TEE_ALG_SHA224:
+	case TEE_ALG_DSA_SHA224:
+	case TEE_ALG_HMAC_SHA224:
+		return TEE_ALG_SHA224;
+
+
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
+	case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256:
+	case TEE_ALG_SHA256:
+	case TEE_ALG_DSA_SHA256:
+	case TEE_ALG_HMAC_SHA256:
+		return TEE_ALG_SHA256;
+
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384:
+	case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384:
+	case TEE_ALG_SHA384:
+	case TEE_ALG_HMAC_SHA384:
+		return TEE_ALG_SHA384;
+
+	case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512:
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512:
+	case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512:
+	case TEE_ALG_SHA512:
+	case TEE_ALG_HMAC_SHA512:
+		return TEE_ALG_SHA512;
+
+	default:
+		return -1;
+	}
+
+    return -1;
+}
+
+static uint32_t init_tee_operation(struct pkcs11_session *session,
+				   struct sks_attribute_head *proc_params)
+{
+	uint32_t rv = SKS_OK;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	uint32_t hash = -1;
+
+	switch (proc_params->id) {
+	case SKS_CKM_SHA1_RSA_PKCS_PSS:
+	case SKS_CKM_SHA256_RSA_PKCS_PSS:
+	case SKS_CKM_SHA384_RSA_PKCS_PSS:
+	case SKS_CKM_SHA512_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS_PSS:
+		rv = sks2tee_proc_params_rsa_pss(session->processing,
+						 proc_params);
+		break;
+	default:
+		break;
+	}
+
+	hash = tee_algo_to_tee_hash(sks2tee_algo_id(proc_params->id));
+	if(hash != -1) {
+		res = TEE_AllocateOperation(&session->processing->extra_op_handle,hash,TEE_MODE_DIGEST,0);
+		if(res != TEE_SUCCESS)
+			rv = SKS_ERROR;
+	}
+	return rv;
+}
+
+uint32_t init_asymm_operation(struct pkcs11_session *session,
+				enum processing_func function,
+				struct sks_attribute_head *proc_params,
+				struct sks_object *obj)
+{
+	uint32_t rv = 0;
+
+	assert(processing_is_tee_asymm(proc_params->id));
+
+	rv = allocate_tee_operation(session, function, proc_params, obj);
+	if (rv)
+		return rv;
+
+	rv = load_tee_key(session, obj, function);
+	if (rv)
+		return rv;
+
+	return init_tee_operation(session, proc_params);
+}
+
+/*
+ * step_sym_step - step (update/oneshot/final) on a symmetric crypto operation
+ *
+ * @session - current session
+ * @function -
+ * @step - step ID in the processing (oneshot, update,final)
+ * @in - input data reference #1
+ * @io2 - input/output data reference #2 (direction depends on function)
+ */
+uint32_t step_asymm_operation(struct pkcs11_session *session,
+			      enum processing_func function,
+			      enum processing_step step,
+			      TEE_Param *in, TEE_Param *io2)
+{
+	uint32_t rv = SKS_ERROR;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	void *in_buf = in ? in->memref.buffer : NULL;
+	size_t in_size = in ? in->memref.size : 0;
+	void *out_buf = io2 ? io2->memref.buffer : NULL;
+	uint32_t out_size = io2 ? io2->memref.size : 0;
+	void *in2_buf = io2 ? io2->memref.buffer : NULL;
+	uint32_t in2_size = io2 ? io2->memref.size : 0;
+	TEE_Attribute *tee_attrs = NULL;
+	size_t tee_attrs_count = 0;
+	uint32_t data32 = 0;
+	bool output_data = false;
+	struct active_processing *proc = session->processing;
+	TEE_OperationInfo opinfo;
+	uint8_t hash_value[TEE_SHA512_HASH_SIZE] = {0};
+	uint32_t hash_size = 0;
+
+	switch (step) {
+	case SKS_FUNC_STEP_ONESHOT:
+	case SKS_FUNC_STEP_UPDATE:
+	case SKS_FUNC_STEP_FINAL:
+		break;
+	default:
+		return SKS_ERROR;
+	}
+
+	/* TEE attribute(s) required by the operation */
+	switch (proc->mecha_type) {
+	case SKS_CKM_SHA1_RSA_PKCS_PSS:
+	case SKS_CKM_SHA256_RSA_PKCS_PSS:
+	case SKS_CKM_SHA384_RSA_PKCS_PSS:
+	case SKS_CKM_SHA512_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS_PSS:
+		tee_attrs = TEE_Malloc(sizeof(TEE_Attribute),
+					TEE_USER_MEM_HINT_NO_FILL_ZERO);
+		if (!tee_attrs) {
+			rv = SKS_MEMORY;
+			goto bail;
+		}
+
+		data32 = *(uint32_t *)proc->extra_ctx;
+		TEE_InitValueAttribute(&tee_attrs[tee_attrs_count],
+					TEE_ATTR_RSA_PSS_SALT_LENGTH,
+					data32, 0);
+		tee_attrs_count++;
+		break;
+	default:
+		break;
+	}
+
+	/* TEE attribute(s) required by the operation */
+	switch (proc->mecha_type) {
+	case SKS_CKM_ECDSA_SHA1:
+	case SKS_CKM_ECDSA_SHA224:
+	case SKS_CKM_ECDSA_SHA256:
+	case SKS_CKM_ECDSA_SHA384:
+	case SKS_CKM_ECDSA_SHA512:
+		if (step == SKS_FUNC_STEP_FINAL)
+			break;
+
+		EMSG("TODO: compute hash for later authentication");
+		rv = SKS_NOT_IMPLEMENTED;
+		goto bail;
+	default:
+		/* Other mechanism do not expect multi stage operation */
+		rv = SKS_ERROR;
+		break;
+	}
+
+	if (proc->extra_op_handle) {
+		TEE_DigestUpdate(proc->extra_op_handle, in_buf, in_size);
+	}
+
+	if (step == SKS_FUNC_STEP_UPDATE)
+		goto bail;
+
+	if (proc->extra_op_handle) {
+		TEE_DigestDoFinal(proc->extra_op_handle, NULL, 0, hash_value, &hash_size);
+	}
+	/*
+	 * Finalize
+	 */
+
+	switch (proc->mecha_type) {
+		case SKS_CKM_SHA1_RSA_PKCS:
+		case SKS_CKM_SHA1_RSA_PKCS_PSS:
+		case SKS_CKM_SHA256_RSA_PKCS_PSS:
+		case SKS_CKM_SHA384_RSA_PKCS_PSS:
+		case SKS_CKM_SHA512_RSA_PKCS_PSS:
+		case SKS_CKM_SHA224_RSA_PKCS_PSS:
+		case SKS_CKM_SHA224_RSA_PKCS:
+		case SKS_CKM_SHA256_RSA_PKCS:
+		case SKS_CKM_SHA384_RSA_PKCS:
+		case SKS_CKM_SHA512_RSA_PKCS:
+			switch (function) {
+				case SKS_FUNCTION_SIGN:
+				case SKS_FUNCTION_VERIFY:
+					in_buf = hash_value;
+					in_size = hash_size;
+					break;
+				default :
+					break;
+			}
+			break;
+		default:
+			break;
+	}
+
+	/* These ECDSA need to use the computed hash as input data */
+	switch (proc->mecha_type) {
+	case SKS_CKM_ECDSA:
+		/* Input size depends on the key size */
+		if (!in_size) {
+			rv = SKS_FAILED;
+			goto bail;
+		}
+		TEE_GetOperationInfo(proc->tee_op_handle, &opinfo);
+		switch (opinfo.algorithm) {
+		case TEE_ALG_ECDSA_P192:
+			if (in_size > 24)
+				in_size = 24;
+			break;
+		case TEE_ALG_ECDSA_P224:
+			if (in_size > 28)
+				in_size = 28;
+			break;
+		case TEE_ALG_ECDSA_P256:
+			if (in_size > 32)
+				in_size = 32;
+			break;
+		case TEE_ALG_ECDSA_P384:
+			if (in_size > 48)
+				in_size = 48;
+			break;
+		case TEE_ALG_ECDSA_P521:
+			if (in_size > 64)
+				in_size = 64;
+			break;
+		default:
+			rv = SKS_FAILED;
+			goto bail;
+		}
+		/* Validate second input buffer size if verify */
+		if (function == SKS_FUNCTION_VERIFY &&
+				in2_size != 2 * in_size) {
+			rv = SKS_CKR_SIGNATURE_LEN_RANGE;
+			goto bail;
+		}
+		break;
+	case SKS_CKM_ECDSA_SHA1:
+		in_buf = proc->extra_ctx;
+		in_size = 192;
+		break;
+	case SKS_CKM_ECDSA_SHA224:
+		in_buf = proc->extra_ctx;
+		in_size = 224;
+		break;
+	case SKS_CKM_ECDSA_SHA256:
+		in_buf = proc->extra_ctx;
+		in_size = 256;
+		break;
+	case SKS_CKM_ECDSA_SHA384:
+		in_buf = proc->extra_ctx;
+		in_size = 384;
+		break;
+	case SKS_CKM_ECDSA_SHA512:
+		in_buf = proc->extra_ctx;
+		in_size = 512;
+		break;
+	default:
+		if (step != SKS_FUNC_STEP_ONESHOT) {
+			rv = SKS_ERROR;
+			goto bail;
+		}
+		break;
+	}
+
+	switch (proc->mecha_type) {
+	case SKS_CKM_ECDSA:
+	case SKS_CKM_ECDSA_SHA1:
+	case SKS_CKM_ECDSA_SHA224:
+	case SKS_CKM_ECDSA_SHA256:
+	case SKS_CKM_ECDSA_SHA384:
+	case SKS_CKM_ECDSA_SHA512:
+	case SKS_CKM_RSA_PKCS:
+	case SKS_CKM_RSA_9796:
+	case SKS_CKM_RSA_X_509:
+	case SKS_CKM_SHA1_RSA_PKCS:
+	case SKS_CKM_RSA_PKCS_OAEP:
+	case SKS_CKM_RSA_PKCS_PSS:
+	case SKS_CKM_SHA1_RSA_PKCS_PSS:
+	case SKS_CKM_SHA256_RSA_PKCS_PSS:
+	case SKS_CKM_SHA384_RSA_PKCS_PSS:
+	case SKS_CKM_SHA512_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS_PSS:
+	case SKS_CKM_SHA224_RSA_PKCS:
+	case SKS_CKM_SHA256_RSA_PKCS:
+	case SKS_CKM_SHA384_RSA_PKCS:
+	case SKS_CKM_SHA512_RSA_PKCS:
+		switch (function) {
+		case SKS_FUNCTION_ENCRYPT:
+			// TODO: TEE_ALG_RSAES_PKCS1_OAEP_MGF1_xxx takes an
+			// optional argument TEE_ATTR_RSA_OAEP_LABEL.
+			res = TEE_AsymmetricEncrypt(proc->tee_op_handle,
+						    tee_attrs, tee_attrs_count,
+						    in_buf, in_size,
+						    out_buf, &out_size);
+			output_data = true;
+			rv = tee2sks_error(res);
+			break;
+
+		case SKS_FUNCTION_DECRYPT:
+			res = TEE_AsymmetricDecrypt(proc->tee_op_handle,
+						    tee_attrs, tee_attrs_count,
+						    in_buf, in_size,
+						    out_buf, &out_size);
+			output_data = true;
+			rv = tee2sks_error(res);
+			break;
+
+		case SKS_FUNCTION_SIGN:
+			res = TEE_AsymmetricSignDigest(proc->tee_op_handle,
+							tee_attrs,
+							tee_attrs_count,
+							in_buf, in_size,
+							out_buf, &out_size);
+			output_data = true;
+			rv = tee2sks_error(res);
+			break;
+
+		case SKS_FUNCTION_VERIFY:
+			res = TEE_AsymmetricVerifyDigest(proc->tee_op_handle,
+							 tee_attrs,
+							 tee_attrs_count,
+							 in_buf, in_size,
+							 in2_buf, in2_size);
+			rv = tee2sks_error(res);
+			break;
+
+		default:
+			TEE_Panic(function);
+			break;
+		}
+		break;
+	default:
+		TEE_Panic(proc->mecha_type);
+		break;
+	}
+bail:
+	if (output_data && (rv == SKS_OK || rv == SKS_SHORT_BUFFER)) {
+		if (io2)
+			io2->memref.size = out_size;
+		else
+			rv = SKS_ERROR;
+	}
+
+	TEE_Free(tee_attrs);
+
+	return rv;
+}
+
+uint32_t do_asymm_derivation(struct pkcs11_session *session,
+			     struct sks_attribute_head *proc_params,
+			     struct sks_attrs_head **head)
+{
+	uint32_t rv = SKS_ERROR;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	TEE_Attribute tee_attrs[2];
+	size_t tee_attrs_count = 0;
+	TEE_ObjectHandle out_handle = TEE_HANDLE_NULL;
+	void *a_ptr = NULL;
+	size_t a_size = 0;
+	uint32_t key_bit_size = 0;
+	uint32_t key_byte_size = 0;
+
+	TEE_MemFill(tee_attrs, 0, sizeof(tee_attrs));
+
+	rv = get_u32_attribute(*head, SKS_CKA_VALUE_LEN, &key_bit_size);
+	if (rv)
+		return rv;
+
+	if (get_type(*head) != SKS_CKK_GENERIC_SECRET)
+		key_bit_size *= 8;
+
+	key_byte_size = (key_bit_size + 7) / 8;
+
+	res = TEE_AllocateTransientObject(TEE_TYPE_GENERIC_SECRET,
+					  key_byte_size * 8, &out_handle);
+	if (res) {
+		DMSG("TEE_AllocateTransientObject failed, 0x%" PRIx32, res);
+		return tee2sks_error(res);
+	}
+
+	switch (proc_params->id) {
+	case SKS_CKM_ECDH1_DERIVE:
+	case SKS_CKM_ECDH1_COFACTOR_DERIVE:
+		rv = sks2tee_ecdh_param_pub(proc_params, &a_ptr, &a_size);
+		if (rv)
+			goto bail;
+
+		// TODO: check size is the expected one (active proc key)
+		TEE_InitRefAttribute(&tee_attrs[tee_attrs_count],
+						TEE_ATTR_ECC_PUBLIC_VALUE_X,
+						a_ptr, a_size / 2);
+		tee_attrs_count++;
+
+		TEE_InitRefAttribute(&tee_attrs[tee_attrs_count],
+						TEE_ATTR_ECC_PUBLIC_VALUE_Y,
+						(char *)a_ptr + a_size / 2,
+						a_size / 2);
+		tee_attrs_count++;
+		break;
+	case SKS_CKM_DH_PKCS_DERIVE:
+		TEE_InitRefAttribute(&tee_attrs[tee_attrs_count],
+						TEE_ATTR_DH_PUBLIC_VALUE,
+						proc_params->data,
+						proc_params->size);
+		tee_attrs_count++;
+		break;
+	default:
+		TEE_Panic(proc_params->id);
+		break;
+	}
+
+	TEE_DeriveKey(session->processing->tee_op_handle,
+			&tee_attrs[0], tee_attrs_count, out_handle);
+
+	rv = alloc_get_tee_attribute_data(out_handle, TEE_ATTR_SECRET_VALUE,
+					  &a_ptr, &a_size);
+	if (rv)
+		goto bail;
+
+	if (a_size * 8 < key_bit_size) {
+		rv = SKS_CKR_KEY_SIZE_RANGE;
+	} else {
+		rv = add_attribute(head, SKS_CKA_VALUE, a_ptr, key_byte_size);
+	}
+
+	TEE_Free(a_ptr);
+bail:
+	release_active_processing(session);
+	TEE_FreeTransientObject(out_handle);
+	return rv;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_ec.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_ec.c
new file mode 100644
index 0000000..66aa446
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_ec.c
@@ -0,0 +1,1493 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#include <assert.h>
+#include <sks_internal_abi.h>
+#include <sks_ta.h>
+#include <string.h>
+#include <tee_api_defines.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <util.h>
+
+#include "attributes.h"
+#include "object.h"
+#include "pkcs11_token.h"
+#include "pkcs11_attributes.h"
+#include "processing.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+#include "processing_mtk_key.h"
+
+/*
+ * DER encoded EC parameters, dumped from openssl tools using something like
+ * openssl ecparam -name secp224r1 -param-enc [explicit]|
+ *    openssl asn1parse -noout -out /dev/stdout | od -t x1
+ */
+static const uint8_t prime192v1_name_der[] = {
+	0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01,
+};
+static const uint8_t secp224r1_name_der[] = {
+	0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x21,
+};
+static const uint8_t prime256v1_name_der[] = {
+	0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07,
+};
+static const uint8_t secp384r1_name_der[] = {
+	0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22,
+};
+static const uint8_t secp521r1_name_der[] = {
+	0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23,
+};
+static const uint8_t brainpoolP160r1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01,
+};
+static const uint8_t brainpoolP160t1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x02,
+};
+static const uint8_t brainpoolP192r1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x03,
+};
+static const uint8_t brainpoolP192t1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x04,
+};
+static const uint8_t brainpoolP224r1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x05,
+};
+static const uint8_t brainpoolP224t1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x06,
+};
+static const uint8_t brainpoolP256r1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07,
+};
+static const uint8_t brainpoolP256t1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x08,
+};
+static const uint8_t brainpoolP320r1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x09,
+};
+static const uint8_t brainpoolP320t1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0A,
+};
+static const uint8_t brainpoolP384r1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B,
+};
+static const uint8_t brainpoolP384t1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0C,
+};
+static const uint8_t brainpoolP512r1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D,
+};
+static const uint8_t brainpoolP512t1_name_der[] = {
+	0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0E,
+};
+
+static const uint8_t secp224r1_oid_der[] = {
+	0x30, 0x81, 0xDF, 0x02, 0x01, 0x01, 0x30, 0x28,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x1D, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+	0x30, 0x53, 0x04, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+	0x04, 0x1C, 0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04,
+	0xB3, 0xAB, 0xF5, 0x41, 0x32, 0x56, 0x50, 0x44,
+	0xB0, 0xB7, 0xD7, 0xBF, 0xD8, 0xBA, 0x27, 0x0B,
+	0x39, 0x43, 0x23, 0x55, 0xFF, 0xB4, 0x03, 0x15,
+	0x00, 0xBD, 0x71, 0x34, 0x47, 0x99, 0xD5, 0xC7,
+	0xFC, 0xDC, 0x45, 0xB5, 0x9F, 0xA3, 0xB9, 0xAB,
+	0x8F, 0x6A, 0x94, 0x8B, 0xC5, 0x04, 0x39, 0x04,
+	0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F,
+	0x32, 0x13, 0x90, 0xB9, 0x4A, 0x03, 0xC1, 0xD3,
+	0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6,
+	0x11, 0x5C, 0x1D, 0x21, 0xBD, 0x37, 0x63, 0x88,
+	0xB5, 0xF7, 0x23, 0xFB, 0x4C, 0x22, 0xDF, 0xE6,
+	0xCD, 0x43, 0x75, 0xA0, 0x5A, 0x07, 0x47, 0x64,
+	0x44, 0xD5, 0x81, 0x99, 0x85, 0x00, 0x7E, 0x34,
+	0x02, 0x1D, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0x16, 0xA2, 0xE0, 0xB8, 0xF0, 0x3E, 0x13,
+	0xDD, 0x29, 0x45, 0x5C, 0x5C, 0x2A, 0x3D, 0x02,
+	0x01, 0x01,
+};
+
+static const uint8_t secp384r1_oid_der[] = {
+	0x30, 0x82, 0x01, 0x57, 0x02, 0x01, 0x01, 0x30,
+	0x3C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+	0x01, 0x01, 0x02, 0x31, 0x00, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
+	0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x7B, 0x04,
+	0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
+	0xFC, 0x04, 0x30, 0xB3, 0x31, 0x2F, 0xA7, 0xE2,
+	0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B, 0xE3,
+	0xF8, 0x2D, 0x19, 0x18, 0x1D, 0x9C, 0x6E, 0xFE,
+	0x81, 0x41, 0x12, 0x03, 0x14, 0x08, 0x8F, 0x50,
+	0x13, 0x87, 0x5A, 0xC6, 0x56, 0x39, 0x8D, 0x8A,
+	0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3,
+	0xEC, 0x2A, 0xEF, 0x03, 0x15, 0x00, 0xA3, 0x35,
+	0x92, 0x6A, 0xA3, 0x19, 0xA2, 0x7A, 0x1D, 0x00,
+	0x89, 0x6A, 0x67, 0x73, 0xA4, 0x82, 0x7A, 0xCD,
+	0xAC, 0x73, 0x04, 0x61, 0x04, 0xAA, 0x87, 0xCA,
+	0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7,
+	0x1E, 0xF3, 0x20, 0xAD, 0x74, 0x6E, 0x1D, 0x3B,
+	0x62, 0x8B, 0xA7, 0x9B, 0x98, 0x59, 0xF7, 0x41,
+	0xE0, 0x82, 0x54, 0x2A, 0x38, 0x55, 0x02, 0xF2,
+	0x5D, 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E,
+	0x38, 0x72, 0x76, 0x0A, 0xB7, 0x36, 0x17, 0xDE,
+	0x4A, 0x96, 0x26, 0x2C, 0x6F, 0x5D, 0x9E, 0x98,
+	0xBF, 0x92, 0x92, 0xDC, 0x29, 0xF8, 0xF4, 0x1D,
+	0xBD, 0x28, 0x9A, 0x14, 0x7C, 0xE9, 0xDA, 0x31,
+	0x13, 0xB5, 0xF0, 0xB8, 0xC0, 0x0A, 0x60, 0xB1,
+	0xCE, 0x1D, 0x7E, 0x81, 0x9D, 0x7A, 0x43, 0x1D,
+	0x7C, 0x90, 0xEA, 0x0E, 0x5F, 0x02, 0x31, 0x00,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF,
+	0x58, 0x1A, 0x0D, 0xB2, 0x48, 0xB0, 0xA7, 0x7A,
+	0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73,
+	0x02, 0x01, 0x01,
+};
+static const uint8_t secp521r1_oid_der[] = {
+	0x30, 0x82, 0x01, 0xC2, 0x02, 0x01, 0x01, 0x30,
+	0x4D, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+	0x01, 0x01, 0x02, 0x42, 0x01, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x81,
+	0x9E, 0x04, 0x42, 0x01, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x04, 0x41, 0x51,
+	0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F,
+	0x92, 0x9A, 0x21, 0xA0, 0xB6, 0x85, 0x40, 0xEE,
+	0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3, 0x15, 0xF3,
+	0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1, 0x09, 0xE1,
+	0x56, 0x19, 0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B,
+	0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1, 0xBF, 0x07,
+	0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1,
+	0xEF, 0x45, 0x1F, 0xD4, 0x6B, 0x50, 0x3F, 0x00,
+	0x03, 0x15, 0x00, 0xD0, 0x9E, 0x88, 0x00, 0x29,
+	0x1C, 0xB8, 0x53, 0x96, 0xCC, 0x67, 0x17, 0x39,
+	0x32, 0x84, 0xAA, 0xA0, 0xDA, 0x64, 0xBA, 0x04,
+	0x81, 0x85, 0x04, 0x00, 0xC6, 0x85, 0x8E, 0x06,
+	0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, 0xCB,
+	0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81,
+	0x39, 0x05, 0x3F, 0xB5, 0x21, 0xF8, 0x28, 0xAF,
+	0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, 0x5E,
+	0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1,
+	0x27, 0xA2, 0xFF, 0xA8, 0xDE, 0x33, 0x48, 0xB3,
+	0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, 0x7E,
+	0x31, 0xC2, 0xE5, 0xBD, 0x66, 0x01, 0x18, 0x39,
+	0x29, 0x6A, 0x78, 0x9A, 0x3B, 0xC0, 0x04, 0x5C,
+	0x8A, 0x5F, 0xB4, 0x2C, 0x7D, 0x1B, 0xD9, 0x98,
+	0xF5, 0x44, 0x49, 0x57, 0x9B, 0x44, 0x68, 0x17,
+	0xAF, 0xBD, 0x17, 0x27, 0x3E, 0x66, 0x2C, 0x97,
+	0xEE, 0x72, 0x99, 0x5E, 0xF4, 0x26, 0x40, 0xC5,
+	0x50, 0xB9, 0x01, 0x3F, 0xAD, 0x07, 0x61, 0x35,
+	0x3C, 0x70, 0x86, 0xA2, 0x72, 0xC2, 0x40, 0x88,
+	0xBE, 0x94, 0x76, 0x9F, 0xD1, 0x66, 0x50, 0x02,
+	0x42, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFA, 0x51, 0x86, 0x87, 0x83, 0xBF,
+	0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7,
+	0x09, 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89,
+	0x9C, 0x47, 0xAE, 0xBB, 0x6F, 0xB7, 0x1E, 0x91,
+	0x38, 0x64, 0x09, 0x02, 0x01, 0x01,
+};
+static const uint8_t prime192v1_oid_der[] = {
+	0x30, 0x81, 0xC7, 0x02, 0x01, 0x01, 0x30, 0x24,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x19, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x4B, 0x04, 0x18,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
+	0x04, 0x18, 0x64, 0x21, 0x05, 0x19, 0xE5, 0x9C,
+	0x80, 0xE7, 0x0F, 0xA7, 0xE9, 0xAB, 0x72, 0x24,
+	0x30, 0x49, 0xFE, 0xB8, 0xDE, 0xEC, 0xC1, 0x46,
+	0xB9, 0xB1, 0x03, 0x15, 0x00, 0x30, 0x45, 0xAE,
+	0x6F, 0xC8, 0x42, 0x2F, 0x64, 0xED, 0x57, 0x95,
+	0x28, 0xD3, 0x81, 0x20, 0xEA, 0xE1, 0x21, 0x96,
+	0xD5, 0x04, 0x31, 0x04, 0x18, 0x8D, 0xA8, 0x0E,
+	0xB0, 0x30, 0x90, 0xF6, 0x7C, 0xBF, 0x20, 0xEB,
+	0x43, 0xA1, 0x88, 0x00, 0xF4, 0xFF, 0x0A, 0xFD,
+	0x82, 0xFF, 0x10, 0x12, 0x07, 0x19, 0x2B, 0x95,
+	0xFF, 0xC8, 0xDA, 0x78, 0x63, 0x10, 0x11, 0xED,
+	0x6B, 0x24, 0xCD, 0xD5, 0x73, 0xF9, 0x77, 0xA1,
+	0x1E, 0x79, 0x48, 0x11, 0x02, 0x19, 0x00, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0x99, 0xDE, 0xF8, 0x36, 0x14,
+	0x6B, 0xC9, 0xB1, 0xB4, 0xD2, 0x28, 0x31, 0x02,
+	0x01, 0x01,
+};
+static const uint8_t __unused prime192v2_oid_der[] = {
+	0x30, 0x81, 0xC7, 0x02, 0x01, 0x01, 0x30, 0x24,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x19, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x4B, 0x04, 0x18,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
+	0x04, 0x18, 0xCC, 0x22, 0xD6, 0xDF, 0xB9, 0x5C,
+	0x6B, 0x25, 0xE4, 0x9C, 0x0D, 0x63, 0x64, 0xA4,
+	0xE5, 0x98, 0x0C, 0x39, 0x3A, 0xA2, 0x16, 0x68,
+	0xD9, 0x53, 0x03, 0x15, 0x00, 0x31, 0xA9, 0x2E,
+	0xE2, 0x02, 0x9F, 0xD1, 0x0D, 0x90, 0x1B, 0x11,
+	0x3E, 0x99, 0x07, 0x10, 0xF0, 0xD2, 0x1A, 0xC6,
+	0xB6, 0x04, 0x31, 0x04, 0xEE, 0xA2, 0xBA, 0xE7,
+	0xE1, 0x49, 0x78, 0x42, 0xF2, 0xDE, 0x77, 0x69,
+	0xCF, 0xE9, 0xC9, 0x89, 0xC0, 0x72, 0xAD, 0x69,
+	0x6F, 0x48, 0x03, 0x4A, 0x65, 0x74, 0xD1, 0x1D,
+	0x69, 0xB6, 0xEC, 0x7A, 0x67, 0x2B, 0xB8, 0x2A,
+	0x08, 0x3D, 0xF2, 0xF2, 0xB0, 0x84, 0x7D, 0xE9,
+	0x70, 0xB2, 0xDE, 0x15, 0x02, 0x19, 0x00, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFE, 0x5F, 0xB1, 0xA7, 0x24, 0xDC,
+	0x80, 0x41, 0x86, 0x48, 0xD8, 0xDD, 0x31, 0x02,
+	0x01, 0x01,
+};
+static const uint8_t __unused prime192v3_oid_der[] = {
+	0x30, 0x81, 0xC7, 0x02, 0x01, 0x01, 0x30, 0x24,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x19, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x4B, 0x04, 0x18,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
+	0x04, 0x18, 0x22, 0x12, 0x3D, 0xC2, 0x39, 0x5A,
+	0x05, 0xCA, 0xA7, 0x42, 0x3D, 0xAE, 0xCC, 0xC9,
+	0x47, 0x60, 0xA7, 0xD4, 0x62, 0x25, 0x6B, 0xD5,
+	0x69, 0x16, 0x03, 0x15, 0x00, 0xC4, 0x69, 0x68,
+	0x44, 0x35, 0xDE, 0xB3, 0x78, 0xC4, 0xB6, 0x5C,
+	0xA9, 0x59, 0x1E, 0x2A, 0x57, 0x63, 0x05, 0x9A,
+	0x2E, 0x04, 0x31, 0x04, 0x7D, 0x29, 0x77, 0x81,
+	0x00, 0xC6, 0x5A, 0x1D, 0xA1, 0x78, 0x37, 0x16,
+	0x58, 0x8D, 0xCE, 0x2B, 0x8B, 0x4A, 0xEE, 0x8E,
+	0x22, 0x8F, 0x18, 0x96, 0x38, 0xA9, 0x0F, 0x22,
+	0x63, 0x73, 0x37, 0x33, 0x4B, 0x49, 0xDC, 0xB6,
+	0x6A, 0x6D, 0xC8, 0xF9, 0x97, 0x8A, 0xCA, 0x76,
+	0x48, 0xA9, 0x43, 0xB0, 0x02, 0x19, 0x00, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0x7A, 0x62, 0xD0, 0x31, 0xC8,
+	0x3F, 0x42, 0x94, 0xF6, 0x40, 0xEC, 0x13, 0x02,
+	0x01, 0x01,
+};
+static const uint8_t prime256v1_oid_der[] = {
+	0x30, 0x81, 0xF7, 0x02, 0x01, 0x01, 0x30, 0x2C,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0x30, 0x5B, 0x04, 0x20,
+	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
+	0x04, 0x20, 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A,
+	0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55, 0x76, 0x98,
+	0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53,
+	0xB0, 0xF6, 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2,
+	0x60, 0x4B, 0x03, 0x15, 0x00, 0xC4, 0x9D, 0x36,
+	0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66, 0x78,
+	0xE1, 0x13, 0x9D, 0x26, 0xB7, 0x81, 0x9F, 0x7E,
+	0x90, 0x04, 0x41, 0x04, 0x6B, 0x17, 0xD1, 0xF2,
+	0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5,
+	0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81,
+	0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45,
+	0xD8, 0x98, 0xC2, 0x96, 0x4F, 0xE3, 0x42, 0xE2,
+	0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A,
+	0x7C, 0x0F, 0x9E, 0x16, 0x2B, 0xCE, 0x33, 0x57,
+	0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68,
+	0x37, 0xBF, 0x51, 0xF5, 0x02, 0x21, 0x00, 0xFF,
+	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC,
+	0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, 0xF3,
+	0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51, 0x02,
+	0x01, 0x01,
+};
+static const uint8_t brainpoolP160r1_oid_der[] = {
+	0x30, 0x81, 0x98, 0x02, 0x01, 0x01, 0x30, 0x20,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x15, 0x00, 0xE9, 0x5E, 0x4A, 0x5F,
+	0x73, 0x70, 0x59, 0xDC, 0x60, 0xDF, 0xC7, 0xAD,
+	0x95, 0xB3, 0xD8, 0x13, 0x95, 0x15, 0x62, 0x0F,
+	0x30, 0x2C, 0x04, 0x14, 0x34, 0x0E, 0x7B, 0xE2,
+	0xA2, 0x80, 0xEB, 0x74, 0xE2, 0xBE, 0x61, 0xBA,
+	0xDA, 0x74, 0x5D, 0x97, 0xE8, 0xF7, 0xC3, 0x00,
+	0x04, 0x14, 0x1E, 0x58, 0x9A, 0x85, 0x95, 0x42,
+	0x34, 0x12, 0x13, 0x4F, 0xAA, 0x2D, 0xBD, 0xEC,
+	0x95, 0xC8, 0xD8, 0x67, 0x5E, 0x58, 0x04, 0x29,
+	0x04, 0xBE, 0xD5, 0xAF, 0x16, 0xEA, 0x3F, 0x6A,
+	0x4F, 0x62, 0x93, 0x8C, 0x46, 0x31, 0xEB, 0x5A,
+	0xF7, 0xBD, 0xBC, 0xDB, 0xC3, 0x16, 0x67, 0xCB,
+	0x47, 0x7A, 0x1A, 0x8E, 0xC3, 0x38, 0xF9, 0x47,
+	0x41, 0x66, 0x9C, 0x97, 0x63, 0x16, 0xDA, 0x63,
+	0x21, 0x02, 0x15, 0x00, 0xE9, 0x5E, 0x4A, 0x5F,
+	0x73, 0x70, 0x59, 0xDC, 0x60, 0xDF, 0x59, 0x91,
+	0xD4, 0x50, 0x29, 0x40, 0x9E, 0x60, 0xFC, 0x09,
+	0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP160t1_oid_der[] = {
+	0x30, 0x81, 0x98, 0x02, 0x01, 0x01, 0x30, 0x20,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x15, 0x00, 0xE9, 0x5E, 0x4A, 0x5F,
+	0x73, 0x70, 0x59, 0xDC, 0x60, 0xDF, 0xC7, 0xAD,
+	0x95, 0xB3, 0xD8, 0x13, 0x95, 0x15, 0x62, 0x0F,
+	0x30, 0x2C, 0x04, 0x14, 0xE9, 0x5E, 0x4A, 0x5F,
+	0x73, 0x70, 0x59, 0xDC, 0x60, 0xDF, 0xC7, 0xAD,
+	0x95, 0xB3, 0xD8, 0x13, 0x95, 0x15, 0x62, 0x0C,
+	0x04, 0x14, 0x7A, 0x55, 0x6B, 0x6D, 0xAE, 0x53,
+	0x5B, 0x7B, 0x51, 0xED, 0x2C, 0x4D, 0x7D, 0xAA,
+	0x7A, 0x0B, 0x5C, 0x55, 0xF3, 0x80, 0x04, 0x29,
+	0x04, 0xB1, 0x99, 0xB1, 0x3B, 0x9B, 0x34, 0xEF,
+	0xC1, 0x39, 0x7E, 0x64, 0xBA, 0xEB, 0x05, 0xAC,
+	0xC2, 0x65, 0xFF, 0x23, 0x78, 0xAD, 0xD6, 0x71,
+	0x8B, 0x7C, 0x7C, 0x19, 0x61, 0xF0, 0x99, 0x1B,
+	0x84, 0x24, 0x43, 0x77, 0x21, 0x52, 0xC9, 0xE0,
+	0xAD, 0x02, 0x15, 0x00, 0xE9, 0x5E, 0x4A, 0x5F,
+	0x73, 0x70, 0x59, 0xDC, 0x60, 0xDF, 0x59, 0x91,
+	0xD4, 0x50, 0x29, 0x40, 0x9E, 0x60, 0xFC, 0x09,
+	0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP192r1_oid_der[] = {
+	0x30, 0x81, 0xB0, 0x02, 0x01, 0x01, 0x30, 0x24,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x19, 0x00, 0xC3, 0x02, 0xF4, 0x1D,
+	0x93, 0x2A, 0x36, 0xCD, 0xA7, 0xA3, 0x46, 0x30,
+	0x93, 0xD1, 0x8D, 0xB7, 0x8F, 0xCE, 0x47, 0x6D,
+	0xE1, 0xA8, 0x62, 0x97, 0x30, 0x34, 0x04, 0x18,
+	0x6A, 0x91, 0x17, 0x40, 0x76, 0xB1, 0xE0, 0xE1,
+	0x9C, 0x39, 0xC0, 0x31, 0xFE, 0x86, 0x85, 0xC1,
+	0xCA, 0xE0, 0x40, 0xE5, 0xC6, 0x9A, 0x28, 0xEF,
+	0x04, 0x18, 0x46, 0x9A, 0x28, 0xEF, 0x7C, 0x28,
+	0xCC, 0xA3, 0xDC, 0x72, 0x1D, 0x04, 0x4F, 0x44,
+	0x96, 0xBC, 0xCA, 0x7E, 0xF4, 0x14, 0x6F, 0xBF,
+	0x25, 0xC9, 0x04, 0x31, 0x04, 0xC0, 0xA0, 0x64,
+	0x7E, 0xAA, 0xB6, 0xA4, 0x87, 0x53, 0xB0, 0x33,
+	0xC5, 0x6C, 0xB0, 0xF0, 0x90, 0x0A, 0x2F, 0x5C,
+	0x48, 0x53, 0x37, 0x5F, 0xD6, 0x14, 0xB6, 0x90,
+	0x86, 0x6A, 0xBD, 0x5B, 0xB8, 0x8B, 0x5F, 0x48,
+	0x28, 0xC1, 0x49, 0x00, 0x02, 0xE6, 0x77, 0x3F,
+	0xA2, 0xFA, 0x29, 0x9B, 0x8F, 0x02, 0x19, 0x00,
+	0xC3, 0x02, 0xF4, 0x1D, 0x93, 0x2A, 0x36, 0xCD,
+	0xA7, 0xA3, 0x46, 0x2F, 0x9E, 0x9E, 0x91, 0x6B,
+	0x5B, 0xE8, 0xF1, 0x02, 0x9A, 0xC4, 0xAC, 0xC1,
+	0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP192t1_oid_der[] = {
+	0x30, 0x81, 0xB0, 0x02, 0x01, 0x01, 0x30, 0x24,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x19, 0x00, 0xC3, 0x02, 0xF4, 0x1D,
+	0x93, 0x2A, 0x36, 0xCD, 0xA7, 0xA3, 0x46, 0x30,
+	0x93, 0xD1, 0x8D, 0xB7, 0x8F, 0xCE, 0x47, 0x6D,
+	0xE1, 0xA8, 0x62, 0x97, 0x30, 0x34, 0x04, 0x18,
+	0xC3, 0x02, 0xF4, 0x1D, 0x93, 0x2A, 0x36, 0xCD,
+	0xA7, 0xA3, 0x46, 0x30, 0x93, 0xD1, 0x8D, 0xB7,
+	0x8F, 0xCE, 0x47, 0x6D, 0xE1, 0xA8, 0x62, 0x94,
+	0x04, 0x18, 0x13, 0xD5, 0x6F, 0xFA, 0xEC, 0x78,
+	0x68, 0x1E, 0x68, 0xF9, 0xDE, 0xB4, 0x3B, 0x35,
+	0xBE, 0xC2, 0xFB, 0x68, 0x54, 0x2E, 0x27, 0x89,
+	0x7B, 0x79, 0x04, 0x31, 0x04, 0x3A, 0xE9, 0xE5,
+	0x8C, 0x82, 0xF6, 0x3C, 0x30, 0x28, 0x2E, 0x1F,
+	0xE7, 0xBB, 0xF4, 0x3F, 0xA7, 0x2C, 0x44, 0x6A,
+	0xF6, 0xF4, 0x61, 0x81, 0x29, 0x09, 0x7E, 0x2C,
+	0x56, 0x67, 0xC2, 0x22, 0x3A, 0x90, 0x2A, 0xB5,
+	0xCA, 0x44, 0x9D, 0x00, 0x84, 0xB7, 0xE5, 0xB3,
+	0xDE, 0x7C, 0xCC, 0x01, 0xC9, 0x02, 0x19, 0x00,
+	0xC3, 0x02, 0xF4, 0x1D, 0x93, 0x2A, 0x36, 0xCD,
+	0xA7, 0xA3, 0x46, 0x2F, 0x9E, 0x9E, 0x91, 0x6B,
+	0x5B, 0xE8, 0xF1, 0x02, 0x9A, 0xC4, 0xAC, 0xC1,
+	0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP224r1_oid_der[] = {
+	0x30, 0x81, 0xC8, 0x02, 0x01, 0x01, 0x30, 0x28,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x1D, 0x00, 0xD7, 0xC1, 0x34, 0xAA,
+	0x26, 0x43, 0x66, 0x86, 0x2A, 0x18, 0x30, 0x25,
+	0x75, 0xD1, 0xD7, 0x87, 0xB0, 0x9F, 0x07, 0x57,
+	0x97, 0xDA, 0x89, 0xF5, 0x7E, 0xC8, 0xC0, 0xFF,
+	0x30, 0x3C, 0x04, 0x1C, 0x68, 0xA5, 0xE6, 0x2C,
+	0xA9, 0xCE, 0x6C, 0x1C, 0x29, 0x98, 0x03, 0xA6,
+	0xC1, 0x53, 0x0B, 0x51, 0x4E, 0x18, 0x2A, 0xD8,
+	0xB0, 0x04, 0x2A, 0x59, 0xCA, 0xD2, 0x9F, 0x43,
+	0x04, 0x1C, 0x25, 0x80, 0xF6, 0x3C, 0xCF, 0xE4,
+	0x41, 0x38, 0x87, 0x07, 0x13, 0xB1, 0xA9, 0x23,
+	0x69, 0xE3, 0x3E, 0x21, 0x35, 0xD2, 0x66, 0xDB,
+	0xB3, 0x72, 0x38, 0x6C, 0x40, 0x0B, 0x04, 0x39,
+	0x04, 0x0D, 0x90, 0x29, 0xAD, 0x2C, 0x7E, 0x5C,
+	0xF4, 0x34, 0x08, 0x23, 0xB2, 0xA8, 0x7D, 0xC6,
+	0x8C, 0x9E, 0x4C, 0xE3, 0x17, 0x4C, 0x1E, 0x6E,
+	0xFD, 0xEE, 0x12, 0xC0, 0x7D, 0x58, 0xAA, 0x56,
+	0xF7, 0x72, 0xC0, 0x72, 0x6F, 0x24, 0xC6, 0xB8,
+	0x9E, 0x4E, 0xCD, 0xAC, 0x24, 0x35, 0x4B, 0x9E,
+	0x99, 0xCA, 0xA3, 0xF6, 0xD3, 0x76, 0x14, 0x02,
+	0xCD, 0x02, 0x1D, 0x00, 0xD7, 0xC1, 0x34, 0xAA,
+	0x26, 0x43, 0x66, 0x86, 0x2A, 0x18, 0x30, 0x25,
+	0x75, 0xD0, 0xFB, 0x98, 0xD1, 0x16, 0xBC, 0x4B,
+	0x6D, 0xDE, 0xBC, 0xA3, 0xA5, 0xA7, 0x93, 0x9F,
+	0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP224t1_oid_der[] = {
+	0x30, 0x81, 0xC8, 0x02, 0x01, 0x01, 0x30, 0x28,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x1D, 0x00, 0xD7, 0xC1, 0x34, 0xAA,
+	0x26, 0x43, 0x66, 0x86, 0x2A, 0x18, 0x30, 0x25,
+	0x75, 0xD1, 0xD7, 0x87, 0xB0, 0x9F, 0x07, 0x57,
+	0x97, 0xDA, 0x89, 0xF5, 0x7E, 0xC8, 0xC0, 0xFF,
+	0x30, 0x3C, 0x04, 0x1C, 0xD7, 0xC1, 0x34, 0xAA,
+	0x26, 0x43, 0x66, 0x86, 0x2A, 0x18, 0x30, 0x25,
+	0x75, 0xD1, 0xD7, 0x87, 0xB0, 0x9F, 0x07, 0x57,
+	0x97, 0xDA, 0x89, 0xF5, 0x7E, 0xC8, 0xC0, 0xFC,
+	0x04, 0x1C, 0x4B, 0x33, 0x7D, 0x93, 0x41, 0x04,
+	0xCD, 0x7B, 0xEF, 0x27, 0x1B, 0xF6, 0x0C, 0xED,
+	0x1E, 0xD2, 0x0D, 0xA1, 0x4C, 0x08, 0xB3, 0xBB,
+	0x64, 0xF1, 0x8A, 0x60, 0x88, 0x8D, 0x04, 0x39,
+	0x04, 0x6A, 0xB1, 0xE3, 0x44, 0xCE, 0x25, 0xFF,
+	0x38, 0x96, 0x42, 0x4E, 0x7F, 0xFE, 0x14, 0x76,
+	0x2E, 0xCB, 0x49, 0xF8, 0x92, 0x8A, 0xC0, 0xC7,
+	0x60, 0x29, 0xB4, 0xD5, 0x80, 0x03, 0x74, 0xE9,
+	0xF5, 0x14, 0x3E, 0x56, 0x8C, 0xD2, 0x3F, 0x3F,
+	0x4D, 0x7C, 0x0D, 0x4B, 0x1E, 0x41, 0xC8, 0xCC,
+	0x0D, 0x1C, 0x6A, 0xBD, 0x5F, 0x1A, 0x46, 0xDB,
+	0x4C, 0x02, 0x1D, 0x00, 0xD7, 0xC1, 0x34, 0xAA,
+	0x26, 0x43, 0x66, 0x86, 0x2A, 0x18, 0x30, 0x25,
+	0x75, 0xD0, 0xFB, 0x98, 0xD1, 0x16, 0xBC, 0x4B,
+	0x6D, 0xDE, 0xBC, 0xA3, 0xA5, 0xA7, 0x93, 0x9F,
+	0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP256r1_oid_der[] = {
+	0x30, 0x81, 0xE0, 0x02, 0x01, 0x01, 0x30, 0x2C,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x21, 0x00, 0xA9, 0xFB, 0x57, 0xDB,
+	0xA1, 0xEE, 0xA9, 0xBC, 0x3E, 0x66, 0x0A, 0x90,
+	0x9D, 0x83, 0x8D, 0x72, 0x6E, 0x3B, 0xF6, 0x23,
+	0xD5, 0x26, 0x20, 0x28, 0x20, 0x13, 0x48, 0x1D,
+	0x1F, 0x6E, 0x53, 0x77, 0x30, 0x44, 0x04, 0x20,
+	0x7D, 0x5A, 0x09, 0x75, 0xFC, 0x2C, 0x30, 0x57,
+	0xEE, 0xF6, 0x75, 0x30, 0x41, 0x7A, 0xFF, 0xE7,
+	0xFB, 0x80, 0x55, 0xC1, 0x26, 0xDC, 0x5C, 0x6C,
+	0xE9, 0x4A, 0x4B, 0x44, 0xF3, 0x30, 0xB5, 0xD9,
+	0x04, 0x20, 0x26, 0xDC, 0x5C, 0x6C, 0xE9, 0x4A,
+	0x4B, 0x44, 0xF3, 0x30, 0xB5, 0xD9, 0xBB, 0xD7,
+	0x7C, 0xBF, 0x95, 0x84, 0x16, 0x29, 0x5C, 0xF7,
+	0xE1, 0xCE, 0x6B, 0xCC, 0xDC, 0x18, 0xFF, 0x8C,
+	0x07, 0xB6, 0x04, 0x41, 0x04, 0x8B, 0xD2, 0xAE,
+	0xB9, 0xCB, 0x7E, 0x57, 0xCB, 0x2C, 0x4B, 0x48,
+	0x2F, 0xFC, 0x81, 0xB7, 0xAF, 0xB9, 0xDE, 0x27,
+	0xE1, 0xE3, 0xBD, 0x23, 0xC2, 0x3A, 0x44, 0x53,
+	0xBD, 0x9A, 0xCE, 0x32, 0x62, 0x54, 0x7E, 0xF8,
+	0x35, 0xC3, 0xDA, 0xC4, 0xFD, 0x97, 0xF8, 0x46,
+	0x1A, 0x14, 0x61, 0x1D, 0xC9, 0xC2, 0x77, 0x45,
+	0x13, 0x2D, 0xED, 0x8E, 0x54, 0x5C, 0x1D, 0x54,
+	0xC7, 0x2F, 0x04, 0x69, 0x97, 0x02, 0x21, 0x00,
+	0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+	0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x71,
+	0x8C, 0x39, 0x7A, 0xA3, 0xB5, 0x61, 0xA6, 0xF7,
+	0x90, 0x1E, 0x0E, 0x82, 0x97, 0x48, 0x56, 0xA7,
+	0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP256t1_oid_der[] = {
+	0x30, 0x81, 0xE0, 0x02, 0x01, 0x01, 0x30, 0x2C,
+	0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01,
+	0x01, 0x02, 0x21, 0x00, 0xA9, 0xFB, 0x57, 0xDB,
+	0xA1, 0xEE, 0xA9, 0xBC, 0x3E, 0x66, 0x0A, 0x90,
+	0x9D, 0x83, 0x8D, 0x72, 0x6E, 0x3B, 0xF6, 0x23,
+	0xD5, 0x26, 0x20, 0x28, 0x20, 0x13, 0x48, 0x1D,
+	0x1F, 0x6E, 0x53, 0x77, 0x30, 0x44, 0x04, 0x20,
+	0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+	0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x72,
+	0x6E, 0x3B, 0xF6, 0x23, 0xD5, 0x26, 0x20, 0x28,
+	0x20, 0x13, 0x48, 0x1D, 0x1F, 0x6E, 0x53, 0x74,
+	0x04, 0x20, 0x66, 0x2C, 0x61, 0xC4, 0x30, 0xD8,
+	0x4E, 0xA4, 0xFE, 0x66, 0xA7, 0x73, 0x3D, 0x0B,
+	0x76, 0xB7, 0xBF, 0x93, 0xEB, 0xC4, 0xAF, 0x2F,
+	0x49, 0x25, 0x6A, 0xE5, 0x81, 0x01, 0xFE, 0xE9,
+	0x2B, 0x04, 0x04, 0x41, 0x04, 0xA3, 0xE8, 0xEB,
+	0x3C, 0xC1, 0xCF, 0xE7, 0xB7, 0x73, 0x22, 0x13,
+	0xB2, 0x3A, 0x65, 0x61, 0x49, 0xAF, 0xA1, 0x42,
+	0xC4, 0x7A, 0xAF, 0xBC, 0x2B, 0x79, 0xA1, 0x91,
+	0x56, 0x2E, 0x13, 0x05, 0xF4, 0x2D, 0x99, 0x6C,
+	0x82, 0x34, 0x39, 0xC5, 0x6D, 0x7F, 0x7B, 0x22,
+	0xE1, 0x46, 0x44, 0x41, 0x7E, 0x69, 0xBC, 0xB6,
+	0xDE, 0x39, 0xD0, 0x27, 0x00, 0x1D, 0xAB, 0xE8,
+	0xF3, 0x5B, 0x25, 0xC9, 0xBE, 0x02, 0x21, 0x00,
+	0xA9, 0xFB, 0x57, 0xDB, 0xA1, 0xEE, 0xA9, 0xBC,
+	0x3E, 0x66, 0x0A, 0x90, 0x9D, 0x83, 0x8D, 0x71,
+	0x8C, 0x39, 0x7A, 0xA3, 0xB5, 0x61, 0xA6, 0xF7,
+	0x90, 0x1E, 0x0E, 0x82, 0x97, 0x48, 0x56, 0xA7,
+	0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP320r1_oid_der[] = {
+	0x30, 0x82, 0x01, 0x10, 0x02, 0x01, 0x01, 0x30,
+	0x34, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+	0x01, 0x01, 0x02, 0x29, 0x00, 0xD3, 0x5E, 0x47,
+	0x20, 0x36, 0xBC, 0x4F, 0xB7, 0xE1, 0x3C, 0x78,
+	0x5E, 0xD2, 0x01, 0xE0, 0x65, 0xF9, 0x8F, 0xCF,
+	0xA6, 0xF6, 0xF4, 0x0D, 0xEF, 0x4F, 0x92, 0xB9,
+	0xEC, 0x78, 0x93, 0xEC, 0x28, 0xFC, 0xD4, 0x12,
+	0xB1, 0xF1, 0xB3, 0x2E, 0x27, 0x30, 0x54, 0x04,
+	0x28, 0x3E, 0xE3, 0x0B, 0x56, 0x8F, 0xBA, 0xB0,
+	0xF8, 0x83, 0xCC, 0xEB, 0xD4, 0x6D, 0x3F, 0x3B,
+	0xB8, 0xA2, 0xA7, 0x35, 0x13, 0xF5, 0xEB, 0x79,
+	0xDA, 0x66, 0x19, 0x0E, 0xB0, 0x85, 0xFF, 0xA9,
+	0xF4, 0x92, 0xF3, 0x75, 0xA9, 0x7D, 0x86, 0x0E,
+	0xB4, 0x04, 0x28, 0x52, 0x08, 0x83, 0x94, 0x9D,
+	0xFD, 0xBC, 0x42, 0xD3, 0xAD, 0x19, 0x86, 0x40,
+	0x68, 0x8A, 0x6F, 0xE1, 0x3F, 0x41, 0x34, 0x95,
+	0x54, 0xB4, 0x9A, 0xCC, 0x31, 0xDC, 0xCD, 0x88,
+	0x45, 0x39, 0x81, 0x6F, 0x5E, 0xB4, 0xAC, 0x8F,
+	0xB1, 0xF1, 0xA6, 0x04, 0x51, 0x04, 0x43, 0xBD,
+	0x7E, 0x9A, 0xFB, 0x53, 0xD8, 0xB8, 0x52, 0x89,
+	0xBC, 0xC4, 0x8E, 0xE5, 0xBF, 0xE6, 0xF2, 0x01,
+	0x37, 0xD1, 0x0A, 0x08, 0x7E, 0xB6, 0xE7, 0x87,
+	0x1E, 0x2A, 0x10, 0xA5, 0x99, 0xC7, 0x10, 0xAF,
+	0x8D, 0x0D, 0x39, 0xE2, 0x06, 0x11, 0x14, 0xFD,
+	0xD0, 0x55, 0x45, 0xEC, 0x1C, 0xC8, 0xAB, 0x40,
+	0x93, 0x24, 0x7F, 0x77, 0x27, 0x5E, 0x07, 0x43,
+	0xFF, 0xED, 0x11, 0x71, 0x82, 0xEA, 0xA9, 0xC7,
+	0x78, 0x77, 0xAA, 0xAC, 0x6A, 0xC7, 0xD3, 0x52,
+	0x45, 0xD1, 0x69, 0x2E, 0x8E, 0xE1, 0x02, 0x29,
+	0x00, 0xD3, 0x5E, 0x47, 0x20, 0x36, 0xBC, 0x4F,
+	0xB7, 0xE1, 0x3C, 0x78, 0x5E, 0xD2, 0x01, 0xE0,
+	0x65, 0xF9, 0x8F, 0xCF, 0xA5, 0xB6, 0x8F, 0x12,
+	0xA3, 0x2D, 0x48, 0x2E, 0xC7, 0xEE, 0x86, 0x58,
+	0xE9, 0x86, 0x91, 0x55, 0x5B, 0x44, 0xC5, 0x93,
+	0x11, 0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP320t1_oid_der[] = {
+	0x30, 0x82, 0x01, 0x10, 0x02, 0x01, 0x01, 0x30,
+	0x34, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+	0x01, 0x01, 0x02, 0x29, 0x00, 0xD3, 0x5E, 0x47,
+	0x20, 0x36, 0xBC, 0x4F, 0xB7, 0xE1, 0x3C, 0x78,
+	0x5E, 0xD2, 0x01, 0xE0, 0x65, 0xF9, 0x8F, 0xCF,
+	0xA6, 0xF6, 0xF4, 0x0D, 0xEF, 0x4F, 0x92, 0xB9,
+	0xEC, 0x78, 0x93, 0xEC, 0x28, 0xFC, 0xD4, 0x12,
+	0xB1, 0xF1, 0xB3, 0x2E, 0x27, 0x30, 0x54, 0x04,
+	0x28, 0xD3, 0x5E, 0x47, 0x20, 0x36, 0xBC, 0x4F,
+	0xB7, 0xE1, 0x3C, 0x78, 0x5E, 0xD2, 0x01, 0xE0,
+	0x65, 0xF9, 0x8F, 0xCF, 0xA6, 0xF6, 0xF4, 0x0D,
+	0xEF, 0x4F, 0x92, 0xB9, 0xEC, 0x78, 0x93, 0xEC,
+	0x28, 0xFC, 0xD4, 0x12, 0xB1, 0xF1, 0xB3, 0x2E,
+	0x24, 0x04, 0x28, 0xA7, 0xF5, 0x61, 0xE0, 0x38,
+	0xEB, 0x1E, 0xD5, 0x60, 0xB3, 0xD1, 0x47, 0xDB,
+	0x78, 0x20, 0x13, 0x06, 0x4C, 0x19, 0xF2, 0x7E,
+	0xD2, 0x7C, 0x67, 0x80, 0xAA, 0xF7, 0x7F, 0xB8,
+	0xA5, 0x47, 0xCE, 0xB5, 0xB4, 0xFE, 0xF4, 0x22,
+	0x34, 0x03, 0x53, 0x04, 0x51, 0x04, 0x92, 0x5B,
+	0xE9, 0xFB, 0x01, 0xAF, 0xC6, 0xFB, 0x4D, 0x3E,
+	0x7D, 0x49, 0x90, 0x01, 0x0F, 0x81, 0x34, 0x08,
+	0xAB, 0x10, 0x6C, 0x4F, 0x09, 0xCB, 0x7E, 0xE0,
+	0x78, 0x68, 0xCC, 0x13, 0x6F, 0xFF, 0x33, 0x57,
+	0xF6, 0x24, 0xA2, 0x1B, 0xED, 0x52, 0x63, 0xBA,
+	0x3A, 0x7A, 0x27, 0x48, 0x3E, 0xBF, 0x66, 0x71,
+	0xDB, 0xEF, 0x7A, 0xBB, 0x30, 0xEB, 0xEE, 0x08,
+	0x4E, 0x58, 0xA0, 0xB0, 0x77, 0xAD, 0x42, 0xA5,
+	0xA0, 0x98, 0x9D, 0x1E, 0xE7, 0x1B, 0x1B, 0x9B,
+	0xC0, 0x45, 0x5F, 0xB0, 0xD2, 0xC3, 0x02, 0x29,
+	0x00, 0xD3, 0x5E, 0x47, 0x20, 0x36, 0xBC, 0x4F,
+	0xB7, 0xE1, 0x3C, 0x78, 0x5E, 0xD2, 0x01, 0xE0,
+	0x65, 0xF9, 0x8F, 0xCF, 0xA5, 0xB6, 0x8F, 0x12,
+	0xA3, 0x2D, 0x48, 0x2E, 0xC7, 0xEE, 0x86, 0x58,
+	0xE9, 0x86, 0x91, 0x55, 0x5B, 0x44, 0xC5, 0x93,
+	0x11, 0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP384r1_oid_der[] = {
+	0x30, 0x82, 0x01, 0x40, 0x02, 0x01, 0x01, 0x30,
+	0x3C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+	0x01, 0x01, 0x02, 0x31, 0x00, 0x8C, 0xB9, 0x1E,
+	0x82, 0xA3, 0x38, 0x6D, 0x28, 0x0F, 0x5D, 0x6F,
+	0x7E, 0x50, 0xE6, 0x41, 0xDF, 0x15, 0x2F, 0x71,
+	0x09, 0xED, 0x54, 0x56, 0xB4, 0x12, 0xB1, 0xDA,
+	0x19, 0x7F, 0xB7, 0x11, 0x23, 0xAC, 0xD3, 0xA7,
+	0x29, 0x90, 0x1D, 0x1A, 0x71, 0x87, 0x47, 0x00,
+	0x13, 0x31, 0x07, 0xEC, 0x53, 0x30, 0x64, 0x04,
+	0x30, 0x7B, 0xC3, 0x82, 0xC6, 0x3D, 0x8C, 0x15,
+	0x0C, 0x3C, 0x72, 0x08, 0x0A, 0xCE, 0x05, 0xAF,
+	0xA0, 0xC2, 0xBE, 0xA2, 0x8E, 0x4F, 0xB2, 0x27,
+	0x87, 0x13, 0x91, 0x65, 0xEF, 0xBA, 0x91, 0xF9,
+	0x0F, 0x8A, 0xA5, 0x81, 0x4A, 0x50, 0x3A, 0xD4,
+	0xEB, 0x04, 0xA8, 0xC7, 0xDD, 0x22, 0xCE, 0x28,
+	0x26, 0x04, 0x30, 0x04, 0xA8, 0xC7, 0xDD, 0x22,
+	0xCE, 0x28, 0x26, 0x8B, 0x39, 0xB5, 0x54, 0x16,
+	0xF0, 0x44, 0x7C, 0x2F, 0xB7, 0x7D, 0xE1, 0x07,
+	0xDC, 0xD2, 0xA6, 0x2E, 0x88, 0x0E, 0xA5, 0x3E,
+	0xEB, 0x62, 0xD5, 0x7C, 0xB4, 0x39, 0x02, 0x95,
+	0xDB, 0xC9, 0x94, 0x3A, 0xB7, 0x86, 0x96, 0xFA,
+	0x50, 0x4C, 0x11, 0x04, 0x61, 0x04, 0x1D, 0x1C,
+	0x64, 0xF0, 0x68, 0xCF, 0x45, 0xFF, 0xA2, 0xA6,
+	0x3A, 0x81, 0xB7, 0xC1, 0x3F, 0x6B, 0x88, 0x47,
+	0xA3, 0xE7, 0x7E, 0xF1, 0x4F, 0xE3, 0xDB, 0x7F,
+	0xCA, 0xFE, 0x0C, 0xBD, 0x10, 0xE8, 0xE8, 0x26,
+	0xE0, 0x34, 0x36, 0xD6, 0x46, 0xAA, 0xEF, 0x87,
+	0xB2, 0xE2, 0x47, 0xD4, 0xAF, 0x1E, 0x8A, 0xBE,
+	0x1D, 0x75, 0x20, 0xF9, 0xC2, 0xA4, 0x5C, 0xB1,
+	0xEB, 0x8E, 0x95, 0xCF, 0xD5, 0x52, 0x62, 0xB7,
+	0x0B, 0x29, 0xFE, 0xEC, 0x58, 0x64, 0xE1, 0x9C,
+	0x05, 0x4F, 0xF9, 0x91, 0x29, 0x28, 0x0E, 0x46,
+	0x46, 0x21, 0x77, 0x91, 0x81, 0x11, 0x42, 0x82,
+	0x03, 0x41, 0x26, 0x3C, 0x53, 0x15, 0x02, 0x31,
+	0x00, 0x8C, 0xB9, 0x1E, 0x82, 0xA3, 0x38, 0x6D,
+	0x28, 0x0F, 0x5D, 0x6F, 0x7E, 0x50, 0xE6, 0x41,
+	0xDF, 0x15, 0x2F, 0x71, 0x09, 0xED, 0x54, 0x56,
+	0xB3, 0x1F, 0x16, 0x6E, 0x6C, 0xAC, 0x04, 0x25,
+	0xA7, 0xCF, 0x3A, 0xB6, 0xAF, 0x6B, 0x7F, 0xC3,
+	0x10, 0x3B, 0x88, 0x32, 0x02, 0xE9, 0x04, 0x65,
+	0x65, 0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP384t1_oid_der[] = {
+	0x30, 0x82, 0x01, 0x40, 0x02, 0x01, 0x01, 0x30,
+	0x3C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+	0x01, 0x01, 0x02, 0x31, 0x00, 0x8C, 0xB9, 0x1E,
+	0x82, 0xA3, 0x38, 0x6D, 0x28, 0x0F, 0x5D, 0x6F,
+	0x7E, 0x50, 0xE6, 0x41, 0xDF, 0x15, 0x2F, 0x71,
+	0x09, 0xED, 0x54, 0x56, 0xB4, 0x12, 0xB1, 0xDA,
+	0x19, 0x7F, 0xB7, 0x11, 0x23, 0xAC, 0xD3, 0xA7,
+	0x29, 0x90, 0x1D, 0x1A, 0x71, 0x87, 0x47, 0x00,
+	0x13, 0x31, 0x07, 0xEC, 0x53, 0x30, 0x64, 0x04,
+	0x30, 0x8C, 0xB9, 0x1E, 0x82, 0xA3, 0x38, 0x6D,
+	0x28, 0x0F, 0x5D, 0x6F, 0x7E, 0x50, 0xE6, 0x41,
+	0xDF, 0x15, 0x2F, 0x71, 0x09, 0xED, 0x54, 0x56,
+	0xB4, 0x12, 0xB1, 0xDA, 0x19, 0x7F, 0xB7, 0x11,
+	0x23, 0xAC, 0xD3, 0xA7, 0x29, 0x90, 0x1D, 0x1A,
+	0x71, 0x87, 0x47, 0x00, 0x13, 0x31, 0x07, 0xEC,
+	0x50, 0x04, 0x30, 0x7F, 0x51, 0x9E, 0xAD, 0xA7,
+	0xBD, 0xA8, 0x1B, 0xD8, 0x26, 0xDB, 0xA6, 0x47,
+	0x91, 0x0F, 0x8C, 0x4B, 0x93, 0x46, 0xED, 0x8C,
+	0xCD, 0xC6, 0x4E, 0x4B, 0x1A, 0xBD, 0x11, 0x75,
+	0x6D, 0xCE, 0x1D, 0x20, 0x74, 0xAA, 0x26, 0x3B,
+	0x88, 0x80, 0x5C, 0xED, 0x70, 0x35, 0x5A, 0x33,
+	0xB4, 0x71, 0xEE, 0x04, 0x61, 0x04, 0x18, 0xDE,
+	0x98, 0xB0, 0x2D, 0xB9, 0xA3, 0x06, 0xF2, 0xAF,
+	0xCD, 0x72, 0x35, 0xF7, 0x2A, 0x81, 0x9B, 0x80,
+	0xAB, 0x12, 0xEB, 0xD6, 0x53, 0x17, 0x24, 0x76,
+	0xFE, 0xCD, 0x46, 0x2A, 0xAB, 0xFF, 0xC4, 0xFF,
+	0x19, 0x1B, 0x94, 0x6A, 0x5F, 0x54, 0xD8, 0xD0,
+	0xAA, 0x2F, 0x41, 0x88, 0x08, 0xCC, 0x25, 0xAB,
+	0x05, 0x69, 0x62, 0xD3, 0x06, 0x51, 0xA1, 0x14,
+	0xAF, 0xD2, 0x75, 0x5A, 0xD3, 0x36, 0x74, 0x7F,
+	0x93, 0x47, 0x5B, 0x7A, 0x1F, 0xCA, 0x3B, 0x88,
+	0xF2, 0xB6, 0xA2, 0x08, 0xCC, 0xFE, 0x46, 0x94,
+	0x08, 0x58, 0x4D, 0xC2, 0xB2, 0x91, 0x26, 0x75,
+	0xBF, 0x5B, 0x9E, 0x58, 0x29, 0x28, 0x02, 0x31,
+	0x00, 0x8C, 0xB9, 0x1E, 0x82, 0xA3, 0x38, 0x6D,
+	0x28, 0x0F, 0x5D, 0x6F, 0x7E, 0x50, 0xE6, 0x41,
+	0xDF, 0x15, 0x2F, 0x71, 0x09, 0xED, 0x54, 0x56,
+	0xB3, 0x1F, 0x16, 0x6E, 0x6C, 0xAC, 0x04, 0x25,
+	0xA7, 0xCF, 0x3A, 0xB6, 0xAF, 0x6B, 0x7F, 0xC3,
+	0x10, 0x3B, 0x88, 0x32, 0x02, 0xE9, 0x04, 0x65,
+	0x65, 0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP512r1_oid_der[] = {
+	0x30, 0x82, 0x01, 0xA2, 0x02, 0x01, 0x01, 0x30,
+	0x4C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+	0x01, 0x01, 0x02, 0x41, 0x00, 0xAA, 0xDD, 0x9D,
+	0xB8, 0xDB, 0xE9, 0xC4, 0x8B, 0x3F, 0xD4, 0xE6,
+	0xAE, 0x33, 0xC9, 0xFC, 0x07, 0xCB, 0x30, 0x8D,
+	0xB3, 0xB3, 0xC9, 0xD2, 0x0E, 0xD6, 0x63, 0x9C,
+	0xCA, 0x70, 0x33, 0x08, 0x71, 0x7D, 0x4D, 0x9B,
+	0x00, 0x9B, 0xC6, 0x68, 0x42, 0xAE, 0xCD, 0xA1,
+	0x2A, 0xE6, 0xA3, 0x80, 0xE6, 0x28, 0x81, 0xFF,
+	0x2F, 0x2D, 0x82, 0xC6, 0x85, 0x28, 0xAA, 0x60,
+	0x56, 0x58, 0x3A, 0x48, 0xF3, 0x30, 0x81, 0x84,
+	0x04, 0x40, 0x78, 0x30, 0xA3, 0x31, 0x8B, 0x60,
+	0x3B, 0x89, 0xE2, 0x32, 0x71, 0x45, 0xAC, 0x23,
+	0x4C, 0xC5, 0x94, 0xCB, 0xDD, 0x8D, 0x3D, 0xF9,
+	0x16, 0x10, 0xA8, 0x34, 0x41, 0xCA, 0xEA, 0x98,
+	0x63, 0xBC, 0x2D, 0xED, 0x5D, 0x5A, 0xA8, 0x25,
+	0x3A, 0xA1, 0x0A, 0x2E, 0xF1, 0xC9, 0x8B, 0x9A,
+	0xC8, 0xB5, 0x7F, 0x11, 0x17, 0xA7, 0x2B, 0xF2,
+	0xC7, 0xB9, 0xE7, 0xC1, 0xAC, 0x4D, 0x77, 0xFC,
+	0x94, 0xCA, 0x04, 0x40, 0x3D, 0xF9, 0x16, 0x10,
+	0xA8, 0x34, 0x41, 0xCA, 0xEA, 0x98, 0x63, 0xBC,
+	0x2D, 0xED, 0x5D, 0x5A, 0xA8, 0x25, 0x3A, 0xA1,
+	0x0A, 0x2E, 0xF1, 0xC9, 0x8B, 0x9A, 0xC8, 0xB5,
+	0x7F, 0x11, 0x17, 0xA7, 0x2B, 0xF2, 0xC7, 0xB9,
+	0xE7, 0xC1, 0xAC, 0x4D, 0x77, 0xFC, 0x94, 0xCA,
+	0xDC, 0x08, 0x3E, 0x67, 0x98, 0x40, 0x50, 0xB7,
+	0x5E, 0xBA, 0xE5, 0xDD, 0x28, 0x09, 0xBD, 0x63,
+	0x80, 0x16, 0xF7, 0x23, 0x04, 0x81, 0x81, 0x04,
+	0x81, 0xAE, 0xE4, 0xBD, 0xD8, 0x2E, 0xD9, 0x64,
+	0x5A, 0x21, 0x32, 0x2E, 0x9C, 0x4C, 0x6A, 0x93,
+	0x85, 0xED, 0x9F, 0x70, 0xB5, 0xD9, 0x16, 0xC1,
+	0xB4, 0x3B, 0x62, 0xEE, 0xF4, 0xD0, 0x09, 0x8E,
+	0xFF, 0x3B, 0x1F, 0x78, 0xE2, 0xD0, 0xD4, 0x8D,
+	0x50, 0xD1, 0x68, 0x7B, 0x93, 0xB9, 0x7D, 0x5F,
+	0x7C, 0x6D, 0x50, 0x47, 0x40, 0x6A, 0x5E, 0x68,
+	0x8B, 0x35, 0x22, 0x09, 0xBC, 0xB9, 0xF8, 0x22,
+	0x7D, 0xDE, 0x38, 0x5D, 0x56, 0x63, 0x32, 0xEC,
+	0xC0, 0xEA, 0xBF, 0xA9, 0xCF, 0x78, 0x22, 0xFD,
+	0xF2, 0x09, 0xF7, 0x00, 0x24, 0xA5, 0x7B, 0x1A,
+	0xA0, 0x00, 0xC5, 0x5B, 0x88, 0x1F, 0x81, 0x11,
+	0xB2, 0xDC, 0xDE, 0x49, 0x4A, 0x5F, 0x48, 0x5E,
+	0x5B, 0xCA, 0x4B, 0xD8, 0x8A, 0x27, 0x63, 0xAE,
+	0xD1, 0xCA, 0x2B, 0x2F, 0xA8, 0xF0, 0x54, 0x06,
+	0x78, 0xCD, 0x1E, 0x0F, 0x3A, 0xD8, 0x08, 0x92,
+	0x02, 0x41, 0x00, 0xAA, 0xDD, 0x9D, 0xB8, 0xDB,
+	0xE9, 0xC4, 0x8B, 0x3F, 0xD4, 0xE6, 0xAE, 0x33,
+	0xC9, 0xFC, 0x07, 0xCB, 0x30, 0x8D, 0xB3, 0xB3,
+	0xC9, 0xD2, 0x0E, 0xD6, 0x63, 0x9C, 0xCA, 0x70,
+	0x33, 0x08, 0x70, 0x55, 0x3E, 0x5C, 0x41, 0x4C,
+	0xA9, 0x26, 0x19, 0x41, 0x86, 0x61, 0x19, 0x7F,
+	0xAC, 0x10, 0x47, 0x1D, 0xB1, 0xD3, 0x81, 0x08,
+	0x5D, 0xDA, 0xDD, 0xB5, 0x87, 0x96, 0x82, 0x9C,
+	0xA9, 0x00, 0x69, 0x02, 0x01, 0x01,
+};
+static const uint8_t brainpoolP512t1_oid_der[] = {
+	0x30, 0x82, 0x01, 0xA2, 0x02, 0x01, 0x01, 0x30,
+	0x4C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+	0x01, 0x01, 0x02, 0x41, 0x00, 0xAA, 0xDD, 0x9D,
+	0xB8, 0xDB, 0xE9, 0xC4, 0x8B, 0x3F, 0xD4, 0xE6,
+	0xAE, 0x33, 0xC9, 0xFC, 0x07, 0xCB, 0x30, 0x8D,
+	0xB3, 0xB3, 0xC9, 0xD2, 0x0E, 0xD6, 0x63, 0x9C,
+	0xCA, 0x70, 0x33, 0x08, 0x71, 0x7D, 0x4D, 0x9B,
+	0x00, 0x9B, 0xC6, 0x68, 0x42, 0xAE, 0xCD, 0xA1,
+	0x2A, 0xE6, 0xA3, 0x80, 0xE6, 0x28, 0x81, 0xFF,
+	0x2F, 0x2D, 0x82, 0xC6, 0x85, 0x28, 0xAA, 0x60,
+	0x56, 0x58, 0x3A, 0x48, 0xF3, 0x30, 0x81, 0x84,
+	0x04, 0x40, 0xAA, 0xDD, 0x9D, 0xB8, 0xDB, 0xE9,
+	0xC4, 0x8B, 0x3F, 0xD4, 0xE6, 0xAE, 0x33, 0xC9,
+	0xFC, 0x07, 0xCB, 0x30, 0x8D, 0xB3, 0xB3, 0xC9,
+	0xD2, 0x0E, 0xD6, 0x63, 0x9C, 0xCA, 0x70, 0x33,
+	0x08, 0x71, 0x7D, 0x4D, 0x9B, 0x00, 0x9B, 0xC6,
+	0x68, 0x42, 0xAE, 0xCD, 0xA1, 0x2A, 0xE6, 0xA3,
+	0x80, 0xE6, 0x28, 0x81, 0xFF, 0x2F, 0x2D, 0x82,
+	0xC6, 0x85, 0x28, 0xAA, 0x60, 0x56, 0x58, 0x3A,
+	0x48, 0xF0, 0x04, 0x40, 0x7C, 0xBB, 0xBC, 0xF9,
+	0x44, 0x1C, 0xFA, 0xB7, 0x6E, 0x18, 0x90, 0xE4,
+	0x68, 0x84, 0xEA, 0xE3, 0x21, 0xF7, 0x0C, 0x0B,
+	0xCB, 0x49, 0x81, 0x52, 0x78, 0x97, 0x50, 0x4B,
+	0xEC, 0x3E, 0x36, 0xA6, 0x2B, 0xCD, 0xFA, 0x23,
+	0x04, 0x97, 0x65, 0x40, 0xF6, 0x45, 0x00, 0x85,
+	0xF2, 0xDA, 0xE1, 0x45, 0xC2, 0x25, 0x53, 0xB4,
+	0x65, 0x76, 0x36, 0x89, 0x18, 0x0E, 0xA2, 0x57,
+	0x18, 0x67, 0x42, 0x3E, 0x04, 0x81, 0x81, 0x04,
+	0x64, 0x0E, 0xCE, 0x5C, 0x12, 0x78, 0x87, 0x17,
+	0xB9, 0xC1, 0xBA, 0x06, 0xCB, 0xC2, 0xA6, 0xFE,
+	0xBA, 0x85, 0x84, 0x24, 0x58, 0xC5, 0x6D, 0xDE,
+	0x9D, 0xB1, 0x75, 0x8D, 0x39, 0xC0, 0x31, 0x3D,
+	0x82, 0xBA, 0x51, 0x73, 0x5C, 0xDB, 0x3E, 0xA4,
+	0x99, 0xAA, 0x77, 0xA7, 0xD6, 0x94, 0x3A, 0x64,
+	0xF7, 0xA3, 0xF2, 0x5F, 0xE2, 0x6F, 0x06, 0xB5,
+	0x1B, 0xAA, 0x26, 0x96, 0xFA, 0x90, 0x35, 0xDA,
+	0x5B, 0x53, 0x4B, 0xD5, 0x95, 0xF5, 0xAF, 0x0F,
+	0xA2, 0xC8, 0x92, 0x37, 0x6C, 0x84, 0xAC, 0xE1,
+	0xBB, 0x4E, 0x30, 0x19, 0xB7, 0x16, 0x34, 0xC0,
+	0x11, 0x31, 0x15, 0x9C, 0xAE, 0x03, 0xCE, 0xE9,
+	0xD9, 0x93, 0x21, 0x84, 0xBE, 0xEF, 0x21, 0x6B,
+	0xD7, 0x1D, 0xF2, 0xDA, 0xDF, 0x86, 0xA6, 0x27,
+	0x30, 0x6E, 0xCF, 0xF9, 0x6D, 0xBB, 0x8B, 0xAC,
+	0xE1, 0x98, 0xB6, 0x1E, 0x00, 0xF8, 0xB3, 0x32,
+	0x02, 0x41, 0x00, 0xAA, 0xDD, 0x9D, 0xB8, 0xDB,
+	0xE9, 0xC4, 0x8B, 0x3F, 0xD4, 0xE6, 0xAE, 0x33,
+	0xC9, 0xFC, 0x07, 0xCB, 0x30, 0x8D, 0xB3, 0xB3,
+	0xC9, 0xD2, 0x0E, 0xD6, 0x63, 0x9C, 0xCA, 0x70,
+	0x33, 0x08, 0x70, 0x55, 0x3E, 0x5C, 0x41, 0x4C,
+	0xA9, 0x26, 0x19, 0x41, 0x86, 0x61, 0x19, 0x7F,
+	0xAC, 0x10, 0x47, 0x1D, 0xB1, 0xD3, 0x81, 0x08,
+	0x5D, 0xDA, 0xDD, 0xB5, 0x87, 0x96, 0x82, 0x9C,
+	0xA9, 0x00, 0x69, 0x02, 0x01, 0x01,
+};
+
+struct supported_ecc_curve {
+	const uint8_t *oid_der;
+	size_t oid_size;
+	const uint8_t *name_der;
+	size_t name_size;
+	size_t key_size;
+	uint32_t tee_id;
+	const char *label;
+	size_t label_size;
+};
+
+#define ECC_CURVE(_tee_id, _key_size, _label)	\
+	{							\
+		.tee_id = _tee_id,				\
+		.key_size = _key_size,				\
+		.oid_der = _label ## _oid_der,			\
+		.oid_size = sizeof(_label ## _oid_der),		\
+		.name_der = _label ## _name_der,			\
+		.name_size = sizeof(_label ## _name_der),	\
+		.label = #_label,					\
+		.label_size = sizeof(#_label) - 1,		\
+	}
+
+/* These are introduced with GPD TEE Core Internal API v1.2 */
+#ifndef TEE_ECC_CURVE_BSI_P160r1
+#define TEE_ECC_CURVE_BSI_P160r1	0x00000101 /* 160 bits */
+#define TEE_ECC_CURVE_BSI_P192r1	0x00000102 /* 192 bits */
+#define TEE_ECC_CURVE_BSI_P224r1	0x00000103 /* 224 bits */
+#define TEE_ECC_CURVE_BSI_P256r1	0x00000104 /* 256 bits */
+#define TEE_ECC_CURVE_BSI_P320r1	0x00000105 /* 320 bits */
+#define TEE_ECC_CURVE_BSI_P384r1	0x00000106 /* 384 bits */
+#define TEE_ECC_CURVE_BSI_P512r1	0x00000107 /* 512 bits */
+#define TEE_ECC_CURVE_BSI_P160t1	0x00000201 /* 160 bits */
+#define TEE_ECC_CURVE_BSI_P192t1	0x00000202 /* 192 bits */
+#define TEE_ECC_CURVE_BSI_P224t1	0x00000203 /* 224 bits */
+#define TEE_ECC_CURVE_BSI_P256t1	0x00000204 /* 256 bits */
+#define TEE_ECC_CURVE_BSI_P320t1	0x00000205 /* 320 bits */
+#define TEE_ECC_CURVE_BSI_P384t1	0x00000206 /* 384 bits */
+#define TEE_ECC_CURVE_BSI_P512t1	0x00000207 /* 512 bits */
+#define TEE_ECC_CURVE_25519		0x00000300 /* 256 bits */
+#define TEE_ECC_CURVE_SM2		0x00000400 /* 256 bits */
+#endif
+
+static const struct supported_ecc_curve ec_curve_param[] = {
+	ECC_CURVE(TEE_ECC_CURVE_NIST_P192, 192, prime192v1),
+	ECC_CURVE(TEE_ECC_CURVE_NIST_P224, 224, secp224r1),
+	ECC_CURVE(TEE_ECC_CURVE_NIST_P256, 256, prime256v1),
+	ECC_CURVE(TEE_ECC_CURVE_NIST_P384, 384, secp384r1),
+	ECC_CURVE(TEE_ECC_CURVE_NIST_P521, 521, secp521r1),
+	/* Note: this will be for GPD TEE Core Internal API v1.2 */
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P160r1, 160, brainpoolP160r1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P160t1, 160, brainpoolP160t1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P192r1, 192, brainpoolP192r1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P192t1, 192, brainpoolP192t1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P224r1, 224, brainpoolP224r1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P224t1, 224, brainpoolP224t1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P256r1, 256, brainpoolP256r1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P256t1, 256, brainpoolP256t1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P320r1, 320, brainpoolP320r1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P320t1, 320, brainpoolP320t1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P384r1, 384, brainpoolP384r1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P384t1, 384, brainpoolP384t1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P512r1, 512, brainpoolP512r1),
+	ECC_CURVE(TEE_ECC_CURVE_BSI_P512t1, 512, brainpoolP512t1),
+};
+
+static const struct supported_ecc_curve *get_curve(void *attr, size_t size)
+{
+	size_t idx = 0;
+
+	/* Weak: not a real DER parser: try by params then by named curve */
+	for (idx = 0; idx < ARRAY_SIZE(ec_curve_param); idx++) {
+		const struct supported_ecc_curve *curve = &ec_curve_param[idx];
+
+		if (size == curve->oid_size &&
+		    !TEE_MemCompare(attr, curve->oid_der, curve->oid_size))
+			return curve;
+
+		if (size == curve->name_size &&
+		    !TEE_MemCompare(attr, curve->name_der, curve->name_size))
+			return curve;
+	}
+
+	return NULL;
+}
+
+size_t ec_params2tee_keysize(void *ec_params, size_t size)
+{
+	const struct supported_ecc_curve *curve = get_curve(ec_params, size);
+
+	if (!curve)
+		return 0;
+
+	return curve->key_size;
+}
+
+/*
+ * This function intentionally panics if the curve is not found.
+ * Use ec_params2tee_keysize() to check the curve is supported by
+ * the internal core API.
+ */
+uint32_t ec_params2tee_curve(void *ec_params, size_t size)
+{
+	const struct supported_ecc_curve *curve = get_curve(ec_params, size);
+
+	assert(curve);
+
+	return curve->tee_id;
+}
+
+uint32_t load_tee_ec_key_attrs(TEE_Attribute **tee_attrs, size_t *tee_count,
+				struct sks_object *obj)
+{
+	TEE_Attribute *attrs = NULL;
+	size_t count = 0;
+	uint32_t rv = SKS_ERROR;
+
+	assert(get_type(obj->attributes) == SKS_CKK_EC);
+
+	switch (get_class(obj->attributes)) {
+	case SKS_CKO_PUBLIC_KEY:
+		attrs = TEE_Malloc(3 * sizeof(TEE_Attribute),
+				   TEE_USER_MEM_HINT_NO_FILL_ZERO);
+		if (!attrs)
+			return SKS_MEMORY;
+
+		if (sks2tee_load_attr(&attrs[count], TEE_ATTR_ECC_CURVE,
+					obj, SKS_CKA_EC_PARAMS))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_ECC_PUBLIC_VALUE_X,
+					obj, SKS_CKA_EC_POINT))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_ECC_PUBLIC_VALUE_Y,
+					obj, SKS_CKA_EC_POINT))
+			count++;
+
+		if (count == 3)
+			rv = SKS_OK;
+
+		break;
+
+	case SKS_CKO_PRIVATE_KEY:
+		attrs = TEE_Malloc(4 * sizeof(TEE_Attribute),
+				   TEE_USER_MEM_HINT_NO_FILL_ZERO);
+		if (!attrs)
+			return SKS_MEMORY;
+
+		if (sks2tee_load_attr(&attrs[count], TEE_ATTR_ECC_CURVE,
+					obj, SKS_CKA_EC_PARAMS))
+			count++;
+
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_ECC_PRIVATE_VALUE,
+					obj, SKS_CKA_VALUE))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_ECC_PUBLIC_VALUE_X,
+					obj, SKS_CKA_EC_POINT))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_ECC_PUBLIC_VALUE_Y,
+					obj, SKS_CKA_EC_POINT))
+			count++;
+
+		if (count == 4)
+			rv = SKS_OK;
+
+		break;
+
+	default:
+		assert(0);
+		break;
+	}
+
+	if (rv == SKS_OK) {
+		*tee_attrs = attrs;
+		*tee_count = count;
+	}
+
+	return rv;
+}
+
+uint32_t sks2tee_algo_ecdh(uint32_t *tee_id,
+			   struct sks_attribute_head *proc_params,
+			   struct sks_object *obj)
+{
+	struct serialargs args;
+	uint32_t rv = 0;
+	uint32_t kdf = 0;
+
+	TEE_MemFill(&args, 0, sizeof(args));
+
+	serialargs_init(&args, proc_params->data, proc_params->size);
+
+	rv = serialargs_get(&args, &kdf, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	if (kdf != SKS_CKD_NULL) {
+		EMSG("Currently no support for hashed shared data");
+		return SKS_CKR_MECHANISM_PARAM_INVALID;
+	}
+
+	switch (get_object_key_bit_size(obj)) {
+	case 192:
+		*tee_id = TEE_ALG_ECDH_P192;
+		break;
+	case 224:
+		*tee_id = TEE_ALG_ECDH_P224;
+		break;
+	case 256:
+		*tee_id = TEE_ALG_ECDH_P256;
+		break;
+	case 384:
+		*tee_id = TEE_ALG_ECDH_P384;
+		break;
+	case 521:
+		*tee_id = TEE_ALG_ECDH_P521;
+		break;
+	default:
+		TEE_Panic(0);
+		break;
+	}
+
+	return SKS_OK;
+}
+
+uint32_t sks2tee_ecdh_param_pub(struct sks_attribute_head *proc_params,
+			        void **pub_data, size_t *pub_size)
+{
+	struct serialargs args;
+	uint32_t rv = 0;
+	uint32_t temp = 0;
+
+	TEE_MemFill(&args, 0, sizeof(args));
+
+	serialargs_init(&args, proc_params->data, proc_params->size);
+
+	/* Skip KDF */
+	rv = serialargs_get(&args, &temp, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	/* Shared data size, shall be 0 */
+	rv = serialargs_get(&args, &temp, sizeof(uint32_t));
+	if (rv || temp)
+		return rv;
+
+	/* Public data size and content */
+	rv = serialargs_get(&args, &temp, sizeof(uint32_t));
+	if (rv || !temp)
+		return rv;
+
+	*pub_size = temp;
+
+	return serialargs_get_ptr(&args, pub_data, temp);
+}
+
+uint32_t sks2tee_algo_ecdsa(uint32_t *tee_id,
+			   struct sks_attribute_head *proc_params,
+			   struct sks_object *obj)
+{
+	switch (proc_params->id) {
+	case SKS_CKM_ECDSA:
+	case SKS_CKM_ECDSA_SHA1:
+	case SKS_CKM_ECDSA_SHA224:
+	case SKS_CKM_ECDSA_SHA256:
+	case SKS_CKM_ECDSA_SHA384:
+	case SKS_CKM_ECDSA_SHA512:
+		break;
+	default:
+		return SKS_ERROR;
+	}
+
+	switch (get_object_key_bit_size(obj)) {
+	case 192:
+		*tee_id = TEE_ALG_ECDSA_P192;
+		break;
+	case 224:
+		*tee_id = TEE_ALG_ECDSA_P224;
+		break;
+	case 256:
+		*tee_id = TEE_ALG_ECDSA_P256;
+		break;
+	case 384:
+		*tee_id = TEE_ALG_ECDSA_P384;
+		break;
+	case 521:
+		*tee_id = TEE_ALG_ECDSA_P521;
+		break;
+	default:
+		TEE_Panic(0);
+		break;
+	}
+
+	return SKS_OK;
+}
+
+static uint32_t tee2sks_ec_attributes(struct sks_attrs_head **pub_head,
+				 struct sks_attrs_head **priv_head,
+				 TEE_ObjectHandle tee_obj, uint32_t tee_size)
+{
+	void *x_ptr = NULL;
+	void *y_ptr = NULL;
+	uint8_t *ecpoint = NULL;
+	size_t x_size = 0;
+	size_t y_size = 0;
+	size_t psize = 0;
+	size_t qsize = 0;
+	size_t dersize = 0;
+	size_t poffset = 0;
+	uint32_t rv = 0;
+
+	rv = tee2sks_add_attribute(priv_head, SKS_CKA_VALUE,
+				   tee_obj, TEE_ATTR_ECC_PRIVATE_VALUE);
+	if (rv)
+		goto bail;
+
+	rv = alloc_get_tee_attribute_data(tee_obj, TEE_ATTR_ECC_PUBLIC_VALUE_X,
+					&x_ptr, &x_size);
+	if (rv)
+		goto bail;
+
+	rv = alloc_get_tee_attribute_data(tee_obj, TEE_ATTR_ECC_PUBLIC_VALUE_Y,
+					&y_ptr, &y_size);
+	if (rv)
+		goto x_cleanup;
+
+	psize = (tee_size + 7) / 8;
+	if (x_size > psize || y_size > psize) {
+		rv = SKS_BAD_PARAM;
+		goto p_cleanup;
+	}
+
+	qsize = 1 + 2 * psize;
+	/* TODO: Support DER long definitive form, needed for 64 key size */
+	if (qsize < 0x80) {
+		dersize = qsize + 2;
+	} else {
+		EMSG("DER long definitive form not yet supported");
+		rv = SKS_CKR_MECHANISM_INVALID;
+		goto p_cleanup;
+	}
+
+	ecpoint = TEE_Malloc(dersize, TEE_MALLOC_FILL_ZERO);
+	if (!ecpoint) {
+		rv = SKS_MEMORY;
+		goto p_cleanup;
+	}
+
+	/* DER encoding */
+	ecpoint[0] = 0x04;
+	ecpoint[1] = qsize & 0x7f;
+	/* Only UNCOMPRESSED ECPOINT is currently supported */
+	ecpoint[2] = 0x04;
+
+	poffset = 0;
+	if (x_size < psize)
+		poffset = psize - x_size;
+	TEE_MemMove(ecpoint + 3 + poffset, x_ptr, x_size);
+
+	poffset = 0;
+	if (y_size < psize)
+		poffset = psize - y_size;
+	TEE_MemMove(ecpoint + 3 + psize + poffset, y_ptr, y_size);
+
+	/*
+	 * Add EC_POINT on both private and public key objects as
+	 * TEE_PopulateTransientObject requires public x/y values
+	 * for TEE_TYPE_ECDSA_KEYPAIR.
+	 */
+	rv = add_attribute(priv_head, SKS_CKA_EC_POINT, ecpoint, dersize);
+	if (rv)
+		goto priv_cleanup;
+
+	rv = add_attribute(pub_head, SKS_CKA_EC_POINT, ecpoint, dersize);
+
+priv_cleanup:
+	TEE_Free(ecpoint);
+p_cleanup:
+	TEE_Free(y_ptr);
+x_cleanup:
+	TEE_Free(x_ptr);
+bail:
+	return rv;
+}
+
+uint32_t generate_ec_keys(struct sks_attribute_head *proc_params,
+			  struct sks_attrs_head **pub_head,
+			  struct sks_attrs_head **priv_head)
+{
+	uint32_t rv = 0;
+	void *a_ptr = NULL;
+	uint32_t a_size = 0;
+	uint32_t tee_size = 0;
+	uint32_t tee_curve = 0;
+	TEE_ObjectHandle tee_obj = TEE_HANDLE_NULL;
+	TEE_Attribute tee_key_attr[1];
+	TEE_Result res = TEE_ERROR_GENERIC;
+
+	TEE_MemFill(tee_key_attr, 0, sizeof(tee_key_attr));
+
+	if (!proc_params || !*pub_head || !*priv_head)
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+
+	if (!get_attribute_ptr(*pub_head, SKS_CKA_EC_POINT, NULL, NULL) ||
+	    !get_attribute_ptr(*priv_head, SKS_CKA_VALUE, NULL, NULL) ||
+	    !get_attribute_ptr(*priv_head, SKS_CKA_EC_POINT, NULL, NULL)) {
+		EMSG("Unexpected attribute(s) found");
+		trace_attributes("public-key", *pub_head);
+		trace_attributes("privat-key", *priv_head);
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	if (get_attribute_ptr(*pub_head, SKS_CKA_EC_PARAMS, &a_ptr, &a_size)) {
+		EMSG("Not EC_PARAMS attribute found");
+		return SKS_CKR_ATTRIBUTE_TYPE_INVALID;
+	}
+
+	tee_size = ec_params2tee_keysize(a_ptr, a_size);
+	if (!tee_size)
+		return SKS_CKR_ATTRIBUTE_TYPE_INVALID;
+
+	tee_curve = ec_params2tee_curve(a_ptr, a_size);
+
+	TEE_InitValueAttribute(&tee_key_attr[0], TEE_ATTR_ECC_CURVE,
+				tee_curve, 0);
+
+	/* Create an ECDSA TEE key: will match PKCS11 ECDSA and ECDH */
+	res = TEE_AllocateTransientObject(TEE_TYPE_ECDSA_KEYPAIR,
+					  521/*tee_size*/, &tee_obj);
+	if (res) {
+		EMSG("TEE service failed, %" PRIx32, res);
+		return tee2sks_error(res);
+	}
+
+	res = TEE_RestrictObjectUsage1(tee_obj, TEE_USAGE_EXTRACTABLE);
+	if (res) {
+		rv = tee2sks_error(res);
+		goto bail;
+	}
+
+	res = TEE_GenerateKey(tee_obj, tee_size, &tee_key_attr[0], 1);
+	if (res) {
+		rv = tee2sks_error(res);
+		goto bail;
+	}
+
+	/*
+	 * Private key needs the same EC_PARAMS as used by the public key.
+	 * Since it is also common for userspace to provide an empty private
+	 * EC_PARAMS, make sure to remove before adding the correct one.
+	 */
+	remove_attribute(priv_head, SKS_CKA_EC_PARAMS);
+	rv = add_attribute(priv_head, SKS_CKA_EC_PARAMS, a_ptr, a_size);
+	if (rv)
+		goto bail;
+
+	rv = tee2sks_ec_attributes(pub_head, priv_head, tee_obj, tee_size);
+
+bail:
+	if (tee_obj != TEE_HANDLE_NULL)
+		TEE_FreeTransientObject(tee_obj);
+
+	return rv;
+}
+
+static int sks2uecc_curve_id(int curve_id)
+{
+	int uECC_curve_id = -1;
+	switch (curve_id)
+	{
+	case TEE_ECC_CURVE_NIST_P192:
+		uECC_curve_id = UECC_CURVE_ID_SECP192R1;
+		break;
+	case TEE_ECC_CURVE_NIST_P224:
+		uECC_curve_id = UECC_CURVE_ID_SECP224R1;
+		break;
+	case TEE_ECC_CURVE_NIST_P256:
+		uECC_curve_id = UECC_CURVE_ID_SECP256R1;
+		break;
+	case TEE_ECC_CURVE_NIST_P384:
+		uECC_curve_id = UECC_CURVE_ID_SECP384R1;
+		break;
+	case TEE_ECC_CURVE_NIST_P521:
+	default:
+		EMSG("[%s][%d] not support curve id!", __FUNCTION__, __LINE__);
+		uECC_curve_id = UECC_CURVE_ID_UNSUPPORT;
+		break;
+	}
+	return uECC_curve_id;
+}
+
+uint32_t generate_hsm_ec_keys(struct sks_attribute_head *proc_params,
+			  struct sks_attrs_head **pub_head,
+			  struct sks_attrs_head **priv_head)
+{
+	uint32_t rv = 0;
+	void *a_ptr = NULL;
+	uint32_t a_size = 0;
+	uint32_t tee_size = 0;
+	uint32_t tee_curve = 0;
+	TEE_ObjectHandle tee_obj = TEE_HANDLE_NULL;
+	TEE_Attribute tee_key_attr[1];
+	TEE_Result res = TEE_ERROR_GENERIC;
+	int keyid = 0;
+	int key_size = 0;
+	int uECC_curve_id = -1;
+
+	TEE_MemFill(tee_key_attr, 0, sizeof(tee_key_attr));
+
+	if (!proc_params || !*pub_head || !*priv_head)
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+
+	if (!get_attribute_ptr(*pub_head, SKS_CKA_EC_POINT, NULL, NULL) ||
+	    !get_attribute_ptr(*priv_head, SKS_CKA_VALUE, NULL, NULL) ||
+	    !get_attribute_ptr(*priv_head, SKS_CKA_EC_POINT, NULL, NULL)) {
+		EMSG("Unexpected attribute(s) found");
+		trace_attributes("public-key", *pub_head);
+		trace_attributes("privat-key", *priv_head);
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	if (get_attribute_ptr(*pub_head, SKS_CKA_EC_PARAMS, &a_ptr, &a_size)) {
+		EMSG("Not EC_PARAMS attribute found");
+		return SKS_CKR_ATTRIBUTE_TYPE_INVALID;
+	}
+
+	tee_size = ec_params2tee_keysize(a_ptr, a_size);
+	if (!tee_size)
+		return SKS_CKR_ATTRIBUTE_TYPE_INVALID;
+
+	tee_curve = ec_params2tee_curve(a_ptr, a_size);
+
+	key_size = tee_size >> 3;
+
+	uECC_curve_id = sks2uecc_curve_id(tee_curve);
+	if (uECC_curve_id == UECC_CURVE_ID_UNSUPPORT)
+	{
+		rv = SKS_CKR_ARGUMENTS_BAD;
+		goto bail;
+	}
+
+	rv = mtk_generate_ecc_key_pair(tee_size, uECC_curve_id, &keyid);
+	if (rv)
+		goto bail;
+
+	/*
+	 * Private key needs the same EC_PARAMS as used by the public key.
+	 * Since it is also common for userspace to provide an empty private
+	 * EC_PARAMS, make sure to remove before adding the correct one.
+	 */
+	remove_attribute(priv_head, SKS_CKA_EC_PARAMS);
+	rv = add_attribute(priv_head, SKS_CKA_EC_PARAMS, a_ptr, a_size);
+	if (rv)
+		goto bail;
+
+	rv = add_attribute(pub_head, SKS_CKA_HSM_KEY_ID, &keyid, sizeof(keyid));
+	if (rv)
+		goto bail;
+
+	rv = add_attribute(pub_head, SKS_CKA_HSM_KEY_LEN, &key_size, sizeof(key_size));
+	if (rv )
+		goto bail;
+
+	rv = add_attribute(priv_head, SKS_CKA_HSM_KEY_ID, &keyid, sizeof(keyid));
+	if (rv)
+		goto bail;
+
+	rv = add_attribute(priv_head, SKS_CKA_HSM_KEY_LEN, &key_size, sizeof(key_size));
+	if (rv )
+		goto bail;
+
+bail:
+	return rv;
+}
+
+uint32_t import_hsm_ecc_keypair(struct sks_attrs_head **pub,
+                                struct sks_attrs_head **priv,
+                                uint8_t *keyblob,
+                                int *blobsize)
+{
+	uint32_t rv = 0;
+	uint8_t *pubkeybuf = NULL;
+	uint32_t pubkeylength;
+	uint8_t *privkeybuf = NULL;
+	uint32_t privkeylength;
+	void *data = NULL;
+	uint32_t data_size;
+	void *a_ptr = NULL;
+	uint32_t a_size = 0;
+	uint32_t tee_size = 0;
+	uint32_t tee_curve = 0;
+	int key_size = 0;
+	int keyid = 0;
+	int uECC_curve_id = -1;
+	ecc_keypair_datastruct ecckeypair;
+
+	TEE_MemFill(&ecckeypair, 0, sizeof(ecckeypair));
+
+	if (!*pub || !*priv || !keyblob || !blobsize)
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+
+	rv = get_attribute_ptr(*priv, SKS_CKA_VALUE, &privkeybuf, &privkeylength);
+	if (rv) {
+		EMSG("[%s][%d] rv : %d\n", __FUNCTION__, __LINE__, rv);
+		return SKS_CKR_GENERAL_ERROR;
+	}
+
+	rv = get_attribute_ptr(*pub, SKS_CKA_VALUE, &pubkeybuf, &pubkeylength);
+	if (rv) {
+		EMSG("[%s][%d] rv : %d\n", __FUNCTION__, __LINE__, rv);
+		return SKS_CKR_GENERAL_ERROR;
+	}
+
+	if (get_attribute_ptr(*pub, SKS_CKA_EC_PARAMS, &a_ptr, &a_size)) {
+		EMSG("Not EC_PARAMS attribute found");
+		return SKS_CKR_ATTRIBUTE_TYPE_INVALID;
+	}
+
+	tee_size = ec_params2tee_keysize(a_ptr, a_size);
+	if (!tee_size)
+		return SKS_CKR_ATTRIBUTE_TYPE_INVALID;
+
+	tee_curve = ec_params2tee_curve(a_ptr, a_size);
+
+	key_size = tee_size >> 3;
+
+	uECC_curve_id = sks2uecc_curve_id(tee_curve);
+	if (uECC_curve_id == UECC_CURVE_ID_UNSUPPORT)
+	{
+		rv = SKS_CKR_ARGUMENTS_BAD;
+		goto bail;
+	}
+
+	ecckeypair.curve_id = uECC_curve_id;
+	TEE_MemMove(ecckeypair.public, pubkeybuf, pubkeylength);
+	TEE_MemMove(ecckeypair.private, privkeybuf, privkeylength);
+
+	rv = mtk_import_key((uint8_t *)&ecckeypair, sizeof(ecckeypair), &keyid, keyblob, blobsize, KEY_ALGO_ID_ECC);
+	if (rv)
+		goto bail;
+
+	rv = add_attribute(pub, SKS_CKA_HSM_KEY_ID, &keyid, sizeof(keyid));
+	if (rv)
+		return SKS_CKR_GENERAL_ERROR;
+
+	rv = add_attribute(pub, SKS_CKA_HSM_KEY_LEN, &key_size, sizeof(key_size));
+	if (rv )
+		return SKS_CKR_GENERAL_ERROR;
+
+	rv = add_attribute(priv, SKS_CKA_HSM_KEY_ID, &keyid, sizeof(keyid));
+	if (rv)
+		return SKS_CKR_GENERAL_ERROR;
+
+	rv = add_attribute(priv, SKS_CKA_HSM_KEY_LEN, &key_size, sizeof(key_size));
+	if (rv )
+		return SKS_CKR_GENERAL_ERROR;
+bail:
+	return rv;
+}
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.c
new file mode 100644
index 0000000..6bfcf24
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.c
@@ -0,0 +1,1690 @@
+// SPDX-License-Identifier: BSD-2-Clause

+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+

+#include "processing_mtk_hsm.h"

+#include "hsm_mbox_if.h"

+#include "mtk_crypto.h"

+#include "hsm_job.h"

+#include "sks_hsm_debug.h"

+

+#define GET_BE32(a) ((((uint32_t) (a)[0]) << 24) | \

+                    (((uint32_t) (a)[1]) << 16) | \

+                    (((uint32_t) (a)[2]) << 8) | \

+                    ((uint32_t) (a)[3]))

+

+#define PUT_BE32(a, val) {	\

+		(a)[0] = (uint8_t) ((((uint32_t) (val)) >> 24) & 0xff);	\

+		(a)[1] = (uint8_t) ((((uint32_t) (val)) >> 16) & 0xff);	\

+		(a)[2] = (uint8_t) ((((uint32_t) (val)) >> 8) & 0xff);	\

+		(a)[3] = (uint8_t) (((uint32_t) (val)) & 0xff);		\

+}

+

+#define PUT_BE64(a, val) { \

+		(a)[0] = (uint8_t) (((uint64_t) (val)) >> 56 & 0xff);	\

+		(a)[1] = (uint8_t) (((uint64_t) (val)) >> 48 & 0xff);	\

+		(a)[2] = (uint8_t) (((uint64_t) (val)) >> 40 & 0xff);	\

+		(a)[3] = (uint8_t) (((uint64_t) (val)) >> 32 & 0xff);	\

+		(a)[4] = (uint8_t) (((uint64_t) (val)) >> 24 & 0xff);	\

+		(a)[5] = (uint8_t) (((uint64_t) (val)) >> 16 & 0xff);	\

+		(a)[6] = (uint8_t) (((uint64_t) (val)) >> 8 & 0xff);	\

+		(a)[7] = (uint8_t) (((uint64_t) (val)) & 0xff);	\

+}

+

+#define LOOKBIT(x) (1UL << (x))

+

+extern  TEE_Result Send_job(job_struct *pjob);

+extern  TEE_Result dump_hsm_log(void);

+

+void __SHOW_VAL(char *c, uint8_t *ptr, uint32_t len);

+void __SHOW_VAL(char *c, uint8_t *ptr, uint32_t len)

+{

+#if HSM_TA_DEBUG

+

+	uint8_t line[8] = {0};

+	SKS_HSM_DEBUG(" --- %s ( %d ) bytes ---\r\n", c, len);

+	int j = 0;

+	for (j = 0; j < len; j++)

+	{

+		line[j % 8] = *(ptr + j);

+		if ((j % 8) == 7)

+			SKS_HSM_DEBUG(" %02X %02X %02X %02X - %02X %02X %02X %02X  \r\n"

+				 , line[0], line[1], line[2], line[3]

+				 , line[4], line[5], line[6], line[7]);

+	}

+	if ((j % 8) != 0)

+	{

+		switch (j % 8)

+		{

+		case 1: SKS_HSM_DEBUG(" %02X -- -- -- - -- -- -- --  \r\n", line[0]); break;

+		case 2: SKS_HSM_DEBUG(" %02X %02X -- -- - -- -- -- --  \r\n", line[0], line[1]); break;

+		case 3: SKS_HSM_DEBUG(" %02X %02X %02X -- - -- -- -- --  \r\n", line[0], line[1], line[2]); break;

+		case 4: SKS_HSM_DEBUG(" %02X %02X %02X %02X - -- -- -- --  \r\n", line[0], line[1], line[2], line[3]); break;

+		case 5: SKS_HSM_DEBUG(" %02X %02X %02X %02X - %02X -- -- --  \r\n", line[0], line[1], line[2], line[3], line[4]); break;

+		case 6: SKS_HSM_DEBUG(" %02X %02X %02X %02X - %02X %02X -- --  \r\n", line[0], line[1], line[2], line[3], line[4], line[5]); break;

+		case 7: SKS_HSM_DEBUG(" %02X %02X %02X %02X - %02X %02X %02X --  \r\n", line[0], line[1], line[2], line[3], line[4], line[5], line[6]); break;

+		}

+	}

+	SKS_HSM_DEBUG(" --------------------\r\n");

+

+#endif

+}

+

+static void inc32(uint8_t *block, uint32_t i)

+{

+	uint32_t val = 0;

+	uint32_t org_val = 0;

+

+	val = GET_BE32(block + 12);

+	org_val = val;

+	val += i;

+	PUT_BE32(block + 12, val);

+

+	if (org_val > val) // Overflow

+	{

+		for (int i = 11; i >= 0; i--)

+		{

+			block[i]++;

+			if (block[i] != 0)

+				break;

+		}

+	}

+}

+

+static void xor_block(uint8_t *dst, const uint8_t *src)

+{

+	uint32_t *d = (uint32_t *) dst;

+	uint32_t *s = (uint32_t *) src;

+	*d++ ^= *s++;

+	*d++ ^= *s++;

+	*d++ ^= *s++;

+	*d++ ^= *s++;

+}

+

+static void shift_right_block(uint8_t *v)

+{

+	uint32_t val = 0;

+

+	val = GET_BE32(v + 12);

+	val >>= 1;

+	if (v[11] & 0x01)

+		val |= 0x80000000;

+	PUT_BE32(v + 12, val);

+

+	val = GET_BE32(v + 8);

+	val >>= 1;

+	if (v[7] & 0x01)

+		val |= 0x80000000;

+	PUT_BE32(v + 8, val);

+

+	val = GET_BE32(v + 4);

+	val >>= 1;

+	if (v[3] & 0x01)

+		val |= 0x80000000;

+	PUT_BE32(v + 4, val);

+

+	val = GET_BE32(v);

+	val >>= 1;

+	PUT_BE32(v, val);

+}

+

+

+/* Multiplication in GF(2^128) */

+static void gf_mult(const uint8_t *x, const uint8_t *y, uint8_t *z)

+{

+	uint8_t v[16] = {0};

+	int i = 0;

+	int j = 0;

+

+	memset(z, 0, 16); /* Z_0 = 0^128 */

+	memcpy(v, y, 16); /* V_0 = Y */

+

+	for (i = 0; i < 16; i++) {

+		for (j = 0; j < 8; j++) {

+			if (x[i] & LOOKBIT(7 - j)) {

+				/* Z_(i + 1) = Z_i XOR V_i */

+				xor_block(z, v);

+			} else {

+				/* Z_(i + 1) = Z_i */

+			}

+

+			if (v[15] & 0x01) {

+				/* V_(i + 1) = (V_i >> 1) XOR R */

+				shift_right_block(v);

+				/* R = 11100001 || 0^120 */

+				v[0] ^= 0xe1;

+			} else {

+				/* V_(i + 1) = V_i >> 1 */

+				shift_right_block(v);

+			}

+		}

+	}

+}

+

+

+static void ghash_start(uint8_t *y)

+{

+	/* Y_0 = 0^128 */

+	memset(y, 0, 16);

+}

+

+

+static void ghash(const uint8_t *h, const uint8_t *x, size_t xlen, uint8_t *y)

+{

+	size_t m = 0;

+	size_t i = 0;

+	const uint8_t *xpos = x;

+	uint8_t tmp[16] = {0};

+

+	m = xlen / 16;

+

+	for (i = 0; i < m; i++) {

+		/* Y_i = (Y^(i-1) XOR X_i) dot H */

+		xor_block(y, xpos);

+		xpos += 16;

+

+		/* dot operation:

+		 * multiplication operation for binary Galois (finite) field of

+		 * 2^128 elements */

+		gf_mult(y, h, tmp);

+		memcpy(y, tmp, 16);

+	}

+

+	if (x + xlen > xpos) {

+		/* Add zero padded last block */

+		size_t last = x + xlen - xpos;

+		memcpy(tmp, xpos, last);

+		memset(tmp + last, 0, sizeof(tmp) - last);

+

+		/* Y_i = (Y^(i-1) XOR X_i) dot H */

+		xor_block(y, tmp);

+

+		/* dot operation:

+		 * multiplication operation for binary Galois (finite) field of

+		 * 2^128 elements */

+		gf_mult(y, h, tmp);

+		memcpy(y, tmp, 16);

+	}

+

+	/* Return Y_m */

+}

+

+

+static void aes_gcm_calculate_j0(const uint8_t *H, const uint8_t *iv, size_t iv_len, uint8_t *J0)

+{

+	uint8_t len_buf[16] = {0};

+

+	if (iv_len == 12)

+	{

+		/* calculate block J_0 = IV || 0^31 || 1 */

+		memcpy(J0, iv, iv_len);

+		memset(J0 + iv_len, 0, 16 - iv_len);

+		J0[15] = 0x01;

+	}

+	else

+	{

+		/*

+		 * s = 128 * ceil(len(IV)/128) - len(IV)

+		 * J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64)

+		 */

+		ghash_start(J0);

+		ghash(H, iv, iv_len, J0);

+		PUT_BE64(len_buf, 0);

+		PUT_BE64(len_buf + 8, iv_len * 8);

+		ghash(H, len_buf, sizeof(len_buf), J0);

+	}

+}

+

+

+static void aes_gcm_ghash(const uint8_t *H, const uint8_t *aad, size_t aad_len,

+                          const uint8_t *crypt, size_t crypt_len, uint8_t *S)

+{

+	uint8_t len_buf[16] = {0};

+

+	/*

+	 * u = 128 * ceil[len(C)/128] - len(C)

+	 * v = 128 * ceil[len(A)/128] - len(A)

+	 * S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)

+	 * (i.e., zero padded to block size A || C and lengths of each in bits)

+	 */

+	ghash_start(S);

+	ghash(H, aad, aad_len, S);

+	ghash(H, crypt, crypt_len, S);

+	PUT_BE64(len_buf, aad_len * 8);

+	PUT_BE64(len_buf + 8, crypt_len * 8);

+	ghash(H, len_buf, sizeof(len_buf), S);

+}

+

+static uint32_t get_symmetric_key_from_attribute(struct sks_object *key, MTK_HSM_State *state)

+{

+	int key_id = 0;

+	int key_id_size = sizeof(key_id);

+	int key_len = 0;

+	int key_len_size = sizeof(key_len);

+	uint32_t rv = 0;

+

+	if ((key == NULL) || (state == NULL))

+		 return SKS_CKR_ARGUMENTS_BAD;

+

+	rv = get_attribute(key->attributes, SKS_CKA_HSM_KEY_ID, &key_id, &key_id_size);

+	if (rv != 0)

+		return rv;

+	rv = get_attribute(key->attributes, SKS_CKA_HSM_KEY_LEN, &key_len, &key_len_size);

+	if (rv != 0)

+		return rv;

+

+	state->key1_id = key_id;

+	state->key1_len = key_len;

+

+	SKS_HSM_DEBUG(" ==> state->key1_len: %d\n", state->key1_len);

+	return SKS_OK;

+}

+

+uint32_t mtk_AES_ECB_init(struct pkcs11_session *session,

+                          struct sks_attribute_head *proc_params,

+                          struct sks_object *key)

+{

+	MTK_HSM_State *_ptr = NULL;

+	uint32_t rv = 0;

+

+	if ((session == NULL) || (proc_params == NULL) || (key == NULL))

+		 return SKS_BAD_PARAM;

+

+	_ptr = TEE_Malloc(sizeof(MTK_HSM_State), TEE_MALLOC_FILL_ZERO);

+	if (!_ptr)

+		return SKS_MEMORY;

+

+	// Get key

+	rv = get_symmetric_key_from_attribute(key, _ptr);

+	if(rv != SKS_OK)

+		return rv;

+

+	session->processing->mtk_hsm_handle = _ptr;

+

+

+	return SKS_OK;

+}

+

+uint32_t mtk_AES_CBC_init(struct pkcs11_session *session,

+						  struct sks_attribute_head *proc_params,

+						  struct sks_object *key)

+{

+	MTK_HSM_State *_ptr = NULL;

+	uint8_t *IV = NULL;

+	uint32_t rv = 0;

+

+	if ((session == NULL) || (proc_params == NULL))

+		 return SKS_BAD_PARAM;

+

+	IV = proc_params->data;

+

+	_ptr = TEE_Malloc(sizeof(MTK_HSM_State), TEE_MALLOC_FILL_ZERO);

+	if (!_ptr)

+		return SKS_MEMORY;

+

+	memcpy(_ptr->CBC_IV, IV, 16);

+

+	// Get key

+	rv = get_symmetric_key_from_attribute(key, _ptr);

+	if(rv != SKS_OK)

+		return rv;

+

+	session->processing->mtk_hsm_handle = _ptr;

+

+	return SKS_OK;

+}

+

+uint32_t mtk_AES_CTR_init(struct pkcs11_session *session,

+				struct sks_attribute_head *proc_params,

+				struct sks_object *key)

+{

+	MTK_HSM_State *_ptr = NULL;

+	uint8_t *CTR = NULL;

+	struct serialargs args;

+	uint32_t rv = 0;

+	/* CTR parameters */

+	uint32_t incr_counter = 0;

+

+	if ((session == NULL) || (proc_params == NULL))

+		 return SKS_BAD_PARAM;

+

+	TEE_MemFill(&args, 0, sizeof(args));

+

+	if (!proc_params)

+		return SKS_BAD_PARAM;

+

+	serialargs_init(&args, proc_params->data, proc_params->size);

+

+	rv = serialargs_get(&args, &incr_counter, sizeof(uint32_t));

+	if (rv)

+		goto bail;

+

+	rv = serialargs_get_ptr(&args, &CTR, 16);

+	if (rv)

+		goto bail;

+

+	__SHOW_VAL("CTR", CTR, 16);

+

+

+	_ptr = TEE_Malloc(sizeof(MTK_HSM_State), TEE_MALLOC_FILL_ZERO);

+	if (!_ptr)

+		return SKS_MEMORY;

+

+	memcpy(_ptr->CTR, CTR, 16);

+

+	// Get key

+	rv = get_symmetric_key_from_attribute(key, _ptr);

+	if(rv != SKS_OK)

+		return rv;

+

+	session->processing->mtk_hsm_handle = _ptr;

+

+bail:

+	return SKS_OK;

+

+}

+

+uint32_t mtk_AES_GCM_init(struct pkcs11_session *session,

+				struct sks_attribute_head *proc_params,

+				struct sks_object *key)

+{

+	MTK_HSM_State *_ptr = NULL;

+	uint8_t *pIv = NULL;

+	uint32_t ulIvLen = 0;

+	uint8_t *pAAD = NULL;

+	uint32_t ulAADLen = 0;

+	uint8_t ulTagBits = 0;

+

+	struct serialargs args;

+	uint32_t rv = 0;

+	/* GCM parameters */

+	uint32_t incr_counter = 0;

+

+	static const org_0[16] = {0};

+	uint8_t H[16] = {0};

+	job_struct _job = {0};

+	uint8_t J0[16] = {0};

+	uint8_t S[16] = {0};

+

+	if ((session == NULL) || (proc_params == NULL))

+		 return SKS_BAD_PARAM;

+

+	TEE_MemFill(&args, 0, sizeof(args));

+

+	if (!proc_params)

+		return SKS_BAD_PARAM;

+

+	serialargs_init(&args, proc_params->data, proc_params->size);

+

+	rv = serialargs_get(&args, &ulIvLen, sizeof(uint32_t));

+	if (rv)

+		goto bail;

+

+	rv = serialargs_get_ptr(&args, &pIv, ulIvLen);

+	if (rv)

+		goto bail;

+

+	rv = serialargs_get(&args, &ulAADLen, sizeof(uint32_t));

+	if (rv)

+		goto bail;

+

+	rv = serialargs_get_ptr(&args, &pAAD, ulAADLen);

+	if (rv)

+		goto bail;

+

+	rv = serialargs_get(&args, &ulTagBits, sizeof(uint8_t));

+	if (rv)

+		goto bail;

+

+	_ptr = TEE_Malloc(sizeof(MTK_HSM_State), TEE_MALLOC_FILL_ZERO);

+	if (!_ptr)

+		return SKS_MEMORY;

+

+	// Get key

+	rv = get_symmetric_key_from_attribute(key, _ptr);

+	if(rv != SKS_OK)

+		return rv;

+

+	/* H = ECB(0^128) */

+	SKS_HSM_DEBUG("-> H = ECB(0^128)\r\n");

+

+	_job.inputPtr               = org_0;

+	_job.inputLength            = 16;

+	_job.outputPtr              = H;

+	_job.outputLength           = 16;

+

+	_job.service		    = CRYPTO_ENCRYPT;

+	_job.family                 = CRYPTO_ALGOFAM_AES;

+	_job.mode                   = CRYPTO_ALGOMODE_ECB;

+	_job.operation_mode         = CRYPTO_OPERATIONMODE_START;

+

+	_job.cryptoKeyId            = _ptr->key1_id;

+	_job.keyLength              = _ptr->key1_len * 8;

+

+	Send_job(&_job);

+

+	/* calculate_j0 */

+	SKS_HSM_DEBUG("-> Calculate j0 \r\n");

+	aes_gcm_calculate_j0(H, pIv, ulIvLen, J0);

+//	__SHOW_VAL("J0", J0, 16);

+

+	/* calculate S of add data*/

+	ghash(H, pAAD, ulAADLen, S);

+

+	memcpy(_ptr->H,   H,  16);

+	memcpy(_ptr->S,   S,  16);

+	memcpy(_ptr->J0,  J0, 16);

+	inc32(J0, 1);

+	memcpy(_ptr->CTR, J0, 16);

+	_ptr->add_len = ulAADLen;

+	_ptr->total_len = 0;

+

+	session->processing->mtk_hsm_handle = _ptr;

+

+bail:

+	return SKS_OK;

+

+}

+

+uint32_t mtk_HMAC_init(struct pkcs11_session *session,

+				struct sks_attribute_head *proc_params,

+				struct sks_object *key)

+{

+	MTK_HSM_State *_ptr = NULL;

+	uint32_t rv = 0;

+

+	if ((session == NULL) || (proc_params == NULL))

+		 return SKS_BAD_PARAM;

+

+	 _ptr = TEE_Malloc(sizeof(MTK_HSM_State), TEE_MALLOC_FILL_ZERO);

+	if (!_ptr)

+		return SKS_MEMORY;

+

+	memset(_ptr->SHA_IV, 0, SHA_MAX_OUTPUT_SIZE);

+	memset(_ptr->SHA_buf, 0, SHA_MAX_BLOCK_SIZE);

+	_ptr->SHA_remain_len = 0;

+	_ptr->isFirstUpdate  = true;

+

+	// Get key

+	rv = get_symmetric_key_from_attribute(key, _ptr);

+	if(rv != SKS_OK)

+		return rv;

+

+	session->processing->mtk_hsm_handle = _ptr;

+

+	return SKS_OK;

+}

+

+uint32_t mtk_AES_CMAC_init(struct pkcs11_session *session,

+				struct sks_attribute_head *proc_params,

+				struct sks_object *key)

+{

+	MTK_HSM_State *_ptr = NULL;

+	uint32_t rv = 0;

+

+	if ((session == NULL) || (proc_params == NULL))

+		 return SKS_BAD_PARAM;

+

+	_ptr = TEE_Malloc(sizeof(MTK_HSM_State), TEE_MALLOC_FILL_ZERO);

+	if (!_ptr)

+		return SKS_MEMORY;

+

+	memset(_ptr->CMAC_Buf, 0, 16);

+	_ptr->isFirstUpdate    = true;

+

+	// Get key

+	rv = get_symmetric_key_from_attribute(key, _ptr);

+	if(rv != SKS_OK)

+		return rv;

+

+	session->processing->mtk_hsm_handle = _ptr;

+

+	return SKS_OK;

+}

+

+uint32_t mtk_SHA_init(struct pkcs11_session *session,

+					  struct sks_attribute_head *proc_params)

+{

+	MTK_HSM_State *_ptr = NULL;

+

+	if ((session == NULL) || (proc_params == NULL))

+		 return SKS_BAD_PARAM;

+

+	 _ptr = TEE_Malloc(sizeof(MTK_HSM_State), TEE_MALLOC_FILL_ZERO);

+	if (!_ptr)

+		return SKS_MEMORY;

+

+	memset(_ptr->SHA_IV, 0, SHA_MAX_OUTPUT_SIZE);

+	memset(_ptr->SHA_buf, 0, SHA_MAX_BLOCK_SIZE);

+	_ptr->SHA_remain_len = 0;

+	_ptr->isFirstUpdate  = true;

+

+	session->processing->mtk_hsm_handle = _ptr;

+

+	return SKS_OK;

+}

+

+uint32_t mtk_ECDSA_init(struct pkcs11_session *session,

+						struct sks_attribute_head *proc_params,

+						struct sks_object *key)

+{

+	MTK_HSM_State *_ptr = NULL;

+	int key_id = 0;

+	int key_id_size = sizeof(key_id);

+	int key_len = 0;

+	int key_len_size = sizeof(key_len);

+	uint32_t rv = 0;

+

+	if ((session == NULL) || (proc_params == NULL))

+		 return SKS_BAD_PARAM;

+

+	_ptr = TEE_Malloc(sizeof(MTK_HSM_State), TEE_MALLOC_FILL_ZERO);

+	if (!_ptr)

+		return SKS_MEMORY;

+

+	// Get key

+	rv = get_attribute(key->attributes, SKS_CKA_HSM_KEY_ID, &key_id, &key_id_size);

+	rv = get_attribute(key->attributes, SKS_CKA_HSM_KEY_LEN, &key_len, &key_len_size);

+

+	session->processing->mtk_hsm_handle = _ptr;

+	session->processing->mtk_hsm_handle->key1_id = key_id;

+	session->processing->mtk_hsm_handle->key1_len = key_len;

+

+	return SKS_OK;

+}

+

+uint32_t mtk_ECDSA_SHA_init(struct pkcs11_session *session,

+						struct sks_attribute_head *proc_params,

+						struct sks_object *key)

+{

+	MTK_HSM_State *_ptr = NULL;

+	int key_id = 0;

+	int key_id_size = sizeof(key_id);

+	int key_len = 0;

+	int key_len_size = sizeof(key_len);

+	uint32_t rv = 0;

+

+	if ((session == NULL) || (proc_params == NULL))

+		 return SKS_BAD_PARAM;

+

+	_ptr = TEE_Malloc(sizeof(MTK_HSM_State), TEE_MALLOC_FILL_ZERO);

+	if (!_ptr)

+		return SKS_MEMORY;

+

+	memset(_ptr->SHA_IV, 0, SHA_MAX_OUTPUT_SIZE);

+	memset(_ptr->SHA_buf, 0, SHA_MAX_BLOCK_SIZE);

+	_ptr->SHA_remain_len = 0;

+	_ptr->isFirstUpdate  = true;

+

+	// Get key

+	rv = get_attribute(key->attributes, SKS_CKA_HSM_KEY_ID, &key_id, &key_id_size);

+	rv = get_attribute(key->attributes, SKS_CKA_HSM_KEY_LEN, &key_len, &key_len_size);

+

+	session->processing->mtk_hsm_handle = _ptr;

+	session->processing->mtk_hsm_handle->key1_id = key_id;

+	session->processing->mtk_hsm_handle->key1_len = key_len;

+

+	return SKS_OK;

+}

+

+enum Crypto_OperationModeType _Step_to_OPmode(enum processing_step step, uint8_t isFirstUpdate)

+{

+	switch (step)

+	{

+	case SKS_FUNC_STEP_ONESHOT:

+		return CRYPTO_OPERATIONMODE_SINGLECALL;

+

+	case SKS_FUNC_STEP_UPDATE:

+		if (isFirstUpdate == true)

+			return CRYPTO_OPERATIONMODE_START;

+		else

+			return CRYPTO_OPERATIONMODE_UPDATE;

+

+	case SKS_FUNC_STEP_FINAL:

+		return CRYPTO_OPERATIONMODE_FINISH;

+

+	default:

+		return CRYPTO_OPERATIONMODE_INVALID;

+	}

+}

+

+uint32_t mtk_AES_ECB_step(struct pkcs11_session *session,

+							  TEE_Param *in, TEE_Param *out,

+							  enum processing_func function,

+							  enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+	job_struct _job = {0};

+

+	if (step == SKS_FUNC_STEP_FINAL)

+		return SKS_OK;

+

+	if ((session == NULL) || (out == NULL))

+		return SKS_BAD_PARAM;

+

+	_job.inputPtr               = in ? (uint8_t *)in->memref.buffer  : NULL;

+	_job.inputLength            = in ? in->memref.size : 0;

+

+	_job.outputPtr              = out ? (uint8_t *)out->memref.buffer : NULL;

+	_job.outputLength           = out ? out->memref.size : 0;

+

+	if (function == SKS_FUNCTION_ENCRYPT)

+		_job.service            = CRYPTO_ENCRYPT;

+	else // SKS_FUNCTION_DECRYPT

+		_job.service            = CRYPTO_DECRYPT;

+

+	_job.family                 = CRYPTO_ALGOFAM_AES;

+	_job.mode                   = CRYPTO_ALGOMODE_ECB;

+	_job.operation_mode         = CRYPTO_OPERATIONMODE_START;

+

+

+	_job.cryptoKeyId            = _ptr->key1_id;

+	_job.keyLength              = _ptr->key1_len * 8;

+

+

+	SKS_HSM_DEBUG(" ==> _job.inputLength: %d\n", _job.inputLength);

+	SKS_HSM_DEBUG(" ==> _job.outputLength: %d\n", _job.outputLength);

+

+	Send_job(&_job);

+

+	return SKS_OK;

+}

+

+uint32_t mtk_AES_CBC_step(struct pkcs11_session *session,

+						  TEE_Param *in, TEE_Param *out,

+						  enum processing_func function,

+						  enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+	uint8_t next_IV[16] = {0};  // Used by decryption

+	job_struct _job = {0};

+	uint8_t *in_buf = NULL;

+	uint8_t *out_buf = NULL;

+

+	if (step == SKS_FUNC_STEP_FINAL)

+		return SKS_OK;

+

+	if ((session == NULL) || (out == NULL))

+		return SKS_BAD_PARAM;

+

+	_job.inputPtr               = in ? (uint8_t *)in->memref.buffer  : NULL;

+	_job.inputLength            = in ? in->memref.size : 0;

+	_job.secondaryInputPtr      = (uint8_t *)_ptr->CBC_IV;

+	_job.secondaryInputLength   = 16;

+

+	_job.outputPtr              = out ? (uint8_t *)out->memref.buffer : NULL;

+	_job.outputLength           = out ? out->memref.size : 0;

+	if (function == SKS_FUNCTION_ENCRYPT)

+		_job.service            = CRYPTO_ENCRYPT;

+	else // SKS_FUNCTION_DECRYPT

+		_job.service            = CRYPTO_DECRYPT;

+

+	_job.family                 = CRYPTO_ALGOFAM_AES;

+	_job.mode                   = CRYPTO_ALGOMODE_CBC;

+	_job.operation_mode         = CRYPTO_OPERATIONMODE_START;

+

+	_job.cryptoKeyId            = _ptr->key1_id;

+	_job.keyLength              = _ptr->key1_len * 8;

+

+	SKS_HSM_DEBUG(" ==> _job.inputLength: %d\n", _job.inputLength);

+	SKS_HSM_DEBUG(" ==> _job.secondaryInputLength: %d\n", _job.secondaryInputLength);

+	SKS_HSM_DEBUG(" ==> _job.outputLength: %d\n", _job.outputLength);

+

+	Send_job(&_job);

+

+	in_buf = (uint8_t *)_job.inputPtr;

+	out_buf = (uint8_t *)_job.outputPtr;

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		// Update IV[]

+		for (int i = 16; i >= 1; i--)

+		{

+			if (function == SKS_FUNCTION_ENCRYPT)

+				_ptr->CBC_IV[16 - i] = out_buf[_job.outputLength - i];

+			else

+				_ptr->CBC_IV[16 - i] = in_buf[_job.outputLength - i];

+		}

+	}

+

+	return SKS_OK;

+}

+

+uint32_t mtk_AES_CTR_step(struct pkcs11_session *session,

+						  TEE_Param *in, TEE_Param *out,

+						  enum processing_func function,

+						  enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+	job_struct _job = {0};

+

+	if (step == SKS_FUNC_STEP_FINAL)

+		return SKS_OK;

+

+	if ((session == NULL) || (in == NULL) || (out == NULL))

+		return SKS_BAD_PARAM;

+

+	_job.inputPtr               = in ? (uint8_t *)in->memref.buffer  : NULL;

+	_job.inputLength            = in ? in->memref.size : 0;

+	_job.secondaryInputPtr      = (uint8_t *)_ptr->CTR;

+	_job.secondaryInputLength   = 16;

+

+	_job.outputPtr              = out ? (uint8_t *)out->memref.buffer : NULL;

+	_job.outputLength           = out ? out->memref.size : 0;

+	if (function == SKS_FUNCTION_ENCRYPT)

+		_job.service            = CRYPTO_ENCRYPT;

+	else // SKS_FUNCTION_DECRYPT

+		_job.service            = CRYPTO_DECRYPT;

+

+	_job.family                 = CRYPTO_ALGOFAM_AES;

+	_job.mode                   = CRYPTO_ALGOMODE_CTR;

+	_job.operation_mode         = CRYPTO_OPERATIONMODE_START;

+

+	_job.cryptoKeyId            = _ptr->key1_id;

+	_job.keyLength              = _ptr->key1_len * 8;

+

+

+	SKS_HSM_DEBUG(" ==> _job.inputLength: %d\n", _job.inputLength);

+	SKS_HSM_DEBUG(" ==> _job.secondaryInputLength: %d\n", _job.secondaryInputLength);

+	SKS_HSM_DEBUG(" ==> _job.outputLength: %d\n", _job.outputLength);

+

+	Send_job(&_job);

+

+	// Update CTR ! _ptr->CTR[] += (_job.inputLength / 16);

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		// Update CTR !!!!

+		inc32(_ptr->CTR, (_job.inputLength / 16));

+	}

+

+	return SKS_OK;

+}

+

+uint32_t mtk_AES_GCM_step(struct pkcs11_session *session,

+				  TEE_Param *in, TEE_Param *out,

+				  enum processing_func function,

+				  enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+	uint8_t tmp_S[64] = {0};

+	uint8_t len_buf[16] = {0};

+	job_struct _job = {0};

+

+	SKS_HSM_DEBUG(" mtk_AES_GCM_step!! function: %d, step: %d  \n", function, step);

+

+	memcpy(tmp_S, _ptr->S, 16);

+

+	if (step != SKS_FUNC_STEP_FINAL)

+	{

+		_ptr->total_len += in->memref.size;

+

+		if (function == SKS_FUNCTION_DECRYPT)	// Hash before decrypt

+		{

+			ghash(_ptr->H, in->memref.buffer, in->memref.size, tmp_S);

+//			__SHOW_VAL("Ghash Decrypt input", out->memref.buffer, in->memref.size);

+//			__SHOW_VAL("Decrypt S", tmp_S, 16);

+		}

+

+		mtk_AES_CTR_step(session, in, out, function, step);

+

+		if (function == SKS_FUNCTION_ENCRYPT)   // Hash after encrypt

+		{

+			ghash(_ptr->H, out->memref.buffer, in->memref.size, tmp_S);

+//			__SHOW_VAL("Ghash Encrypt input", out->memref.buffer, in->memref.size);

+//			__SHOW_VAL("Encrypt S", tmp_S, 16);

+		}

+	}

+

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		memcpy(_ptr->S, tmp_S, 16);

+	}

+	else // (step == SKS_FUNC_STEP_FINAL) or (step == SKS_FUNC_STEP_ONESHOT)

+	{

+		PUT_BE64(len_buf, (_ptr->add_len) * 8);

+		PUT_BE64(len_buf + 8, _ptr->total_len * 8);

+		ghash(_ptr->H, len_buf, sizeof(len_buf), tmp_S);

+

+		/* T = MSB_t(GCTR_K(J_0, S)) */

+		_job.inputPtr               = tmp_S;

+		_job.inputLength            = 16;

+		_job.secondaryInputPtr      = _ptr->J0;

+		_job.secondaryInputLength   = 16;

+		_job.outputPtr              = len_buf;

+		_job.outputLength           = 16;

+

+		_job.service		    = CRYPTO_ENCRYPT;

+		_job.family                 = CRYPTO_ALGOFAM_AES;

+		_job.mode                   = CRYPTO_ALGOMODE_CTR;

+		_job.operation_mode         = CRYPTO_OPERATIONMODE_START;

+

+		_job.cryptoKeyId            = _ptr->key1_id;

+		_job.keyLength              = _ptr->key1_len * 8;

+

+		Send_job(&_job);

+

+		__SHOW_VAL("Fianl tag", len_buf, 16);

+

+		if (step == SKS_FUNC_STEP_ONESHOT)

+			memcpy(&out->memref.buffer[out->memref.size - 16], len_buf, 16);

+		else

+			memcpy(out->memref.buffer, len_buf, 16);

+

+	}

+

+	return SKS_OK;

+}

+

+uint32_t mtk_AES_CMAC_step(struct pkcs11_session *session,

+						   TEE_Param *in, TEE_Param *inout,

+						   enum processing_func function,

+						   enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+	job_struct _job = {0};

+	uint8_t veri_buf[64] = {0};

+	uint8_t _buf[16] = {0};

+	uint8_t *verify_buf = NULL;

+	uint8_t *out_buf = NULL;

+

+	if ((session == NULL))

+		return SKS_BAD_PARAM;

+

+	if (step == SKS_FUNC_STEP_ONESHOT)

+	{

+		_job.inputPtr               = in ? (uint8_t *)in->memref.buffer  : NULL;

+		_job.inputLength            = in ? in->memref.size : 0;

+	}

+	else if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		_job.inputPtr               = in ? (uint8_t *)in->memref.buffer  : NULL;

+		_job.inputLength            = in ? in->memref.size : 0;

+

+		if (_ptr->isFirstUpdate == true)

+		{

+			memcpy(_ptr->CMAC_Buf, &((uint8_t *)_job.inputPtr)[_job.inputLength - 16], 16);

+			_job.inputLength -= 16;

+

+			if (_job.inputLength == 0)

+				return SKS_OK;

+		}

+		else

+		{

+			memcpy(_buf, &((uint8_t *)_job.inputPtr)[_job.inputLength - 16], 16);

+

+			if (_job.inputLength > 16)

+			{

+				for (int i = _job.inputLength; i >= 16; i-- )

+					((uint8_t *)_job.inputPtr)[i] = ((uint8_t *)_job.inputPtr)[i - 16];

+			}

+

+			memcpy((uint8_t *)_job.inputPtr, _ptr->CMAC_Buf, 16);

+			memcpy(_ptr->CMAC_Buf, _buf, 16);

+		}

+	}

+	else // (step == SKS_FUNC_STEP_FINAL)

+	{

+		_job.inputPtr               = _ptr->CMAC_Buf;

+		_job.inputLength            = 16;

+	}

+

+

+	_job.secondaryInputPtr      = (uint8_t *)_ptr->CBC_IV;

+	_job.secondaryInputLength   = 16;

+

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		_job.outputPtr              = veri_buf;

+	}

+	else

+	{

+		if (function == SKS_FUNCTION_VERIFY)

+			_job.outputPtr  = veri_buf;

+		else

+			_job.outputPtr  = inout ? (uint8_t *)inout->memref.buffer : NULL;

+	}

+	_job.outputLength           = 16;

+

+	_job.service                = CRYPTO_MACGENERATE;   // No matter the function is sign or verify, HSM do the same thing.

+	_job.family                 = CRYPTO_ALGOFAM_AES;

+	_job.mode                   = CRYPTO_ALGOMODE_CMAC;

+

+	_job.cryptoKeyId            = _ptr->key1_id;

+	_job.keyLength              = _ptr->key1_len * 8;

+	SKS_HSM_DEBUG(" ==> _job.keyLength: %d\n", _job.keyLength);

+

+

+	_job.operation_mode         = _Step_to_OPmode(step, _ptr->isFirstUpdate);

+	SKS_HSM_DEBUG(" step: %d --> op_mode: %d  \n", step, _job.operation_mode);

+

+	SKS_HSM_DEBUG(" ==> _job.inputLength: %d\n", _job.inputLength);

+	SKS_HSM_DEBUG(" ==> _job.outputLength: %d\n", _job.outputLength);

+

+	Send_job(&_job);

+

+	if (step == SKS_FUNC_STEP_ONESHOT)

+		verify_buf = inout ? (uint8_t *)inout->memref.buffer : NULL;

+	else

+		verify_buf = in ? (uint8_t *)in->memref.buffer : NULL;

+

+	out_buf = (uint8_t *)_job.outputPtr;

+

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		// Update IV[]

+		memcpy(_ptr->CBC_IV, out_buf, 16);

+//		__SHOW_VAL("CMAC Updated IV[]", _ptr->CBC_IV, 16);

+	}

+	else

+	{

+		if (function == SKS_FUNCTION_VERIFY)

+		{

+			if (memcmp(verify_buf, out_buf, _job.outputLength) != 0)

+			{

+				SKS_HSM_ERROR(" CMAC%d verify ERROR!!  \n", _job.keyLength);

+				return SKS_ERROR;

+			}

+		}

+	}

+

+	if (_ptr->isFirstUpdate == true)

+		_ptr->isFirstUpdate = false;

+

+	return SKS_OK;

+}

+

+static uint32_t _merge_remain_data(TEE_Param *in, TEE_Param *new_in, MTK_HSM_State *mtk_ptr, uint32_t _block_size)

+{

+	uint8_t *in_buf     = (uint8_t *)in->memref.buffer;

+	uint32_t in_size    = in->memref.size;

+

+	uint32_t rlen       = mtk_ptr->SHA_remain_len;

+	uint32_t merged_len = in_size + rlen;

+

+	if (merged_len < _block_size)

+	{

+		memcpy(&mtk_ptr->SHA_buf[rlen], in_buf, in_size);

+		mtk_ptr->SHA_remain_len = merged_len;

+

+		SKS_HSM_DEBUG("  ==> No copy, new rlen: %d   \n", mtk_ptr->SHA_remain_len);

+		return SKS_OK;

+	}

+

+	if (rlen != 0)

+	{

+		new_in->memref.buffer = TEE_Malloc(merged_len, TEE_MALLOC_FILL_ZERO);

+		if (!new_in->memref.buffer)

+		{

+			SKS_HSM_ERROR(" %s [%d] Memory allocate fail!!  \n", __FUNCTION__, __LINE__);

+			return SKS_MEMORY;

+		}

+

+		memcpy(new_in->memref.buffer, mtk_ptr->SHA_buf, rlen);

+		memcpy((&new_in->memref.buffer[rlen]), in_buf, in_size);

+	}

+

+	rlen    = merged_len % _block_size;

+	in_size = merged_len - rlen;

+

+	if (new_in->memref.buffer != NULL)

+		memcpy(mtk_ptr->SHA_buf, &new_in->memref.buffer[in_size], rlen);

+	else

+		memcpy(mtk_ptr->SHA_buf, &in_buf[in_size], rlen);

+

+	new_in->memref.size     = in_size;

+	mtk_ptr->SHA_remain_len = rlen;

+	SKS_HSM_DEBUG("  ==> new in_size: %d   \n", new_in->memref.size);

+	SKS_HSM_DEBUG("  ==> new rlen: %d   \n", mtk_ptr->SHA_remain_len);

+

+	__SHOW_VAL("Remain data", mtk_ptr->SHA_buf, mtk_ptr->SHA_remain_len);

+

+	return SKS_OK;

+

+}

+

+#define SHA_MAX_OUTPUT_SIZE      (64)

+uint32_t mtk_SHA_step(uint32_t mecha_type,

+					  struct pkcs11_session *session,

+					  TEE_Param *in, TEE_Param *out,

+					  enum processing_func function,

+					  enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+

+	job_struct _job = {0};

+	uint8_t _block_size = 0;

+	uint8_t tmp_SHA_block[SHA_MAX_OUTPUT_SIZE] = {0};

+

+	TEE_Param new_in_body = {0};

+	uint8_t *out_buf = NULL;

+

+	switch (mecha_type)

+	{

+	case SKS_CKM_MTK_HSM_SHA1:

+		_job.family = CRYPTO_ALGOFAM_SHA1;

+		_block_size = 64;

+		break;

+

+	case SKS_CKM_MTK_HSM_SHA224:

+		_job.family = CRYPTO_ALGOFAM_SHA2_224;

+		_block_size = 64;

+		break;

+

+	case SKS_CKM_MTK_HSM_SHA256:

+		_job.family = CRYPTO_ALGOFAM_SHA2_256;

+		_block_size = 64;

+		break;

+

+	case SKS_CKM_MTK_HSM_SHA384:

+		_job.family = CRYPTO_ALGOFAM_SHA2_384;

+		_block_size = 128;

+		break;

+

+	case SKS_CKM_MTK_HSM_SHA512:

+		_job.family = CRYPTO_ALGOFAM_SHA2_512;

+		_block_size = 128;

+		break;

+

+	default:

+		return SKS_BAD_PARAM;

+		break;

+	}

+

+	// Process the data left last time that is not block size alignment.

+	if (step == SKS_FUNC_STEP_ONESHOT)

+	{

+		_job.inputPtr       = in ? (uint8_t *)in->memref.buffer  : NULL;

+		_job.inputLength    = in ? in->memref.size : 0;

+	}

+	else if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		if (_merge_remain_data(in, &new_in_body, _ptr, _block_size) != SKS_OK)

+			return SKS_MEMORY;

+

+		if (new_in_body.memref.size == 0)

+		{

+			return SKS_OK;

+		}

+

+		if (new_in_body.memref.buffer == NULL)

+			_job.inputPtr       = in ? (uint8_t *)in->memref.buffer  : NULL;

+		else

+			_job.inputPtr       = new_in_body.memref.buffer;

+

+		_job.inputLength    = new_in_body.memref.size;

+	}

+	else

+	{

+		if (_ptr->SHA_remain_len != 0)

+		{

+			_job.inputPtr       = _ptr->SHA_buf;

+			_job.inputLength    = _ptr->SHA_remain_len;

+		}

+		else

+		{

+			_job.inputPtr       = NULL;

+			_job.inputLength    = 0;

+		}

+	}

+

+	_job.secondaryInputPtr      = (uint8_t *)_ptr->SHA_IV;

+	_job.secondaryInputLength   = _block_size / 2;

+

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		_job.outputPtr          = tmp_SHA_block;

+		_job.outputLength       = _block_size / 2;

+	}

+	else

+	{

+		_job.outputPtr          = out ? (uint8_t *)out->memref.buffer : NULL;

+		_job.outputLength       = out ? out->memref.size : 0;

+	}

+

+	_job.service                = CRYPTO_HASH;

+	_job.mode                   = CRYPTO_ALGOMODE_NOT_SET;

+

+	_job.cryptoKeyId            = 0xFF;

+	_job.keyLength              = 0;

+

+	_job.operation_mode         = _Step_to_OPmode(step, _ptr->isFirstUpdate);

+

+	SKS_HSM_DEBUG(" ==> _job.secondaryInputLength: %d\n", _job.secondaryInputLength);

+	SKS_HSM_DEBUG(" ==> _job.outputLength: %d\n", _job.outputLength);

+

+	Send_job(&_job);

+

+	out_buf = (uint8_t *)_job.outputPtr;

+

+	__SHOW_VAL("out_buf", out_buf, 32);

+

+	if (step == SKS_FUNC_STEP_UPDATE)

+		memcpy(_ptr->SHA_IV, out_buf, _job.outputLength); // Update SHA_IV[]

+

+	if (_ptr->isFirstUpdate == true)

+		_ptr->isFirstUpdate = false;

+

+	if (new_in_body.memref.buffer != NULL)

+		TEE_Free(new_in_body.memref.buffer);

+

+	return SKS_OK;

+}

+

+uint32_t mtk_SHA256_HMAC_step(struct pkcs11_session *session,

+							  TEE_Param *in, TEE_Param *inout,

+							  enum processing_func function,

+							  enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+	uint8_t *verify_buf = NULL;

+	uint8_t *out_buf =    NULL;

+	job_struct _job = {0};

+	uint8_t _block_size = 64;

+	uint8_t veri_buf[64] = {0};

+

+	TEE_Param new_in_body = {0};

+

+	if ((session == NULL))

+		return SKS_BAD_PARAM;

+

+	// Process the data left last time that is not block size alignment.

+	if (step == SKS_FUNC_STEP_ONESHOT)

+	{

+		_job.inputPtr       = in ? (uint8_t *)in->memref.buffer  : NULL;

+		_job.inputLength    = in ? in->memref.size : 0;

+	}

+	else if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		if (_merge_remain_data(in, &new_in_body, _ptr, _block_size) != SKS_OK)

+			return SKS_MEMORY;

+

+		if (new_in_body.memref.size == 0)

+		{

+			return SKS_OK;

+		}

+

+		if (new_in_body.memref.buffer == NULL)

+			_job.inputPtr       = in ? (uint8_t *)in->memref.buffer  : NULL;

+		else

+			_job.inputPtr       = new_in_body.memref.buffer;

+

+		_job.inputLength    = new_in_body.memref.size;

+	}

+	else

+	{

+		if (_ptr->SHA_remain_len != 0)

+		{

+			_job.inputPtr       = _ptr->SHA_buf;

+			_job.inputLength    = _ptr->SHA_remain_len;

+		}

+		else

+		{

+			_job.inputPtr       = NULL;

+			_job.inputLength    = 0;

+		}

+	}

+

+	_job.secondaryInputPtr      = (uint8_t *)_ptr->SHA_IV;

+	_job.secondaryInputLength   = 32;

+

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		_job.outputPtr      = veri_buf;

+		_job.outputLength   = _block_size / 2;

+	}

+	else

+	{

+		if (function == SKS_FUNCTION_VERIFY)

+			_job.outputPtr  = veri_buf;

+		else

+			_job.outputPtr  = inout ? (uint8_t *)inout->memref.buffer : NULL;

+

+		_job.outputLength       = 32;

+	}

+

+	_job.service                = CRYPTO_MACGENERATE;   // No matter the function is sign or verify, HSM do the same thing.

+	_job.family                 = CRYPTO_ALGOFAM_SHA2_256;

+	_job.mode                   = CRYPTO_ALGOMODE_HMAC;

+

+	_job.cryptoKeyId            = _ptr->key1_id;

+	_job.keyLength              = _ptr->key1_len * 8;

+

+	_job.operation_mode         = _Step_to_OPmode(step, _ptr->isFirstUpdate);

+

+	SKS_HSM_DEBUG(" ==> _job.inputLength: %d\n", _job.inputLength);

+	SKS_HSM_DEBUG(" ==> _job.secondaryInputLength: %d\n", _job.secondaryInputLength);

+	SKS_HSM_DEBUG(" ==> _job.outputLength: %d\n", _job.outputLength);

+

+	Send_job(&_job);

+

+	if (step == SKS_FUNC_STEP_ONESHOT)

+		verify_buf = inout ? (uint8_t *)inout->memref.buffer : NULL;

+	else

+		verify_buf = in ? (uint8_t *)in->memref.buffer : NULL;

+

+	out_buf = (uint8_t *)_job.outputPtr;

+

+	__SHOW_VAL("out_buf", out_buf, 32);

+

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		// Update SHA_IV[]

+		memcpy(_ptr->SHA_IV, out_buf, 32);

+	}

+	else

+	{

+		if (function == SKS_FUNCTION_VERIFY)

+		{

+			__SHOW_VAL("Verification out_buf", verify_buf, _job.outputLength);

+			if (memcmp(verify_buf, out_buf, _job.outputLength) != 0)

+			{

+				SKS_HSM_ERROR(" HMAC256 verify ERROR!!  \n");

+				return SKS_ERROR;

+			}

+		}

+	}

+

+	if (_ptr->isFirstUpdate == true)

+		_ptr->isFirstUpdate = false;

+

+	if (new_in_body.memref.buffer != NULL)

+		TEE_Free(new_in_body.memref.buffer);

+

+	return SKS_OK;

+}

+

+uint32_t mtk_SHA384_HMAC_step(struct pkcs11_session *session,

+							  TEE_Param *in, TEE_Param *inout,

+							  enum processing_func function,

+							  enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+	job_struct _job = {0};

+	uint8_t _block_size = 128;

+	uint8_t veri_buf[64] = {0};

+

+	TEE_Param new_in_body = {0};

+	uint8_t *verify_buf = NULL;

+	uint8_t *out_buf = NULL;

+

+	if ((session == NULL))

+		return SKS_BAD_PARAM;

+

+	// Process the data left last time that is not block size alignment.

+	if (step == SKS_FUNC_STEP_ONESHOT)

+	{

+		_job.inputPtr       = in ? (uint8_t *)in->memref.buffer  : NULL;

+		_job.inputLength    = in ? in->memref.size : 0;

+	}

+	else if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		if (_merge_remain_data(in, &new_in_body, _ptr, _block_size) != SKS_OK)

+			return SKS_MEMORY;

+

+		if (new_in_body.memref.size == 0)

+		{

+			return SKS_OK;

+		}

+

+		if (new_in_body.memref.buffer == NULL)

+			_job.inputPtr       = in ? (uint8_t *)in->memref.buffer  : NULL;

+		else

+			_job.inputPtr       = new_in_body.memref.buffer;

+

+		_job.inputLength    = new_in_body.memref.size;

+	}

+	else

+	{

+		if (_ptr->SHA_remain_len != 0)

+		{

+			_job.inputPtr       = _ptr->SHA_buf;

+			_job.inputLength    = _ptr->SHA_remain_len;

+		}

+		else

+		{

+			_job.inputPtr       = NULL;

+			_job.inputLength    = 0;

+		}

+	}

+

+	_job.secondaryInputPtr      = (uint8_t *)_ptr->SHA_IV;

+	_job.secondaryInputLength   = 64;  // A specific length of HMAC-384

+

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		_job.outputPtr      = veri_buf;

+		_job.outputLength   = _block_size / 2;

+	}

+	else

+	{

+		if (function == SKS_FUNCTION_VERIFY)

+			_job.outputPtr  = veri_buf;

+		else

+			_job.outputPtr  = inout ? (uint8_t *)inout->memref.buffer : NULL;

+

+		_job.outputLength       = 48;

+	}

+

+	_job.service                = CRYPTO_MACGENERATE;   // No matter the function is sign or verify, HSM do the same thing.

+	_job.family                 = CRYPTO_ALGOFAM_SHA2_384;

+	_job.mode                   = CRYPTO_ALGOMODE_HMAC;

+

+	_job.cryptoKeyId            = _ptr->key1_id;

+	_job.keyLength              = _ptr->key1_len * 8;

+

+	_job.operation_mode         = _Step_to_OPmode(step, _ptr->isFirstUpdate);

+

+	SKS_HSM_DEBUG(" ==> _job.inputLength: %d\n", _job.inputLength);

+	SKS_HSM_DEBUG(" ==> _job.secondaryInputLength: %d\n", _job.secondaryInputLength);

+	SKS_HSM_DEBUG(" ==> _job.outputLength: %d\n", _job.outputLength);

+

+	Send_job(&_job);

+

+	if (step == SKS_FUNC_STEP_ONESHOT)

+		verify_buf = inout ? (uint8_t *)inout->memref.buffer : NULL;

+	else

+		verify_buf = in ? (uint8_t *)in->memref.buffer : NULL;

+

+	out_buf = (uint8_t *)_job.outputPtr;

+

+	__SHOW_VAL("out_buf", out_buf, _job.outputLength);

+

+	if (step == SKS_FUNC_STEP_UPDATE)

+	{

+		// Update SHA_IV[]

+		memcpy(_ptr->SHA_IV, out_buf, _job.outputLength);

+	}

+	else

+	{

+		if (function == SKS_FUNCTION_VERIFY)

+		{

+			__SHOW_VAL("Verification out_buf", verify_buf, _job.outputLength);

+			if (memcmp(verify_buf, out_buf, _job.outputLength) != 0)

+			{

+    			SKS_HSM_ERROR(" HMAC384 verify ERROR!!  \n");

+				return SKS_ERROR;

+			}

+		}

+	}

+

+	if (_ptr->isFirstUpdate == true)

+		_ptr->isFirstUpdate = false;

+

+	if (new_in_body.memref.buffer != NULL)

+		TEE_Free(new_in_body.memref.buffer);

+

+	return SKS_OK;

+}

+

+uint32_t mtk_ECDSA_step(struct pkcs11_session *session,

+									 TEE_Param *in, TEE_Param *inout,

+									 enum processing_func function,

+									 enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+	job_struct _job = {0};

+	uint8_t r[64] = {0};

+	uint8_t s[64] = {0};

+	uint8_t *out_buf = NULL;

+	uint8_t rs_len = 0;

+

+	if ((session == NULL) || (in == NULL))

+		return SKS_BAD_PARAM;

+

+	_job.inputPtr               = in ? (uint8_t *)in->memref.buffer  : NULL;

+	_job.inputLength            = in ? in->memref.size : 0;

+

+	if (function == SKS_FUNCTION_SIGN)

+	{

+		_job.outputPtr              = r;

+		_job.outputLength           = inout ? (inout->memref.size / 2): 0;

+		_job.secondaryOutputPtr     = s;

+		_job.secondaryOutputLength  = inout ? (inout->memref.size / 2): 0;

+	}

+	else // (function == SKS_FUNCTION_VERIFY)

+	{

+		uint8_t rs_len				= inout ? (inout->memref.size / 2): 0;

+		uint8_t *in_buf2			= inout ? (uint8_t *)inout->memref.buffer  : NULL;

+		memcpy(r, in_buf2, rs_len);

+		memcpy(s, &in_buf2[rs_len], rs_len);

+

+		_job.secondaryInputPtr      = r;

+		_job.secondaryInputLength   = rs_len;

+		_job.tertiaryInputPtr	    = s;

+		_job.tertiaryInputLength    = rs_len;

+	}

+

+	if (function == SKS_FUNCTION_SIGN)

+		_job.service                = CRYPTO_SIGNATUREGENERATE;

+	else

+		_job.service                = CRYPTO_SIGNATUREVERIFY;

+

+	_job.family                 = CRYPTO_ALGOFAM_ECCNIST;

+	_job.mode                   = CRYPTO_ALGOMODE_NOT_SET;

+

+	_job.cryptoKeyId            = _ptr->key1_id;

+	_job.keyLength              = _ptr->key1_len* 8;

+

+	_job.operation_mode         = _Step_to_OPmode(step, _ptr->isFirstUpdate);

+

+	SKS_HSM_DEBUG(" ==> _job.inputLength: %d\n", _job.inputLength);

+	if (function == SKS_FUNCTION_SIGN)

+		SKS_HSM_DEBUG(" ==> _job.outputLength: %d\n", _job.outputLength);

+	else

+		SKS_HSM_DEBUG(" ==> _job.secondaryInputLength: %d\n", _job.secondaryInputLength);

+

+

+	Send_job(&_job);

+

+	out_buf = inout ? (uint8_t *)inout->memref.buffer : NULL;

+	rs_len   = _job.outputLength;

+

+	__SHOW_VAL("r", r, rs_len);

+	__SHOW_VAL("s", s, rs_len);

+

+	if (function == SKS_FUNCTION_SIGN)

+	{

+		// Merge 2 output buffer into 1

+		memcpy(out_buf, r, rs_len);

+		memcpy(&out_buf[rs_len], s, rs_len);

+	}

+

+	return SKS_OK;

+}

+

+uint32_t mtk_ECDSA_SHA_step(struct pkcs11_session *session,

+									 TEE_Param *in, TEE_Param *inout,

+									 enum processing_func function,

+									 enum processing_step step)

+{

+	MTK_HSM_State *_ptr = session->processing->mtk_hsm_handle;

+	uint32_t mecha_type = session->processing->mecha_type;

+	uint32_t digesting_mecha_type = 0;

+	uint8_t digestedOutBuf[512] = {0};

+	uint32_t digestedDataLen    = 0;

+	TEE_Param digestedOut       = {0};

+

+	if ((session == NULL) || (in == NULL))

+		return SKS_BAD_PARAM;

+

+	// ASSERT SHA one-shot only

+

+	if (step != SKS_FUNC_STEP_ONESHOT)

+	{

+		SKS_HSM_ERROR(" ASSERT SHA one-shot only!! \n");

+		return SKS_BAD_PARAM;

+	}

+

+	switch (mecha_type)

+	{

+	case SKS_CKM_MTK_HSM_ECDSA_SHA224:

+		digesting_mecha_type = SKS_CKM_MTK_HSM_SHA224;

+		digestedOut.memref.size = 28;

+		break;

+

+	case SKS_CKM_MTK_HSM_ECDSA_SHA256:

+		digesting_mecha_type = SKS_CKM_MTK_HSM_SHA256;

+		digestedOut.memref.size = 32;

+		break;

+

+	case SKS_CKM_MTK_HSM_ECDSA_SHA384:

+		digesting_mecha_type = SKS_CKM_MTK_HSM_SHA384;

+		digestedOut.memref.size = 48;

+		break;

+	case SKS_CKM_MTK_HSM_ECDSA_SHA512:

+		digesting_mecha_type = SKS_CKM_MTK_HSM_SHA512;

+		digestedOut.memref.size = 64;

+		break;

+	default:

+	case SKS_CKM_MTK_HSM_ECDSA_SHA1:

+		digesting_mecha_type = SKS_CKM_MTK_HSM_SHA1;

+		digestedOut.memref.size = 20;

+		break;

+	}

+	digestedOut.memref.buffer = digestedOutBuf;

+

+	mtk_SHA_step(digesting_mecha_type, session, in, &digestedOut, function, step);

+	mtk_ECDSA_step(session, &digestedOut, inout, function, step);

+

+	return SKS_OK;

+}

+

+uint32_t mtk_generate_random(TEE_Param *out)

+{

+	job_struct _job = {0};

+

+	if (out == NULL)

+		return SKS_BAD_PARAM;

+

+	_job.outputPtr              = (uint8_t *)out->memref.buffer;

+	_job.outputLength           = out->memref.size;

+

+	_job.service                = CRYPTO_RANDOMGENERATE;

+	_job.family                 = CRYPTO_ALGOFAM_RNG;

+	_job.mode                   = CRYPTO_ALGOMODE_NOT_SET;

+

+	SKS_HSM_DEBUG(" ==> _job.outputLength: %d\n", _job.outputLength);

+

+	Send_job(&_job);

+

+	__SHOW_VAL("TRNG val", _job.outputPtr, _job.outputLength);

+

+	return SKS_OK;

+}

+

+uint32_t mtk_dump_hsm_log(void)

+{

+	dump_hsm_log();

+

+	return 0;

+}

+

+TEE_Result Send_job(job_struct *pjob)

+{

+	TEE_TASessionHandle cryp_session;

+	TEE_Result res = TEE_SUCCESS;

+	uint32_t origin = 0;

+	TEE_Param params[4];

+	TEE_UUID uuid = PTA_MBOX_UUID;

+	int hsm_ret = -1;

+

+	uint32_t types = TEE_PARAM_TYPES( TEE_PARAM_TYPE_VALUE_INPUT

+					, TEE_PARAM_TYPE_VALUE_INPUT

+					, TEE_PARAM_TYPE_VALUE_INPUT

+					, TEE_PARAM_TYPE_VALUE_INPUT);

+

+	TEE_MemFill(params, 0, sizeof(TEE_Param) * 4);

+	params[0].value.a = (uint32_t)pjob;

+	params[0].value.b = (uint32_t)sizeof(job_struct);

+	params[1].value.a = (uint32_t)&hsm_ret;

+

+	res = TEE_OpenTASession(&uuid, 0, types, params, &cryp_session,

+							&origin);

+

+	if (res != TEE_SUCCESS) {

+		SKS_HSM_ERROR("rpc - TEE_OpenTASession returned 0x%x\n",

+			 (unsigned int)res);

+		return res;

+	}

+

+	res = TEE_InvokeTACommand(cryp_session, 0, PTA_CMD_HSM_SEND_JOB, types, params, &origin);

+	if (res != TEE_SUCCESS) {

+		SKS_HSM_ERROR("rpc_call_cryp - TEE_InvokeTACommand returned 0x%x\n",

+			 (unsigned int)res);

+	}

+

+	TEE_CloseTASession(cryp_session);

+

+	return res;

+

+}

+

+TEE_Result dump_hsm_log(void)

+{

+	TEE_TASessionHandle cryp_session;

+	TEE_Result res = TEE_SUCCESS;

+	uint32_t origin = 0;

+	TEE_Param params[4];

+	TEE_UUID uuid = PTA_MBOX_UUID;

+	int hsm_ret = -1;

+

+	uint32_t types = TEE_PARAM_TYPES( TEE_PARAM_TYPE_VALUE_INPUT

+					, TEE_PARAM_TYPE_VALUE_INPUT

+					, TEE_PARAM_TYPE_VALUE_INPUT

+					, TEE_PARAM_TYPE_VALUE_INPUT);

+

+	TEE_MemFill(params, 0, sizeof(TEE_Param) * 4);

+

+	res = TEE_OpenTASession(&uuid, 0, types, params, &cryp_session,

+							&origin);

+

+	if (res != TEE_SUCCESS) {

+		SKS_HSM_ERROR("rpc - TEE_OpenTASession returned 0x%x\n",

+			 (unsigned int)res);

+		return res;

+	}

+

+	res = TEE_InvokeTACommand(cryp_session, 0, PTA_CMD_HSM_DUMP_LOG, types, params, &origin);

+	if (res != TEE_SUCCESS) {

+		SKS_HSM_ERROR("rpc_call_cryp - TEE_InvokeTACommand returned 0x%x\n",

+			 (unsigned int)res);

+	}

+

+	TEE_CloseTASession(cryp_session);

+

+	return res;

+

+}

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.h
new file mode 100644
index 0000000..f27b4be
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_hsm.h
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef __PROCESSING_MTK_HSM_H
+#define __PROCESSING_MTK_HSM_H
+
+#include <assert.h>
+#include <sks_internal_abi.h>
+#include <sks_ta.h>
+#include <string.h>
+#include <tee_api_defines.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <util.h>
+
+#include "attributes.h"
+#include "object.h"
+#include "pkcs11_token.h"
+#include "pkcs11_attributes.h"
+#include "processing.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+
+#define PTA_MBOX_UUID     {0x12345678, 0x1234, 0x5678, {0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89}}
+
+extern uint32_t mtk_AES_ECB_init(struct pkcs11_session *session,
+                                 struct sks_attribute_head *proc_params,
+                                 struct sks_object *key);
+extern uint32_t mtk_AES_CBC_init(struct pkcs11_session *session,
+                                 struct sks_attribute_head *proc_params,
+                                 struct sks_object *key);
+extern uint32_t mtk_AES_CTR_init(struct pkcs11_session *session,
+                                 struct sks_attribute_head *proc_params,
+                                 struct sks_object *key);
+extern uint32_t mtk_AES_GCM_init(struct pkcs11_session *session,
+                                 struct sks_attribute_head *proc_params,
+                                 struct sks_object *key);
+extern uint32_t mtk_AES_CMAC_init(struct pkcs11_session *session,
+                                 struct sks_attribute_head *proc_params,
+                                 struct sks_object *key);
+extern uint32_t mtk_HMAC_init(struct pkcs11_session *session,
+                                 struct sks_attribute_head *proc_params,
+                                 struct sks_object *key);
+extern uint32_t mtk_ECDSA_init(struct pkcs11_session *session,
+                               struct sks_attribute_head *proc_params,
+                               struct sks_object *key);
+extern uint32_t mtk_SHA_init(struct pkcs11_session *session,
+                             struct sks_attribute_head *proc_params);
+extern uint32_t mtk_ECDSA_SHA_init(struct pkcs11_session *session,
+                               struct sks_attribute_head *proc_params,
+                               struct sks_object *key);
+extern uint32_t mtk_SHA_step(uint32_t mecha_type,
+                             struct pkcs11_session *session,
+                             TEE_Param *in, TEE_Param *out,
+                             enum processing_func function,
+                             enum processing_step step);
+
+extern uint32_t mtk_AES_ECB_step(struct pkcs11_session *session,
+                                 TEE_Param *in, TEE_Param *out,
+                                 enum processing_func function,
+                                 enum processing_step step);
+extern uint32_t mtk_AES_CBC_step(struct pkcs11_session *session,
+                                 TEE_Param *in, TEE_Param *out,
+                                 enum processing_func function,
+                                 enum processing_step step);
+extern uint32_t mtk_AES_CTR_step(struct pkcs11_session *session,
+                                 TEE_Param *in, TEE_Param *out,
+                                 enum processing_func function,
+                                 enum processing_step step);
+extern uint32_t mtk_AES_GCM_step(struct pkcs11_session *session,
+                                 TEE_Param *in, TEE_Param *out,
+                                 enum processing_func function,
+                                 enum processing_step step);
+extern uint32_t mtk_AES_CMAC_step(struct pkcs11_session *session,
+                                  TEE_Param *in, TEE_Param *out,
+                                  enum processing_func function,
+                                  enum processing_step step);
+extern uint32_t mtk_SHA256_HMAC_step(struct pkcs11_session *session,
+                                     TEE_Param *in, TEE_Param *inout,
+                                     enum processing_func function,
+                                     enum processing_step step);
+extern uint32_t mtk_SHA384_HMAC_step(struct pkcs11_session *session,
+                                     TEE_Param *in, TEE_Param *inout,
+                                     enum processing_func function,
+                                     enum processing_step step);
+extern uint32_t mtk_ECDSA_step(struct pkcs11_session *session,
+                                     TEE_Param *in, TEE_Param *inout,
+                                     enum processing_func function,
+                                     enum processing_step step);
+extern uint32_t mtk_ECDSA_SHA_step(struct pkcs11_session *session,
+                                     TEE_Param *in, TEE_Param *inout,
+                                     enum processing_func function,
+                                     enum processing_step step);
+
+extern uint32_t mtk_generate_random(TEE_Param *out);
+
+extern uint32_t mtk_dump_hsm_log(void);
+
+#endif // __PROCESSING_MTK_HSM_H
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_key.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_key.c
new file mode 100644
index 0000000..3136a1d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_key.c
@@ -0,0 +1,902 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#include <assert.h>
+#include <sks_internal_abi.h>
+#include <sks_ta.h>
+#include <string.h>
+#include <tee_api_defines.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <util.h>
+#include <tee_api.h>
+
+#include "attributes.h"
+#include "object.h"
+#include "pkcs11_token.h"
+#include "pkcs11_attributes.h"
+#include "processing.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+#include "mtk_key.h"
+#include "sks_hsm_debug.h"
+
+#define KEY_TABLE_STRING "key_table"
+#define KEY_TABLE_SIZE_STRING "key_tbl_size"
+
+#define ALIGN_TO_16(x) (((x+15)>>4)<<4)
+
+static int pta_gen_sym_key(int size, int *pkey_id);
+static int pta_get_key_blob(uint8_t *dst, int size, int key_id, int algo_id, int *pblobsize);
+static int pta_get_key_table(uint8_t *dst, int size, int *ptablesize);
+static int pta_gen_key_pair(int size, int uECC_curve_id, int *pkey_id);
+static int pta_rebuild_key_table(uint8_t *buffer, int tablesize);
+static int pta_rebuild_key_blob(uint8_t *buffer, int blob_size, int key_id);
+static int pta_import_key(uint8_t *pkeybuffer, uint32_t size, int *pkeyid, int algo_id);
+static int pta_export_key(uint8_t *pblob, uint32_t blobsize, uint8_t *ppubkey, uint32_t *ppubkeylength);
+static int pta_delete_key(int key_id);
+
+static int _create_file(uint8_t *pPOName, uint32_t namelen)
+{
+	TEE_ObjectHandle ohKey = TEE_HANDLE_NULL;
+	TEE_ObjectHandle hPersistObj = TEE_HANDLE_NULL;
+	TEE_Result nResult = TEE_SUCCESS;
+
+
+	nResult = TEE_CreatePersistentObject(
+	              TEE_STORAGE_PRIVATE,
+	              pPOName, namelen,
+	              (TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE | TEE_DATA_FLAG_ACCESS_WRITE_META),
+	              ohKey,
+	              TEE_HANDLE_NULL, 0,
+	              &hPersistObj);
+
+	if (nResult != 0)
+	{
+		if (nResult != TEE_ERROR_ITEM_NOT_FOUND)
+			SKS_HSM_ERROR("TEE_CreatePersistentObject error, nResult 0x%x!!!\n", nResult);
+		return nResult;
+	}
+
+	TEE_CloseObject(hPersistObj);
+
+	return nResult;
+}
+
+static int _delete_file(uint8_t *pPOName, uint32_t namelen)
+{
+	TEE_ObjectHandle hPersistObj = TEE_HANDLE_NULL;
+	TEE_Result nResult = TEE_SUCCESS;
+
+	nResult = TEE_OpenPersistentObject(
+	              TEE_STORAGE_PRIVATE,
+	              pPOName, namelen,
+	              TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE | TEE_DATA_FLAG_ACCESS_WRITE_META,
+	              &hPersistObj);
+
+	if (nResult != 0)
+	{
+		if (nResult != TEE_ERROR_ITEM_NOT_FOUND)
+			SKS_HSM_ERROR("TEE_OpenPersistentObject error, nResult 0x%x!!!\n", nResult);
+		return nResult;
+	}
+
+	TEE_CloseAndDeletePersistentObject(hPersistObj);
+
+	return TEE_SUCCESS;
+
+}
+
+static int _write_file(uint8_t *pPOName, uint32_t namelen, uint8_t *Content, uint32_t size)
+{
+	TEE_ObjectHandle hPersistObj = TEE_HANDLE_NULL;
+	TEE_Result nResult = TEE_SUCCESS;
+
+	nResult = TEE_OpenPersistentObject(
+	              TEE_STORAGE_PRIVATE,
+	              pPOName, namelen,
+	              TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE | TEE_DATA_FLAG_ACCESS_WRITE_META,
+	              &hPersistObj);
+
+	if (nResult != 0)
+	{
+		if (nResult != TEE_ERROR_ITEM_NOT_FOUND)
+			SKS_HSM_ERROR("TEE_OpenPersistentObject error, nResult 0x%x!!!\n", nResult);
+		return nResult;
+	}
+
+	nResult = TEE_WriteObjectData(
+	              hPersistObj,
+	              (void*)Content,
+	              size);
+
+	if (nResult != 0)
+	{
+		SKS_HSM_ERROR("TEE_WriteObjectData error, nResult 0x%x!!!\n", nResult);
+		return nResult;
+	}
+
+	TEE_CloseObject(hPersistObj);
+
+	return nResult;
+}
+static int _read_file(uint8_t *pPOName, uint32_t namelen, uint8_t *Content, uint32_t size)
+{
+	TEE_ObjectHandle hPersistObj = TEE_HANDLE_NULL;
+	TEE_Result nResult = TEE_SUCCESS;
+	uint32_t count = 0;
+	uint32_t rsize = size;
+
+	nResult = TEE_OpenPersistentObject(
+	              TEE_STORAGE_PRIVATE,
+	              pPOName, namelen,
+	              TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE | TEE_DATA_FLAG_ACCESS_WRITE_META,
+	              &hPersistObj);
+
+	if (nResult != 0)
+	{
+		if (nResult != TEE_ERROR_ITEM_NOT_FOUND)
+			SKS_HSM_ERROR("TEE_CreatePersistentObject error, nResult 0x%x!!!\n", nResult);
+		return nResult;
+	}
+
+	nResult = TEE_ReadObjectData(hPersistObj, Content, rsize, &count);
+	if ((rsize != count) || (nResult != 0))
+	{
+		SKS_HSM_ERROR("error rsize 0x%x, count 0x%x!!!\n", rsize, count);
+		SKS_HSM_ERROR("nResult 0x%x!!!\n", nResult);
+		TEE_CloseObject(hPersistObj);
+		return -1;
+	}
+	TEE_CloseObject(hPersistObj);
+
+	return nResult;
+}
+
+char *itoa_32(int n, char *str, int radix)
+{
+	char digit[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	char *p = str;
+	char *head = str;
+	unsigned int val;
+
+	if (str == NULL) {
+		return NULL;
+	}
+
+	if (n == 0) {
+		*p++ = '0';
+		*p = 0;
+		return str;
+	}
+
+	if (radix == 10 && n < 0)
+		val = (-n);
+	else
+		val = n;
+
+	while (val) {
+		*p++ = digit[val % radix];
+		val /= radix;
+	}
+
+	if (radix == 10 && n < 0)
+		*p++ = '-';
+	*p = 0;
+	for (--p; head < p ; ++head, --p)
+	{
+		char temp = *head;
+		*head = *p;
+		*p = temp;
+	}
+	return str;
+}
+
+static void _make_blob_filename(uint8_t *dst, int key_id)
+{
+	int8_t *prefix = "blob_";
+	int8_t strkeyid[64] = {0};
+
+	if (dst == NULL) {
+		return;
+	}
+	itoa_32(key_id, strkeyid, 16);
+
+	memcpy(dst, prefix, strlen(prefix));
+	memcpy(dst + strlen((char *)prefix), strkeyid, strlen(strkeyid));
+}
+
+static void _write_key_blob_to_storage(uint8_t *buffer, uint32_t blobsize, int key_id)
+{
+	int8_t *prefix = "blob_";
+	int8_t pPOName[128] = {0};
+	uint32_t namelen = 0;
+
+	if (buffer == NULL) {
+		return;
+	}
+	_make_blob_filename(pPOName, key_id);
+
+	namelen = strlen((char *)pPOName);
+
+	_create_file(pPOName, namelen);
+	_write_file(pPOName, namelen, buffer, blobsize);
+}
+
+
+static void _remove_key_blob_from_storage(key_id)
+{
+	int8_t *prefix = "blob_";
+	int8_t pPOName[128] = {0};
+	uint32_t namelen = 0;
+
+	_make_blob_filename(pPOName, key_id);
+
+	namelen = strlen((char *)pPOName);
+	_delete_file(pPOName, namelen);
+
+}
+
+static void _write_key_table_to_storage(uint8_t *buffer, uint32_t tablesize)
+{
+	int8_t pTableName[] = KEY_TABLE_STRING;
+	int8_t pTableSizeName[] = KEY_TABLE_SIZE_STRING;
+	uint32_t namelen = 0;
+
+	if (buffer == NULL) {
+		return;
+	}
+	namelen = strlen((char *)pTableName);
+	_create_file(pTableName, namelen);
+	_write_file(pTableName, namelen, buffer, tablesize);
+
+	namelen = strlen((char *)pTableSizeName);
+	_create_file(pTableSizeName, namelen);
+	_write_file(pTableSizeName, namelen, &tablesize, sizeof(uint32_t));
+}
+
+static void _read_key_table_size(uint32_t *ptablesize)
+{
+	int8_t pTableSizeName[128] = KEY_TABLE_SIZE_STRING;
+	uint8_t Content[4] = {0};
+	uint32_t dstsize = sizeof(Content);
+	uint32_t namelen = 0;
+
+	if (ptablesize == NULL) {
+		return;
+	}
+	namelen = strlen((char *)pTableSizeName);
+	_read_file(pTableSizeName, namelen, Content, dstsize);
+
+	*ptablesize = *((uint32_t *)Content);
+}
+
+static void _read_key_table(uint8_t *buffer, uint32_t tablesize)
+{
+	int8_t pTableName[128] = KEY_TABLE_STRING;
+	uint32_t namelen = 0;
+
+	namelen = strlen((char *)pTableName);
+	_read_file(pTableName, namelen, buffer, tablesize);
+}
+
+static void _read_key_blob(uint8_t *buffer, uint32_t buffersize, int key_id)
+{
+	int8_t pBlobName[128] = {0};
+	uint32_t namelen = 0;
+
+	_make_blob_filename(pBlobName, key_id);
+
+	namelen = strlen((char *)pBlobName);
+	_read_file(pBlobName, namelen, buffer, buffersize);
+}
+
+static int _get_key_info_in_table(key_table *ptbl, int idx, uint32_t *pkeyid, uint32_t *pkeysize)
+{
+	if (ptbl == NULL) {
+		return -1;
+	}
+	*pkeyid = ptbl->slot[idx].id;
+	*pkeysize = ptbl->slot[idx].key_w.size;
+	return 0;
+}
+
+static inline void _estimate_blob_size(uint32_t key_size, uint32_t *pblobsize)
+{
+	*pblobsize = ALIGN_TO_16(key_size) + BLOB_MAC_SIZE + BLOB_HEADER_SIZE;
+}
+
+static inline int _check_symmetric_key_size_valid(uint32_t size)
+{
+	return (size == 16) || (size == 24) || (size == 32) || (size == 48);
+}
+
+int mtk_delete_key(struct sks_object *object)
+{
+	uint8_t buffer[sizeof(key_table)] = {0};
+	int tablesize = 0;
+	uint32_t rv = 0;
+	int key_id = 0;
+	int key_id_size = sizeof(key_id);
+
+	if (object == NULL)
+		 return SKS_CKR_ARGUMENTS_BAD;
+
+	rv = get_attribute(object->attributes, SKS_CKA_HSM_KEY_ID, &key_id, &key_id_size);
+	if (rv != 0) /* not mtk key object */
+		return SKS_CKR_ARGUMENTS_BAD;
+	if (pta_delete_key(key_id) != TEE_SUCCESS)
+		return TEE_ERROR_GENERIC;
+
+	_remove_key_blob_from_storage(key_id);
+
+	if (pta_get_key_table(buffer, sizeof(buffer), &tablesize) != TEE_SUCCESS)
+		return TEE_ERROR_GENERIC;
+
+	_write_key_table_to_storage(buffer, tablesize);
+
+	return TEE_SUCCESS;
+}
+
+int mtk_generate_symmetric_key(int size, int *pkeyid)
+{
+	int key_id = 0;
+	uint8_t buffer[sizeof(key_table)] = {0};
+	int blobsize = 0;
+	int tablesize = 0;
+
+	int _rv = _check_symmetric_key_size_valid(size);
+	SKS_HSM_DEBUG("  %s [%d] size: %d, rv: %d \n", __FUNCTION__, __LINE__, size, _rv);
+	if (!_check_symmetric_key_size_valid(size))
+		return TEE_ERROR_GENERIC;
+
+	if (pkeyid == NULL)
+		return TEE_ERROR_GENERIC;
+
+	if (pta_gen_sym_key(size, &key_id) != TEE_SUCCESS)
+		return TEE_ERROR_GENERIC;
+
+	if (pta_get_key_blob(buffer, sizeof(buffer), key_id, KEY_ALGO_ID_AES, &blobsize) != TEE_SUCCESS)
+		return TEE_ERROR_GENERIC;
+
+	_write_key_blob_to_storage(buffer, blobsize, key_id);
+
+	if (pta_get_key_table(buffer, sizeof(buffer), &tablesize) != TEE_SUCCESS)
+		return TEE_ERROR_GENERIC;
+
+	_write_key_table_to_storage(buffer, tablesize);
+
+	*pkeyid = key_id;
+
+	return TEE_SUCCESS;
+}
+
+int mtk_generate_ecc_key_pair(int size, int curve_id, int *pkeyid)
+{
+	int key_id = 0;
+	uint8_t buffer[sizeof(key_table)] = {0};
+	int blobsize = 0;
+	int tablesize = 0;
+	int uECC_curve_id = curve_id;
+
+	if (pkeyid == NULL)
+		return TEE_ERROR_GENERIC;
+
+	if (pta_gen_key_pair(size, uECC_curve_id, &key_id) != TEE_SUCCESS)
+		return TEE_ERROR_GENERIC;
+
+	if (pta_get_key_blob(buffer, sizeof(buffer), key_id, KEY_ALGO_ID_ECC, &blobsize) != TEE_SUCCESS)
+		return TEE_ERROR_GENERIC;
+
+	_write_key_blob_to_storage(buffer, blobsize, key_id);
+
+	if (pta_get_key_table(buffer, sizeof(buffer), &tablesize) != TEE_SUCCESS)
+		return TEE_ERROR_GENERIC;
+
+	_write_key_table_to_storage(buffer, tablesize);
+
+	*pkeyid = key_id;
+
+	return TEE_SUCCESS;
+}
+
+
+int mtk_rebuild_key_table(void)
+{
+	uint8_t *table_buffer = NULL;
+	uint8_t *blob_buffer = NULL;
+	int table = 0;
+	uint32_t tablesize = 0, blob_size = 0, key_size = 0, key_id = 0;
+	uint32_t maxblobsize = MAX_BLOB_SIZE;
+	key_table *ptable = NULL;
+
+	_read_key_table_size(&tablesize);
+
+	if (tablesize <= 0) {
+		SKS_HSM_ERROR("[%s][%d] invalid table size : %d\n", __FUNCTION__, __LINE__, tablesize);
+		goto fail;
+	}
+
+	table_buffer = TEE_Malloc(tablesize, TEE_MALLOC_FILL_ZERO);
+	if (table_buffer == NULL) {
+		SKS_HSM_ERROR("[%s][%d] allocate memory fail\n", __FUNCTION__, __LINE__);
+		goto fail;
+	}
+
+	blob_buffer = TEE_Malloc(maxblobsize, TEE_MALLOC_FILL_ZERO);
+	if (blob_buffer == NULL) {
+		SKS_HSM_ERROR("[%s][%d] allocate memory fail\n", __FUNCTION__, __LINE__);
+		goto fail;
+	}
+
+	_read_key_table(table_buffer, tablesize);
+	ptable = (key_table *)table_buffer;
+	SKS_HSM_INFO("[%s][%d] ptable->nkeys : %d\n", __FUNCTION__, __LINE__, ptable->nkeys);
+
+	/* clean garbage slot address info in table*/
+	for (int i = 0; i < ptable->nkeys; ++i) {
+		ptable->slot[i].key_w.addr32 = 0;
+	}
+
+	if (pta_rebuild_key_table(table_buffer, tablesize) != 0) {
+		SKS_HSM_ERROR("[%s][%d] rebuild key table fail!\n", __FUNCTION__, __LINE__);
+		goto fail;
+	}
+
+	/* Rebuild the key blob for each key_id in the key table*/
+	for (int i = 0; i < ptable->nkeys; ++i) {
+		memset(blob_buffer, 0, maxblobsize);
+		blob_size = key_id = key_size = 0;
+
+		_get_key_info_in_table(ptable, i, &key_id, &key_size);
+		if (key_size == 0 || key_id == 0)
+			continue;
+
+		_estimate_blob_size(key_size, &blob_size);
+		_read_key_blob(blob_buffer, blob_size, key_id);
+		pta_rebuild_key_blob(blob_buffer, blob_size, key_id);
+	}
+
+
+	if (table_buffer != NULL)
+		TEE_Free(table_buffer);
+	if (blob_buffer != NULL)
+		TEE_Free(blob_buffer);
+
+	return 0;
+
+fail:
+	if (table_buffer != NULL)
+		TEE_Free(table_buffer);
+	if (blob_buffer != NULL)
+		TEE_Free(blob_buffer);
+
+	return -1;
+}
+
+int mtk_import_key(uint8_t *pkey, uint32_t size,
+				int *pkeyid, int *pblob,
+				int *inblobsize, int algo_id)
+{
+	uint8_t buffer[sizeof(key_table)] = {0};
+	int blobsize = 0;
+	int key_id = 0;
+	int tablesize = 0;
+	int rv = 0;
+	ecc_keypair_datastruct *pecckey = NULL;
+
+	if ((pkey == NULL) || (pkeyid == NULL) || (inblobsize == NULL)) {
+		SKS_HSM_ERROR("[%s][%d] bad argument\n", __FUNCTION__, __LINE__);
+		goto fail;
+	}
+
+	switch (algo_id)
+	{
+	case KEY_ALGO_ID_ECC:
+		pecckey = (ecc_keypair_datastruct *)pkey;
+		if (pecckey->curve_id == UECC_CURVE_ID_UNSUPPORT) {
+			SKS_HSM_ERROR("[%s][%d] not support curve\n", __FUNCTION__, __LINE__);
+			goto fail;
+		}
+		break;
+	case KEY_ALGO_ID_AES:
+		if (!_check_symmetric_key_size_valid(size)) {
+			SKS_HSM_ERROR("[%s][%d] not symmetric key size (%d)\n", __FUNCTION__, __LINE__, size);
+			goto fail;
+		}
+		break;
+	default:
+		SKS_HSM_ERROR("[%s][%d] not algorithm type\n", __FUNCTION__, __LINE__);
+		break;
+	}
+
+	rv = pta_import_key(pkey, size, &key_id, algo_id);
+	if (rv != TEE_SUCCESS) {
+		SKS_HSM_ERROR("[%s][%d] import key fail (%d)\n", __FUNCTION__, __LINE__, rv);
+		goto fail;
+	}
+
+	rv = pta_get_key_blob(buffer, sizeof(buffer), key_id, algo_id, &blobsize);
+	if (rv != TEE_SUCCESS) {
+		SKS_HSM_ERROR("[%s][%d] get blob fail (%d)\n", __FUNCTION__, __LINE__, rv);
+		goto fail;
+	}
+
+	if (blobsize > *inblobsize) {
+		SKS_HSM_ERROR("[%s][%d] in buf too small (%d > %d)\n", __FUNCTION__, __LINE__, blobsize, inblobsize);
+		goto fail;
+	}
+	_write_key_blob_to_storage(buffer, blobsize, key_id);
+	memcpy(pblob, buffer, blobsize);
+	*inblobsize = blobsize;
+
+	rv = pta_get_key_table(buffer, sizeof(buffer), &tablesize);
+	if (rv != TEE_SUCCESS) {
+		SKS_HSM_ERROR("[%s][%d] get table fail (%d)\n", __FUNCTION__, __LINE__, rv);
+		goto fail;
+	}
+
+	_write_key_table_to_storage(buffer, tablesize);
+
+	*pkeyid = key_id;
+
+	return TEE_SUCCESS;
+fail:
+	return TEE_ERROR_GENERIC;
+}
+
+int mtk_export_key(uint8_t *pblob, uint32_t blobsize, uint8_t *ppubkey, uint32_t *ppubkeylength)
+{
+	int rv = 0;
+	if ((pblob == NULL) || (ppubkey == NULL) || (ppubkeylength == NULL)) {
+		SKS_HSM_ERROR("[%s][%d] bad argument\n", __FUNCTION__, __LINE__);
+		goto fail;
+	}
+
+	rv = pta_export_key(pblob, blobsize, ppubkey, ppubkeylength);
+	if (rv != TEE_SUCCESS) {
+		SKS_HSM_ERROR("[%s][%d] export key fail (%d)\n", __FUNCTION__, __LINE__, rv);
+		goto fail;
+	}
+
+	return TEE_SUCCESS;
+fail:
+	return TEE_ERROR_GENERIC;
+
+}
+
+static void _fill_pta_params(TEE_Param *params,
+                             uint32_t a0, uint32_t b0,
+                             uint32_t a1, uint32_t b1,
+                             uint32_t a2, uint32_t b2,
+                             uint32_t a3, uint32_t b3)
+{
+	TEE_MemFill(params, 0, sizeof(TEE_Param) * 4);
+
+	params[0].value.a = a0;
+	params[0].value.b = b0;
+
+	params[1].value.a = a1;
+	params[1].value.b = b1;
+
+	params[2].value.a = a2;
+	params[2].value.b = b2;
+
+	params[3].value.a = a3;
+	params[3].value.b = b3;
+}
+
+static int _transmit_to_pta(TEE_Param *params, uint32_t cmd_id)
+{
+	TEE_TASessionHandle pta_session;
+	uint32_t origin;
+	TEE_UUID uuid = PTA_MBOX_UUID;
+	TEE_Result res = TEE_SUCCESS;
+
+	uint32_t types = TEE_PARAM_TYPES( TEE_PARAM_TYPE_VALUE_INPUT
+	                                  , TEE_PARAM_TYPE_VALUE_INPUT
+	                                  , TEE_PARAM_TYPE_VALUE_INPUT
+	                                  , TEE_PARAM_TYPE_VALUE_INPUT);
+
+	res = TEE_OpenTASession(&uuid, 0, types, params, &pta_session,
+	                        &origin);
+
+	if (res != TEE_SUCCESS) {
+		SKS_HSM_ERROR("rpc_sha256 - TEE_OpenTASession returned 0x%x\n",
+		     (unsigned int)res);
+		return res;
+	}
+
+
+	res = TEE_InvokeTACommand(pta_session, 0, cmd_id, types, params, &origin);
+	if (res != TEE_SUCCESS) {
+		SKS_HSM_ERROR("rpc_call_cryp - TEE_InvokeTACommand returned 0x%x\n",
+		     (unsigned int)res);
+	}
+
+	TEE_CloseTASession(pta_session);
+	return res;
+}
+
+static int pta_gen_key_pair(int size, int uECC_curve_id, int *pkey_id) // TODO: ADD CURVE ID
+{
+	TEE_Result res = TEE_SUCCESS;
+	TEE_Param params[4] = {0};
+
+	int hsm_ret = -1;
+	int key_id = -2;
+	int key_size = size;
+
+	if (pkey_id == NULL) {
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	_fill_pta_params(params,
+	                 (uint32_t)&hsm_ret, (uint32_t)size,
+	                 (uint32_t)uECC_curve_id, (uint32_t)&key_id,
+	                 NULL, NULL,
+	                 NULL, NULL);
+
+	res = _transmit_to_pta(params, PTA_CMD_HSM_GEN_KEY_PAIR);
+
+	if (res != TEE_SUCCESS) {
+		return TEE_ERROR_GENERIC;
+	}
+
+	*pkey_id = key_id;
+
+	return hsm_ret;
+}
+
+static int pta_gen_sym_key(int size, int *pkey_id)
+{
+	TEE_Result res = TEE_SUCCESS;
+	TEE_Param params[4] = {0};
+
+	int hsm_ret = -1;
+	int key_id = -2;
+	int key_size = size;
+
+	if (pkey_id == NULL) {
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	_fill_pta_params(params,
+	                 (uint32_t)&hsm_ret, (uint32_t)&key_id,
+	                 (uint32_t)key_size , NULL,
+	                 NULL, NULL,
+	                 NULL, NULL);
+
+	res = _transmit_to_pta(params, PTA_CMD_HSM_GEN_SYMM_KEY);
+
+	if (res != TEE_SUCCESS) {
+		return TEE_ERROR_GENERIC;
+	}
+
+	*pkey_id = key_id;
+
+	return hsm_ret;
+}
+
+static int pta_delete_key(int key_id)
+{
+	TEE_Result res = TEE_SUCCESS;
+	TEE_Param params[4] = {0};
+
+	int hsm_ret = -1;
+
+	_fill_pta_params(params,
+	                 (uint32_t)&hsm_ret, (uint32_t)key_id,
+	                 NULL , NULL,
+	                 NULL, NULL,
+	                 NULL, NULL);
+
+	res = _transmit_to_pta(params, PTA_CMD_HSM_DELETE_KEY);
+
+	if (res != TEE_SUCCESS) {
+		return TEE_ERROR_GENERIC;
+	}
+
+	return hsm_ret;
+}
+
+static int pta_export_key(uint8_t *pblob, uint32_t blobsize, uint8_t *ppubkey, uint32_t *ppubkeylength)
+{
+	TEE_Result res;
+	TEE_Param params[4];
+
+	int hsm_ret = -1;
+
+	if ((pblob == NULL) || (ppubkey == NULL) || (ppubkeylength == NULL)) {
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	_fill_pta_params(params,
+	                 (uint32_t)&hsm_ret, (uint32_t)pblob,
+	                 (uint32_t)blobsize , (uint32_t)ppubkey,
+	                 (uint32_t)ppubkeylength, NULL,
+	                 NULL, NULL);
+
+
+	res = _transmit_to_pta(params, PTA_CMD_HSM_EXPORT_KEY);
+
+	if (res != TEE_SUCCESS) {
+		return TEE_ERROR_GENERIC;
+	}
+
+	return hsm_ret;
+}
+
+static int pta_import_key(uint8_t *pkeybuffer, uint32_t size, int *pkeyid, int algo_id)
+{
+	TEE_Result res = TEE_SUCCESS;
+	TEE_Param params[4];
+
+	int hsm_ret = -1;
+	int key_id = 0;
+
+	if ((pkeybuffer == NULL) || (pkeyid == NULL)) {
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	_fill_pta_params(params,
+	                 (uint32_t)&hsm_ret, (uint32_t)pkeybuffer,
+	                 (uint32_t)size , (uint32_t)&key_id,
+	                 (uint32_t)algo_id, NULL,
+	                 NULL, NULL);
+
+
+	res = _transmit_to_pta(params, PTA_CMD_HSM_IMPORT_KEY);
+
+	if (res != TEE_SUCCESS) {
+		return TEE_ERROR_GENERIC;
+	}
+
+	*pkeyid = key_id;
+
+	return hsm_ret;
+}
+
+static int pta_get_key_blob(uint8_t *dst, int size, int key_id, int algo_id, int *pblobsize)
+{
+	TEE_Result res = TEE_SUCCESS;
+	TEE_Param params[4];
+
+	int hsm_ret = -1;
+	uint32_t blobsize;
+
+	if (dst == NULL) {
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	_fill_pta_params(params,
+	                 (uint32_t)&hsm_ret, (uint32_t)key_id,
+	                 (uint32_t)dst , (uint32_t)size,
+	                 (uint32_t)algo_id, (uint32_t)&blobsize,
+	                 NULL, NULL);
+
+
+	res = _transmit_to_pta(params, PTA_CMD_HSM_GET_KEY_BLOB);
+
+	if (res != TEE_SUCCESS) {
+		return TEE_ERROR_GENERIC;
+	}
+
+	*pblobsize = blobsize;
+
+	return hsm_ret;
+}
+
+static int pta_get_key_table(uint8_t *dst, int size, int *ptablesize)
+{
+	TEE_Result res = TEE_SUCCESS;
+	TEE_Param params[4];
+
+	int hsm_ret = -1;
+	uint32_t tablesize;
+
+	if (dst == NULL) {
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	_fill_pta_params(params,
+	                 (uint32_t)&hsm_ret, (uint32_t)dst,
+	                 (uint32_t)size , (uint32_t)&tablesize,
+	                 NULL, NULL,
+	                 NULL, NULL);
+
+	res = _transmit_to_pta(params, PTA_CMD_HSM_GET_KEY_TABLE);
+
+	if (res != TEE_SUCCESS) {
+		return TEE_ERROR_GENERIC;
+	}
+
+	*ptablesize = tablesize;
+
+	return hsm_ret;
+}
+
+
+static int pta_rebuild_key_table(uint8_t *buffer, int tablesize)
+{
+	TEE_Result res = TEE_SUCCESS;
+	TEE_Param params[4] = {0};
+	int hsm_ret = -1;
+
+	if (buffer == NULL) {
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	_fill_pta_params(params,
+	                 (uint32_t)&hsm_ret, (uint32_t)buffer,
+	                 (uint32_t)tablesize , NULL,
+	                 NULL, NULL,
+	                 NULL, NULL);
+
+	res = _transmit_to_pta(params, PTA_CMD_HSM_REBUILD_KEY_TABLE);
+
+	if (res != TEE_SUCCESS) {
+		return TEE_ERROR_GENERIC;
+	}
+
+	return hsm_ret;
+}
+
+static int pta_rebuild_key_blob(uint8_t *buffer, int blob_size, int key_id)
+{
+	TEE_Result res = TEE_SUCCESS;
+	TEE_Param params[4] = {0};
+	int hsm_ret = -1;
+
+	if (buffer == NULL) {
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	_fill_pta_params(params,
+	                 (uint32_t)&hsm_ret, (uint32_t)buffer,
+	                 (uint32_t)blob_size , (uint32_t)key_id,
+	                 NULL, NULL,
+	                 NULL, NULL);
+
+	res = _transmit_to_pta(params, PTA_CMD_HSM_REBUILD_KEY_BLOB);
+
+	if (res != TEE_SUCCESS) {
+		return TEE_ERROR_GENERIC;
+	}
+
+	return hsm_ret;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_key.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_key.h
new file mode 100644
index 0000000..751f5ed
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_mtk_key.h
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef __PROCESSING_MTK_KEY_H
+#define __PROCESSING_MTK_KEY_H
+
+#include "object.h"
+#include "mtk_key.h"
+
+/*
+ * MTK HSM related APIs
+ */
+int mtk_generate_symmetric_key(int size, int *pkeyid);
+int mtk_generate_ecc_key_pair(int size, int curve_id, int *pkeyid);
+int mtk_rebuild_key_table(void);
+int mtk_import_key(uint8_t *pkey, uint32_t size,
+                int *pkeyid, int *pblob,
+                int *inblobsize, int algo_id);
+int mtk_export_key(uint8_t *pblob, uint32_t blobsize,
+                uint8_t *ppubkey, uint32_t *ppubkeylength);
+
+int mtk_delete_key(struct sks_object *object);
+
+
+#endif // __PROCESSING_MTK_KEY_H
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_rsa.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_rsa.c
new file mode 100644
index 0000000..eea201d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_rsa.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <assert.h>
+#include <compiler.h>
+#include <tee_api_defines.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+
+#include "attributes.h"
+#include "pkcs11_token.h"
+#include "processing.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+uint32_t sks2tee_proc_params_rsa_pss(struct active_processing *processing,
+				     struct sks_attribute_head *proc_params)
+{
+	struct serialargs args;
+	uint32_t rv;
+	uint32_t data32;
+	uint32_t salt_len;
+
+	serialargs_init(&args, proc_params->data, proc_params->size);
+
+	rv = serialargs_get(&args, &data32, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &data32, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &salt_len, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	processing->extra_ctx = TEE_Malloc(sizeof(uint32_t),
+						TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!processing->extra_ctx)
+		return SKS_MEMORY;
+
+	*(uint32_t *)processing->extra_ctx = salt_len;
+
+	return SKS_OK;
+}
+
+void tee_release_rsa_pss_operation(struct active_processing *processing)
+{
+	TEE_Free(processing->extra_ctx);
+	processing->extra_ctx = NULL;
+}
+
+uint32_t sks2tee_algo_rsa_pss(uint32_t *tee_id,
+				struct sks_attribute_head *proc_params)
+{
+	struct serialargs args;
+	uint32_t rv;
+	uint32_t hash;
+	uint32_t mgf;
+	uint32_t salt_len;
+
+	serialargs_init(&args, proc_params->data, proc_params->size);
+
+	rv = serialargs_get(&args, &hash, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &mgf, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &salt_len, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	switch (*tee_id) {
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1:
+		if (hash != SKS_CKM_SHA_1 || mgf != SKS_CKG_MGF1_SHA1)
+			return SKS_CKR_MECHANISM_PARAM_INVALID;
+		break;
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224:
+		if (hash != SKS_CKM_SHA224 || mgf != SKS_CKG_MGF1_SHA224)
+			return SKS_CKR_MECHANISM_PARAM_INVALID;
+		break;
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
+		if (hash != SKS_CKM_SHA256 || mgf != SKS_CKG_MGF1_SHA256)
+			return SKS_CKR_MECHANISM_PARAM_INVALID;
+		break;
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384:
+		if (hash != SKS_CKM_SHA384 || mgf != SKS_CKG_MGF1_SHA384)
+			return SKS_CKR_MECHANISM_PARAM_INVALID;
+		break;
+	case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512:
+		if (hash != SKS_CKM_SHA512 || mgf != SKS_CKG_MGF1_SHA512)
+			return SKS_CKR_MECHANISM_PARAM_INVALID;
+		break;
+	default:
+		return SKS_ERROR;
+	}
+
+	return SKS_OK;
+}
+
+// Currently unused
+uint32_t tee_init_rsa_aes_key_wrap_operation(struct active_processing *proc,
+					     void *proc_params,
+					     size_t params_size)
+{
+	struct serialargs args;
+	uint32_t rv;
+	uint32_t aes_bit_size;
+	uint32_t hash;
+	uint32_t mgf;
+	uint32_t source_type;
+	void *source_data;
+	uint32_t source_size;
+
+	serialargs_init(&args, proc_params, params_size);
+
+	rv = serialargs_get(&args, &aes_bit_size, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &hash, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &mgf, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &source_type, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &source_size, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get_ptr(&args, &source_data, source_size);
+	if (rv)
+		return rv;
+
+	// TODO
+	(void)proc;
+	return SKS_ERROR;
+}
+
+uint32_t sks2tee_algo_rsa_oaep(uint32_t *tee_id,
+				struct sks_attribute_head *proc_params)
+{
+	struct serialargs args;
+	uint32_t rv;
+	uint32_t hash;
+	uint32_t mgf;
+	uint32_t source_type;
+	void *source_data;
+	uint32_t source_size;
+
+	serialargs_init(&args, proc_params->data, proc_params->size);
+
+	rv = serialargs_get(&args, &hash, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &mgf, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &source_type, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &source_size, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get_ptr(&args, &source_data, source_size);
+	if (rv)
+		return rv;
+
+	switch (proc_params->id) {
+	case SKS_CKM_RSA_PKCS_OAEP:
+		switch (hash) {
+		case SKS_CKM_SHA_1:
+			if (mgf != SKS_CKG_MGF1_SHA1 || source_size)
+				return SKS_CKR_MECHANISM_PARAM_INVALID;
+			*tee_id = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1;
+			break;
+		case SKS_CKM_SHA224:
+			if (mgf != SKS_CKG_MGF1_SHA224 || source_size)
+				return SKS_CKR_MECHANISM_PARAM_INVALID;
+			*tee_id = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224;
+			break;
+		case SKS_CKM_SHA256:
+			if (mgf != SKS_CKG_MGF1_SHA256 || source_size)
+				return SKS_CKR_MECHANISM_PARAM_INVALID;
+			*tee_id = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256;
+			break;
+		case SKS_CKM_SHA384:
+			if (mgf != SKS_CKG_MGF1_SHA384 || source_size)
+				return SKS_CKR_MECHANISM_PARAM_INVALID;
+			*tee_id = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384;
+			break;
+		case SKS_CKM_SHA512:
+			if (mgf != SKS_CKG_MGF1_SHA512 || source_size)
+				return SKS_CKR_MECHANISM_PARAM_INVALID;
+			*tee_id = TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512;
+			break;
+		default:
+			EMSG("Unexpected %s (0x%" PRIx32 ")",
+				sks2str_proc(hash), hash);
+			return SKS_ERROR;
+		}
+		break;
+	default:
+		EMSG("Unexpected %s (0x%" PRIx32 ")",
+			sks2str_proc(proc_params->id), proc_params->id);
+		return SKS_ERROR;
+	}
+
+	return SKS_OK;
+}
+
+// Unused yet...
+uint32_t tee_init_rsa_oaep_operation(struct active_processing *processing,
+				     void *proc_params, size_t params_size);
+
+uint32_t tee_init_rsa_oaep_operation(struct active_processing *processing,
+				     void *proc_params, size_t params_size)
+{
+	struct serialargs args;
+	uint32_t rv;
+	uint32_t hash;
+	uint32_t mgf;
+	uint32_t source_type;
+	void *source_data;
+	uint32_t source_size;
+
+	serialargs_init(&args, proc_params, params_size);
+
+	rv = serialargs_get(&args, &hash, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &mgf, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &source_type, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get(&args, &source_size, sizeof(uint32_t));
+	if (rv)
+		return rv;
+
+	rv = serialargs_get_ptr(&args, &source_data, source_size);
+	if (rv)
+		return rv;
+
+	// TODO
+	(void)processing;
+	return SKS_ERROR;
+}
+
+uint32_t load_tee_rsa_key_attrs(TEE_Attribute **tee_attrs, size_t *tee_count,
+				struct sks_object *obj)
+{
+	TEE_Attribute *attrs = NULL;
+	size_t count = 0;
+	uint32_t rv = SKS_ERROR;
+
+	assert(get_type(obj->attributes) == SKS_CKK_RSA);
+
+	switch (get_class(obj->attributes)) {
+	case SKS_CKO_PUBLIC_KEY:
+		attrs = TEE_Malloc(3 * sizeof(TEE_Attribute),
+				   TEE_USER_MEM_HINT_NO_FILL_ZERO);
+		if (!attrs)
+			return SKS_MEMORY;
+
+		if (sks2tee_load_attr(&attrs[count], TEE_ATTR_RSA_MODULUS,
+					obj, SKS_CKA_MODULUS))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_RSA_PUBLIC_EXPONENT,
+					obj, SKS_CKA_PUBLIC_EXPONENT))
+			count++;
+
+		if (count == 2)
+			rv = SKS_OK;
+
+		break;
+
+	case SKS_CKO_PRIVATE_KEY:
+		attrs = TEE_Malloc(8 * sizeof(TEE_Attribute),
+				   TEE_USER_MEM_HINT_NO_FILL_ZERO);
+		if (!attrs)
+			return SKS_MEMORY;
+
+		if (sks2tee_load_attr(&attrs[count], TEE_ATTR_RSA_MODULUS,
+					obj, SKS_CKA_MODULUS))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_RSA_PUBLIC_EXPONENT,
+					obj, SKS_CKA_PUBLIC_EXPONENT))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_RSA_PRIVATE_EXPONENT,
+					obj, SKS_CKA_PRIVATE_EXPONENT))
+			count++;
+
+		if (count != 3)
+			break;
+
+		if (get_attribute(obj->attributes, SKS_CKA_PRIME_1,
+					   NULL, NULL)) {
+			rv = SKS_OK;
+			break;
+		}
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_RSA_PRIME1,
+					obj, SKS_CKA_PRIME_1))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_RSA_PRIME2,
+					obj, SKS_CKA_PRIME_2))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_RSA_EXPONENT1,
+					obj, SKS_CKA_EXPONENT_1))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_RSA_EXPONENT2,
+					obj, SKS_CKA_EXPONENT_2))
+			count++;
+
+		if (sks2tee_load_attr(&attrs[count],
+					TEE_ATTR_RSA_COEFFICIENT,
+					obj, SKS_CKA_COEFFICIENT))
+			count++;
+
+		if (count == 8)
+			rv = SKS_OK;
+
+		break;
+
+	default:
+		assert(0);
+		break;
+	}
+
+	if (rv == SKS_OK) {
+		*tee_attrs = attrs;
+		*tee_count = count;
+	}
+
+	return rv;
+}
+
+static uint32_t tee2sks_rsa_attributes(struct sks_attrs_head **pub_head,
+					struct sks_attrs_head **priv_head,
+					TEE_ObjectHandle tee_obj)
+{
+	uint32_t rv;
+
+	rv = tee2sks_add_attribute(pub_head, SKS_CKA_MODULUS,
+				   tee_obj, TEE_ATTR_RSA_MODULUS);
+	if (rv)
+		goto bail;
+
+	if (get_attribute_ptr(*pub_head, SKS_CKA_PUBLIC_EXPONENT, NULL, NULL)) {
+		rv = tee2sks_add_attribute(pub_head,
+					   SKS_CKA_PUBLIC_EXPONENT,
+					   tee_obj,
+					   TEE_ATTR_RSA_PUBLIC_EXPONENT);
+		if (rv)
+			goto bail;
+	}
+
+	rv = tee2sks_add_attribute(priv_head, SKS_CKA_MODULUS,
+				   tee_obj, TEE_ATTR_RSA_MODULUS);
+	if (rv)
+		goto bail;
+
+	rv = tee2sks_add_attribute(priv_head, SKS_CKA_PUBLIC_EXPONENT,
+				   tee_obj, TEE_ATTR_RSA_PUBLIC_EXPONENT);
+	if (rv)
+		goto bail;
+
+	rv = tee2sks_add_attribute(priv_head, SKS_CKA_PRIVATE_EXPONENT,
+				   tee_obj, TEE_ATTR_RSA_PRIVATE_EXPONENT);
+	if (rv)
+		goto bail;
+
+	rv = tee2sks_add_attribute(priv_head, SKS_CKA_PRIME_1,
+				   tee_obj, TEE_ATTR_RSA_PRIME1);
+	if (rv)
+		goto bail;
+
+	rv = tee2sks_add_attribute(priv_head, SKS_CKA_PRIME_2,
+				   tee_obj, TEE_ATTR_RSA_PRIME2);
+	if (rv)
+		goto bail;
+
+	rv = tee2sks_add_attribute(priv_head, SKS_CKA_EXPONENT_1,
+				   tee_obj, TEE_ATTR_RSA_EXPONENT1);
+	if (rv)
+		goto bail;
+
+	rv = tee2sks_add_attribute(priv_head, SKS_CKA_EXPONENT_2,
+				   tee_obj, TEE_ATTR_RSA_EXPONENT2);
+	if (rv)
+		goto bail;
+
+	rv = tee2sks_add_attribute(priv_head, SKS_CKA_COEFFICIENT,
+				   tee_obj, TEE_ATTR_RSA_COEFFICIENT);
+bail:
+	return rv;
+}
+
+uint32_t generate_rsa_keys(struct sks_attribute_head *proc_params,
+			   struct sks_attrs_head **pub_head,
+			   struct sks_attrs_head **priv_head)
+{
+	uint32_t rv;
+	void *a_ptr;
+	uint32_t a_size;
+	TEE_ObjectHandle tee_obj;
+	TEE_Result res;
+	uint32_t tee_size;
+	TEE_Attribute tee_attrs[1];
+	uint32_t tee_count = 0;
+
+	if (!proc_params || !*pub_head || !*priv_head) {
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	if (get_attribute_ptr(*pub_head, SKS_CKA_MODULUS_BITS,
+				&a_ptr, &a_size)) {
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	if (a_size != sizeof(uint32_t)) {
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	TEE_MemMove(&tee_size, a_ptr, sizeof(uint32_t));
+
+	rv = get_attribute_ptr(*pub_head, SKS_CKA_PUBLIC_EXPONENT,
+				&a_ptr, &a_size);
+	if (rv == SKS_OK) {
+		TEE_InitRefAttribute(&tee_attrs[tee_count],
+				     TEE_ATTR_RSA_PUBLIC_EXPONENT,
+				     a_ptr, a_size);
+
+		tee_count++;
+	}
+
+	if (!get_attribute(*pub_head, SKS_CKA_MODULUS, NULL, NULL) ||
+	    !get_attribute(*priv_head, SKS_CKA_MODULUS, NULL, NULL) ||
+	    !get_attribute(*priv_head, SKS_CKA_PUBLIC_EXPONENT, NULL, NULL) ||
+	    !get_attribute(*priv_head, SKS_CKA_PRIVATE_EXPONENT, NULL, NULL) ||
+	    !get_attribute(*priv_head, SKS_CKA_PRIME_1, NULL, NULL) ||
+	    !get_attribute(*priv_head, SKS_CKA_PRIME_2, NULL, NULL) ||
+	    !get_attribute(*priv_head, SKS_CKA_EXPONENT_1, NULL, NULL) ||
+	    !get_attribute(*priv_head, SKS_CKA_EXPONENT_2, NULL, NULL) ||
+	    !get_attribute(*priv_head, SKS_CKA_COEFFICIENT, NULL, NULL)) {
+		EMSG("Unexpected attribute(s) found");
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	/* Create an ECDSA TEE key: will match PKCS11 ECDSA and ECDH */
+	res = TEE_AllocateTransientObject(TEE_TYPE_RSA_KEYPAIR,
+					  tee_size, &tee_obj);
+	if (res) {
+		DMSG("TEE_AllocateTransientObject failed 0x%" PRIx32, res);
+		return tee2sks_error(res);
+	}
+
+	res = TEE_RestrictObjectUsage1(tee_obj, TEE_USAGE_EXTRACTABLE);
+	if (res) {
+		DMSG("TEE_RestrictObjectUsage1 failed 0x%" PRIx32, res);
+		rv = tee2sks_error(res);
+		goto bail;
+	}
+
+	res = TEE_GenerateKey(tee_obj, tee_size, &tee_attrs[0], tee_count);
+	if (res) {
+		DMSG("TEE_GenerateKey failed 0x%" PRIx32, res);
+		rv = tee2sks_error(res);
+		goto bail;
+	}
+
+	rv = tee2sks_rsa_attributes(pub_head, priv_head, tee_obj);
+
+bail:
+	if (tee_obj != TEE_HANDLE_NULL)
+		TEE_FreeTransientObject(tee_obj);
+
+	return rv;
+}
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_symm.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_symm.c
new file mode 100644
index 0000000..71314a3
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/processing_symm.c
@@ -0,0 +1,627 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#include <assert.h>
+#include <sks_internal_abi.h>
+#include <sks_ta.h>
+#include <string.h>
+#include <tee_api_defines.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <util.h>
+
+#include "attributes.h"
+#include "object.h"
+#include "pkcs11_token.h"
+#include "pkcs11_attributes.h"
+#include "processing.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+bool processing_is_tee_symm(uint32_t proc_id)
+{
+	switch (proc_id) {
+	/* Authentication */
+	case SKS_CKM_AES_CMAC_GENERAL:
+	case SKS_CKM_AES_CMAC:
+	case SKS_CKM_MD5_HMAC:
+	case SKS_CKM_SHA_1_HMAC:
+	case SKS_CKM_SHA224_HMAC:
+	case SKS_CKM_SHA256_HMAC:
+	case SKS_CKM_SHA384_HMAC:
+	case SKS_CKM_SHA512_HMAC:
+	case SKS_CKM_AES_XCBC_MAC:
+	/* Cipherering */
+	case SKS_CKM_AES_ECB:
+	case SKS_CKM_AES_CBC:
+	case SKS_CKM_AES_CBC_PAD:
+	case SKS_CKM_AES_CTS:
+	case SKS_CKM_AES_CTR:
+	case SKS_CKM_AES_CCM:
+	case SKS_CKM_AES_GCM:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static uint32_t sks2tee_algorithm(uint32_t *tee_id,
+			      struct sks_attribute_head *proc_params)
+{
+	static const uint32_t sks2tee_algo[][2] = {
+		/* AES flavors */
+		{ SKS_CKM_AES_ECB, TEE_ALG_AES_ECB_NOPAD },
+		{ SKS_CKM_AES_CBC, TEE_ALG_AES_CBC_NOPAD },
+		{ SKS_CKM_AES_CBC_PAD, TEE_ALG_AES_CBC_NOPAD }, // TODO
+		{ SKS_CKM_AES_CTR, TEE_ALG_AES_CTR },
+		{ SKS_CKM_AES_CTS, TEE_ALG_AES_CTS },
+		{ SKS_CKM_AES_CCM, TEE_ALG_AES_CCM },
+		{ SKS_CKM_AES_GCM, TEE_ALG_AES_GCM },
+		{ SKS_CKM_AES_CMAC, TEE_ALG_AES_CMAC },
+		{ SKS_CKM_AES_CMAC_GENERAL, TEE_ALG_AES_CMAC },
+		{ SKS_CKM_AES_XCBC_MAC, TEE_ALG_AES_CBC_MAC_NOPAD },
+		/* HMAC flavors */
+		{ SKS_CKM_MD5_HMAC, TEE_ALG_HMAC_MD5 },
+		{ SKS_CKM_SHA_1_HMAC, TEE_ALG_HMAC_SHA1 },
+		{ SKS_CKM_SHA224_HMAC, TEE_ALG_HMAC_SHA224 },
+		{ SKS_CKM_SHA256_HMAC, TEE_ALG_HMAC_SHA256 },
+		{ SKS_CKM_SHA384_HMAC, TEE_ALG_HMAC_SHA384 },
+		{ SKS_CKM_SHA512_HMAC, TEE_ALG_HMAC_SHA512 },
+	};
+	size_t end = sizeof(sks2tee_algo) / (2 * sizeof(uint32_t));
+	size_t n = 0;
+
+	for (n = 0; n < end; n++) {
+		if (proc_params->id == sks2tee_algo[n][0]) {
+			*tee_id = sks2tee_algo[n][1];
+			break;
+		}
+	}
+
+	if (n == end)
+		return SKS_NOT_IMPLEMENTED;
+
+	return SKS_OK;
+}
+
+static uint32_t sks2tee_key_type(uint32_t *tee_type,
+				  struct sks_attribute_head *proc_params,
+				  struct sks_object *obj)
+{
+	static const uint32_t sks2tee_key_type[][2] = {
+		{ SKS_CKK_AES, TEE_TYPE_AES },
+		{ SKS_CKK_GENERIC_SECRET, TEE_TYPE_GENERIC_SECRET },
+		{ SKS_CKK_MD5_HMAC, TEE_TYPE_HMAC_MD5 },
+		{ SKS_CKK_SHA_1_HMAC, TEE_TYPE_HMAC_SHA1 },
+		{ SKS_CKK_SHA224_HMAC, TEE_TYPE_HMAC_SHA224 },
+		{ SKS_CKK_SHA256_HMAC, TEE_TYPE_HMAC_SHA256 },
+		{ SKS_CKK_SHA384_HMAC, TEE_TYPE_HMAC_SHA384 },
+		{ SKS_CKK_SHA512_HMAC, TEE_TYPE_HMAC_SHA512 },
+	};
+	static const uint32_t sks_mech2tee_type[][2] = {
+		{ SKS_CKM_MD5_HMAC, TEE_TYPE_HMAC_MD5 },
+		{ SKS_CKM_SHA_1_HMAC, TEE_TYPE_HMAC_SHA1 },
+		{ SKS_CKM_SHA224_HMAC, TEE_TYPE_HMAC_SHA224 },
+		{ SKS_CKM_SHA256_HMAC, TEE_TYPE_HMAC_SHA256 },
+		{ SKS_CKM_SHA384_HMAC, TEE_TYPE_HMAC_SHA384 },
+		{ SKS_CKM_SHA512_HMAC, TEE_TYPE_HMAC_SHA512 },
+	};
+	size_t last = 0;
+	size_t n = 0;
+	uint32_t type = 0;
+	uint32_t key_type = 0;
+
+	assert(get_class(obj->attributes) == SKS_CKO_SECRET_KEY);
+
+	key_type = get_type(obj->attributes);
+	last = sizeof(sks2tee_key_type) / (2 * sizeof(uint32_t));
+	for (n = 0; n < last; n++) {
+		if (sks2tee_key_type[n][0] == key_type) {
+			type = sks2tee_key_type[n][1];
+			break;
+		}
+	}
+	if (n == last)
+		return SKS_NOT_FOUND;
+
+	/*
+	 * HMAC secret corresponds to the generic secret key type
+	 * or the mechanism specific key type. If generic, find the
+	 * corresponding TEE_TYPE based on the mechanism used.
+	 */
+	if (type == TEE_TYPE_GENERIC_SECRET) {
+		last = sizeof(sks_mech2tee_type) /
+				(2 * sizeof(uint32_t));
+		for (n = 0; n < last; n++) {
+			if (sks_mech2tee_type[n][0] == proc_params->id) {
+				type = sks_mech2tee_type[n][1];
+				break;
+			}
+		}
+	}
+
+	*tee_type = type;
+
+	return SKS_OK;
+}
+
+static uint32_t allocate_tee_operation(struct pkcs11_session *session,
+					enum processing_func function,
+					struct sks_attribute_head *proc_params,
+					struct sks_object *obj)
+{
+	uint32_t size = (uint32_t)get_object_key_bit_size(obj);
+	uint32_t algo = 0;
+	uint32_t mode = 0;
+	TEE_Result res = TEE_ERROR_GENERIC;
+
+	assert(session->processing->tee_op_handle == TEE_HANDLE_NULL);
+
+	if (sks2tee_algorithm(&algo, proc_params))
+		return SKS_FAILED;
+
+	/* Sign/Verify with AES or generic key relate to TEE MAC operation */
+	switch (proc_params->id) {
+	case SKS_CKM_AES_CMAC_GENERAL:
+	case SKS_CKM_AES_CMAC:
+	case SKS_CKM_MD5_HMAC:
+	case SKS_CKM_SHA_1_HMAC:
+	case SKS_CKM_SHA224_HMAC:
+	case SKS_CKM_SHA256_HMAC:
+	case SKS_CKM_SHA384_HMAC:
+	case SKS_CKM_SHA512_HMAC:
+	case SKS_CKM_AES_XCBC_MAC:
+		mode = TEE_MODE_MAC;
+		break;
+	default:
+		sks2tee_mode(&mode, function);
+		break;
+	}
+
+	res = TEE_AllocateOperation(&session->processing->tee_op_handle,
+				    algo, mode, size);
+	switch (res) {
+	case TEE_ERROR_NOT_SUPPORTED:
+		return SKS_CKR_MECHANISM_INVALID;
+	case TEE_SUCCESS:
+		break;
+	default:
+		EMSG("TEE_AllocateOp. failed %" PRIx32 " %" PRIx32 " %" PRIx32,
+			algo, mode, size);
+	}
+
+	return tee2sks_error(res);
+}
+
+static uint32_t load_tee_key(struct pkcs11_session *session,
+				struct sks_attribute_head *proc_params,
+				struct sks_object *obj)
+{
+	TEE_Attribute tee_attr;
+	size_t object_size = 0;
+	uint32_t key_type = 0;
+	uint32_t rv = 0;
+	TEE_Result res = TEE_ERROR_GENERIC;
+
+	TEE_MemFill(&tee_attr, 0, sizeof(tee_attr));
+
+	if (obj->key_handle != TEE_HANDLE_NULL) {
+		/* Key was already loaded and fits current need */
+		goto key_ready;
+	}
+
+	if (!sks2tee_load_attr(&tee_attr, TEE_ATTR_SECRET_VALUE,
+			       obj, SKS_CKA_VALUE)) {
+		EMSG("No secret found");
+		return SKS_FAILED;
+	}
+
+	rv = sks2tee_key_type(&key_type, proc_params, obj);
+	if (rv)
+		return rv;
+
+	object_size = get_object_key_bit_size(obj);
+	if (!object_size)
+		return SKS_ERROR;
+
+	res = TEE_AllocateTransientObject(key_type, object_size,
+					  &obj->key_handle);
+	if (res) {
+		DMSG("TEE_AllocateTransientObject failed, %" PRIx32, res);
+		return tee2sks_error(res);
+	}
+
+	res = TEE_PopulateTransientObject(obj->key_handle, &tee_attr, 1);
+	if (res) {
+		DMSG("TEE_PopulateTransientObject failed, %" PRIx32, res);
+		goto error;
+	}
+
+key_ready:
+	res = TEE_SetOperationKey(session->processing->tee_op_handle,
+				  obj->key_handle);
+	if (res) {
+		DMSG("TEE_SetOperationKey failed, %" PRIx32, res);
+		goto error;
+	}
+
+	return tee2sks_error(res);
+
+error:
+	TEE_FreeTransientObject(obj->key_handle);
+	obj->key_handle = TEE_HANDLE_NULL;
+
+	return tee2sks_error(res);
+}
+
+static uint32_t init_tee_operation(struct pkcs11_session *session,
+				   struct sks_attribute_head *proc_params)
+{
+	uint32_t rv = SKS_ERROR;
+
+	switch (proc_params->id) {
+	case SKS_CKM_AES_CMAC_GENERAL:
+	case SKS_CKM_AES_CMAC:
+	case SKS_CKM_MD5_HMAC:
+	case SKS_CKM_SHA_1_HMAC:
+	case SKS_CKM_SHA224_HMAC:
+	case SKS_CKM_SHA256_HMAC:
+	case SKS_CKM_SHA384_HMAC:
+	case SKS_CKM_SHA512_HMAC:
+	case SKS_CKM_AES_XCBC_MAC:
+		if (proc_params->size)
+			return SKS_CKR_MECHANISM_PARAM_INVALID;
+
+		TEE_MACInit(session->processing->tee_op_handle, NULL, 0);
+		rv = SKS_OK;
+		break;
+	case SKS_CKM_AES_ECB:
+		if (proc_params->size)
+			return SKS_CKR_MECHANISM_PARAM_INVALID;
+
+		TEE_CipherInit(session->processing->tee_op_handle, NULL, 0);
+		rv = SKS_OK;
+		break;
+	case SKS_CKM_AES_CBC:
+	case SKS_CKM_AES_CBC_PAD:
+	case SKS_CKM_AES_CTS:
+		if (proc_params->size != 16)
+			return SKS_CKR_MECHANISM_PARAM_INVALID;
+
+		TEE_CipherInit(session->processing->tee_op_handle,
+			       proc_params->data, 16);
+		rv = SKS_OK;
+		break;
+	case SKS_CKM_AES_CTR:
+		rv = tee_init_ctr_operation(session->processing,
+					    proc_params->data,
+					    proc_params->size);
+		break;
+	case SKS_CKM_AES_CCM:
+		rv = tee_init_ccm_operation(session->processing,
+					    proc_params->data,
+					    proc_params->size);
+		break;
+	case SKS_CKM_AES_GCM:
+		rv = tee_init_gcm_operation(session->processing,
+					    proc_params->data,
+					    proc_params->size);
+		break;
+	default:
+		TEE_Panic(proc_params->id);
+		break;
+	}
+
+	return rv;
+}
+
+uint32_t init_symm_operation(struct pkcs11_session *session,
+				enum processing_func function,
+				struct sks_attribute_head *proc_params,
+				struct sks_object *obj)
+{
+	uint32_t rv = 0;
+
+	assert(processing_is_tee_symm(proc_params->id));
+
+	rv = allocate_tee_operation(session, function, proc_params, obj);
+	if (rv)
+		return rv;
+
+	rv = load_tee_key(session, proc_params, obj);
+	if (rv)
+		return rv;
+
+	return init_tee_operation(session, proc_params);
+}
+
+/*
+ * step_sym_cipher - processing symmetric (and related) cipher operation step
+ *
+ * @session - current session
+ * @function
+ * @step - step ID in the processing (oneshot, update,final)
+ * @in - input data reference #1
+ * @io2 - input or output data reference #2, depending on function/step.
+ */
+uint32_t step_symm_operation(struct pkcs11_session *session,
+			     enum processing_func function,
+			     enum processing_step step,
+			     TEE_Param *in, TEE_Param *io2)
+{
+	uint32_t rv = SKS_ERROR;
+	TEE_Result res = TEE_ERROR_GENERIC;
+	void *in_buf = in ? in->memref.buffer : NULL;
+	size_t in_size = in ? in->memref.size : 0;
+	void *out_buf = io2 ? io2->memref.buffer : NULL;
+	uint32_t out_size = io2 ? io2->memref.size : 0;
+	uint32_t out_size2 = out_size;
+	void *in2_buf = io2 ? io2->memref.buffer : NULL;
+	uint32_t in2_size = io2 ? io2->memref.size : 0;
+	bool output_data = false;
+	struct active_processing *proc = session->processing;
+
+	switch (step) {
+	case SKS_FUNC_STEP_ONESHOT:
+	case SKS_FUNC_STEP_UPDATE:
+	case SKS_FUNC_STEP_FINAL:
+		break;
+	default:
+		return SKS_ERROR;
+	}
+
+	/* Validate input buffer size */
+	switch (proc->mecha_type) {
+	case SKS_CKM_AES_ECB:
+	case SKS_CKM_AES_CBC:
+		switch (function) {
+		case SKS_FUNCTION_ENCRYPT:
+			if ((in_size % 16) != 0)
+				return SKS_CKR_DATA_LEN_RANGE;
+			break;
+		case SKS_FUNCTION_DECRYPT:
+			if ((in_size % 16) != 0)
+				return SKS_CKR_ENCRYPTED_DATA_LEN_RANGE;
+			break;
+		default:
+			break;
+		}
+		break;
+	case SKS_CKM_AES_CBC_PAD:
+		switch (function) {
+		case SKS_FUNCTION_DECRYPT:
+			if ((in_size % 16) != 0)
+				return SKS_CKR_ENCRYPTED_DATA_LEN_RANGE;
+			break;
+		default:
+			break;
+		}
+		break;
+	case SKS_CKM_AES_CTS:
+		switch (function) {
+		case SKS_FUNCTION_ENCRYPT:
+			if (in_size < 16)
+				return SKS_CKR_DATA_LEN_RANGE;
+			break;
+		case SKS_FUNCTION_DECRYPT:
+			if (in_size < 16)
+				return SKS_CKR_ENCRYPTED_DATA_LEN_RANGE;
+			break;
+		default:
+			break;
+		}
+	default:
+		break;
+	}
+
+	/*
+	 * Feed active operation with with data
+	 * (SKS_FUNC_STEP_UPDATE/_ONESHOT)
+	 */
+	switch (proc->mecha_type) {
+	case SKS_CKM_AES_CMAC_GENERAL:
+	case SKS_CKM_AES_CMAC:
+	case SKS_CKM_MD5_HMAC:
+	case SKS_CKM_SHA_1_HMAC:
+	case SKS_CKM_SHA224_HMAC:
+	case SKS_CKM_SHA256_HMAC:
+	case SKS_CKM_SHA384_HMAC:
+	case SKS_CKM_SHA512_HMAC:
+	case SKS_CKM_AES_XCBC_MAC:
+		if (step == SKS_FUNC_STEP_FINAL)
+			break;
+
+		if (!in) {
+			DMSG("No input data");
+			return SKS_BAD_PARAM;
+		}
+
+		switch (function) {
+		case SKS_FUNCTION_SIGN:
+		case SKS_FUNCTION_VERIFY:
+			TEE_MACUpdate(proc->tee_op_handle, in_buf, in_size);
+			rv = SKS_OK;
+			break;
+		default:
+			TEE_Panic(function);
+			break;
+		}
+		break;
+
+	case SKS_CKM_AES_ECB:
+	case SKS_CKM_AES_CBC:
+	case SKS_CKM_AES_CBC_PAD:
+	case SKS_CKM_AES_CTS:
+	case SKS_CKM_AES_CTR:
+		if (step == SKS_FUNC_STEP_FINAL ||
+		    step == SKS_FUNC_STEP_ONESHOT)
+			break;
+
+		if (!in) {
+			DMSG("No input data");
+			return SKS_BAD_PARAM;
+		}
+
+		switch (function) {
+		case SKS_FUNCTION_ENCRYPT:
+		case SKS_FUNCTION_DECRYPT:
+			res = TEE_CipherUpdate(proc->tee_op_handle,
+						in_buf, in_size,
+						out_buf, &out_size);
+			output_data = true;
+			rv = tee2sks_error(res);
+			break;
+		default:
+			TEE_Panic(function);
+			break;
+		}
+		break;
+
+	case SKS_CKM_AES_CCM:
+	case SKS_CKM_AES_GCM:
+		if (step == SKS_FUNC_STEP_FINAL)
+			break;
+
+		if (!in) {
+			DMSG("No input data");
+			return SKS_BAD_PARAM;
+		}
+
+		switch (function) {
+		case SKS_FUNCTION_ENCRYPT:
+			res = TEE_AEUpdate(proc->tee_op_handle,
+					   in_buf, in_size, out_buf, &out_size);
+			output_data = true;
+			rv = tee2sks_error(res);
+
+			if (step == SKS_FUNC_STEP_ONESHOT &&
+			    (rv == SKS_OK || rv == SKS_SHORT_BUFFER)) {
+				out_buf = (char *)out_buf + out_size;
+				out_size2 -= out_size;
+			}
+			break;
+		case SKS_FUNCTION_DECRYPT:
+			rv = tee_ae_decrypt_update(proc, in_buf, in_size);
+			out_size = 0;
+			output_data = true;
+			break;
+		default:
+			TEE_Panic(function);
+			break;
+		}
+		break;
+	default:
+		TEE_Panic(proc->mecha_type);
+		break;
+	}
+
+	if (step == SKS_FUNC_STEP_UPDATE)
+		goto bail;
+
+	/*
+	 * Finalize (SKS_FUNC_STEP_ONESHOT/_FINAL) operation
+	 */
+	switch (session->processing->mecha_type) {
+	case SKS_CKM_AES_CMAC_GENERAL:
+	case SKS_CKM_AES_CMAC:
+	case SKS_CKM_MD5_HMAC:
+	case SKS_CKM_SHA_1_HMAC:
+	case SKS_CKM_SHA224_HMAC:
+	case SKS_CKM_SHA256_HMAC:
+	case SKS_CKM_SHA384_HMAC:
+	case SKS_CKM_SHA512_HMAC:
+	case SKS_CKM_AES_XCBC_MAC:
+		switch (function) {
+		case SKS_FUNCTION_SIGN:
+			res = TEE_MACComputeFinal(proc->tee_op_handle,
+						  NULL, 0, out_buf, &out_size);
+			output_data = true;
+			rv = tee2sks_error(res);
+			break;
+		case SKS_FUNCTION_VERIFY:
+			res = TEE_MACCompareFinal(proc->tee_op_handle,
+						  NULL, 0, in2_buf, in2_size);
+			rv = tee2sks_error(res);
+			break;
+		default:
+			TEE_Panic(function);
+			break;
+		}
+		break;
+
+	case SKS_CKM_AES_ECB:
+	case SKS_CKM_AES_CBC:
+	case SKS_CKM_AES_CBC_PAD:
+	case SKS_CKM_AES_CTS:
+	case SKS_CKM_AES_CTR:
+		if (step == SKS_FUNC_STEP_ONESHOT && !in) {
+			DMSG("No input data");
+			return SKS_BAD_PARAM;
+		}
+		switch (function) {
+		case SKS_FUNCTION_ENCRYPT:
+		case SKS_FUNCTION_DECRYPT:
+			res = TEE_CipherDoFinal(proc->tee_op_handle,
+						in_buf, in_size,
+						out_buf, &out_size);
+			output_data = true;
+			rv = tee2sks_error(res);
+			break;
+		default:
+			TEE_Panic(function);
+			break;
+		}
+		break;
+
+	case SKS_CKM_AES_CCM:
+	case SKS_CKM_AES_GCM:
+		switch (function) {
+		case SKS_FUNCTION_ENCRYPT:
+			rv = tee_ae_encrypt_final(proc, out_buf, &out_size2);
+			output_data = true;
+
+			/*
+			 * FIXME: on failure & ONESHOT, restore operation state
+			 * before TEE_AEUpdate() was called
+			 */
+			if (step == SKS_FUNC_STEP_ONESHOT) {
+				out_size += out_size2;
+			} else {
+				out_size = out_size2;
+			}
+			break;
+		case SKS_FUNCTION_DECRYPT:
+			rv = tee_ae_decrypt_final(proc, out_buf, &out_size);
+			output_data = true;
+			break;
+		default:
+			TEE_Panic(function);
+			break;
+		}
+		break;
+	default:
+		TEE_Panic(proc->mecha_type);
+		break;
+	}
+
+bail:
+	if (output_data && (rv == SKS_OK || rv == SKS_SHORT_BUFFER)) {
+		if (io2)
+			io2->memref.size = out_size;
+		else
+			rv = SKS_BAD_PARAM;
+	}
+
+	return rv;
+}
+
+uint32_t do_symm_derivation(struct pkcs11_session *session __unused,
+			     struct sks_attribute_head *proc_params __unused,
+			     struct sks_object *parent_key __unused,
+			     struct sks_attrs_head **head __unused)
+{
+	EMSG("Symm key derivation not yet supported");
+	return SKS_ERROR;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sanitize_object.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sanitize_object.c
new file mode 100644
index 0000000..d7b7449
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sanitize_object.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sks_internal_abi.h>
+#include <sks_ta.h>
+#include <stdlib.h>
+#include <string.h>
+#include <util.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <trace.h>
+
+#include "attributes.h"
+#include "sanitize_object.h"
+#include "serializer.h"
+#include "sks_helpers.h"
+
+/*
+ * Functions to generate a serialized object.
+ * References are pointers to struct serializer.
+ */
+#define SKS_ID(sks)			case sks:
+
+bool sanitize_consistent_class_and_type(struct sks_attrs_head *attrs)
+{
+	uint32_t class = get_class(attrs);
+	uint32_t type = get_type(attrs);
+
+	switch (class) {
+	case SKS_CKO_DATA:
+		return true;
+	case SKS_CKO_SECRET_KEY:
+		return key_type_is_symm_key(type);
+	case SKS_CKO_MECHANISM:
+		return mechanism_is_valid(type);
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+		return key_type_is_asymm_key(type);
+	case SKS_CKO_CERTIFICATE:
+		return certificate_is_valid(type);
+	case SKS_CKO_OTP_KEY:
+	case SKS_CKO_DOMAIN_PARAMETERS:
+	case SKS_CKO_HW_FEATURE:
+	default:
+		return false;
+	}
+
+	return false;
+}
+
+/* Sanitize class/type in a client attribute list */
+static uint32_t sanitize_class_and_type(struct sks_attrs_head **dst,
+				     void *src)
+{
+	struct sks_object_head head;
+	char *cur = NULL;
+	char *end = NULL;
+	size_t len = 0;
+	uint32_t class_found = 0;
+	uint32_t type_found = 0;
+	struct sks_attribute_head cli_ref;
+	uint32_t rc = SKS_OK;
+	size_t src_size = 0;
+
+	TEE_MemMove(&head, src, sizeof(head));
+	TEE_MemFill(&cli_ref, 0, sizeof(cli_ref));
+
+	src_size = sizeof(struct sks_object_head) + head.attrs_size;
+
+	class_found = SKS_UNDEFINED_ID;
+	type_found = SKS_UNDEFINED_ID;
+
+	cur = (char *)src + sizeof(struct sks_object_head);
+	end = cur + head.attrs_size;
+
+	for (; cur < end; cur += len) {
+		/* Structure aligned copy of client reference in the object */
+		TEE_MemMove(&cli_ref, cur, sizeof(cli_ref));
+		len = sizeof(cli_ref) + cli_ref.size;
+
+		if (sks_attr_is_class(cli_ref.id)) {
+			uint32_t class;
+
+			if (cli_ref.size != sks_attr_is_class(cli_ref.id)) {
+				rc = SKS_CKR_TEMPLATE_INCONSISTENT;
+				goto bail;
+			}
+
+			TEE_MemMove(&class, cur + sizeof(cli_ref), cli_ref.size);
+
+			if (class_found != SKS_UNDEFINED_ID &&
+			    class_found != class) {
+				EMSG("Conflicting class value");
+				rc = SKS_CKR_TEMPLATE_INCONSISTENT;
+				goto bail;
+			}
+
+			class_found = class;
+			continue;
+		}
+
+		/* The attribute is a type-in-class */
+		if (sks_attr_is_type(cli_ref.id)) {
+			uint32_t type = 0;
+
+			if (cli_ref.size != sks_attr_is_type(cli_ref.id)) {
+				rc = SKS_CKR_TEMPLATE_INCONSISTENT;
+				goto bail;
+			}
+
+			TEE_MemMove(&type, cur + sizeof(cli_ref), cli_ref.size);
+
+			if (type_found != SKS_UNDEFINED_ID &&
+			    type_found != type) {
+				EMSG("Conflicting type-in-class value");
+				rc = SKS_CKR_TEMPLATE_INCONSISTENT;
+				goto bail;
+			}
+
+			type_found = type;
+		}
+	}
+
+	/* Sanity */
+	if (cur != end) {
+		EMSG("Unexpected alignment issue");
+		rc = SKS_FAILED;
+		goto bail;
+	}
+
+	if (class_found != SKS_UNDEFINED_ID) {
+		rc = add_attribute(dst, SKS_CKA_CLASS,
+				   &class_found, sizeof(uint32_t));
+		if (rc)
+			goto bail;
+	}
+
+	if (type_found != SKS_UNDEFINED_ID) {
+		rc = add_attribute(dst, SKS_CKA_KEY_TYPE,
+				   &type_found, sizeof(uint32_t));
+	}
+
+bail:
+	if (rc)
+		trace_attributes_from_api_head("bad-template", src, src_size);
+
+	return rc;
+}
+
+static uint32_t sanitize_boolprop(struct sks_attrs_head **dst,
+				struct sks_attribute_head *cli_ref,
+				char *cur, uint32_t *boolprop_base,
+				uint32_t *sanity)
+{
+	int shift = 0;
+	uint32_t mask = 0;
+	uint32_t value = 0;
+	uint32_t *boolprop_ptr = NULL;
+	uint32_t *sanity_ptr = NULL;
+
+	/* Get the boolean property shift position and value */
+	shift = sks_attr2boolprop_shift(cli_ref->id);
+	if (shift < 0)
+		return SKS_NOT_FOUND;
+
+	if (shift >= SKS_MAX_BOOLPROP_SHIFT)
+		return SKS_FAILED;
+
+	mask = 1 << (shift % 32);
+	if ((*(uint8_t *)(cur + sizeof(*cli_ref))) == SKS_TRUE)
+		value = mask;
+	else
+		value = 0;
+
+	/* Locate the current config value for the boolean property */
+	boolprop_ptr = boolprop_base + (shift / 32);
+	sanity_ptr = sanity + (shift / 32);
+
+	/* Error if already set to a different boolean value */
+	if (*sanity_ptr & mask && value != (*boolprop_ptr & mask))
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+
+	if (value)
+		*boolprop_ptr |= mask;
+	else
+		*boolprop_ptr &= ~mask;
+
+	/* Store the attribute inside the serialized data */
+	if (!(*sanity_ptr & mask)) {
+		uint32_t rc = 0;
+		uint8_t sks_bool = !!value;
+
+		rc = add_attribute(dst, SKS_BOOLPROPS_BASE + shift,
+				   &sks_bool, sizeof(uint8_t));
+		if (rc)
+			return rc;
+	}
+
+	*sanity_ptr |= mask;
+
+	return SKS_OK;
+}
+
+static uint32_t sanitize_boolprops(struct sks_attrs_head **dst, void *src)
+{
+	struct sks_object_head head;
+	char *cur = NULL;
+	char *end = NULL;
+	size_t len = 0;
+	struct sks_attribute_head cli_ref;
+	uint32_t sanity[SKS_MAX_BOOLPROP_ARRAY] = { 0 };
+	uint32_t boolprops[SKS_MAX_BOOLPROP_ARRAY] = { 0 };
+	uint32_t rc = 0;
+
+	TEE_MemMove(&head, src, sizeof(head));
+	TEE_MemFill(&cli_ref, 0, sizeof(cli_ref));
+
+	cur = (char *)src + sizeof(struct sks_object_head);
+	end = cur + head.attrs_size;
+
+	for (; cur < end; cur += len) {
+		/* Structure aligned copy of the cli_ref in the object */
+		TEE_MemMove(&cli_ref, cur, sizeof(cli_ref));
+		len = sizeof(cli_ref) + cli_ref.size;
+
+		rc = sanitize_boolprop(dst, &cli_ref, cur, boolprops, sanity);
+		if (rc != SKS_OK && rc != SKS_NOT_FOUND)
+			return rc;
+	}
+
+	return SKS_OK;
+}
+
+/* Counterpart of serialize_indirect_attribute() */
+static uint32_t sanitize_indirect_attr(struct sks_attrs_head **dst,
+					struct sks_attribute_head *cli_ref,
+					char *cur)
+{
+	struct sks_attrs_head *obj2 = NULL;
+	uint32_t rc = 0;
+	uint32_t class = get_class(*dst);
+
+	if (class == SKS_UNDEFINED_ID)
+		return SKS_NOT_FOUND;
+
+	/*
+	 * Serialized attributes: current applicable only the key templates which
+	 * are tables of attributes.
+	 */
+	switch (cli_ref->id) {
+	case SKS_CKA_WRAP_TEMPLATE:
+	case SKS_CKA_UNWRAP_TEMPLATE:
+	case SKS_CKA_DERIVE_TEMPLATE:
+		break;
+	default:
+		return SKS_NOT_FOUND;
+	}
+	/* Such attributes are expected only for keys (and vendor defined) */
+	if (sks_attr_class_is_key(class))
+		return SKS_CKR_TEMPLATE_INCONSISTENT;
+
+	rc = init_attributes_head(&obj2);
+	if (rc != SKS_OK)
+		return rc;
+
+	/* Build a new serial object while sanitizing the attributes list */
+	rc = sanitize_client_object(&obj2, cur + sizeof(*cli_ref),
+				    cli_ref->size);
+	if (rc)
+		return rc;
+
+	return add_attribute(dst, cli_ref->id, obj2,
+			     sizeof(struct sks_attrs_head) + obj2->attrs_size);
+}
+
+uint32_t sanitize_client_object(struct sks_attrs_head **dst,
+				void *src, size_t size)
+{
+	struct sks_object_head head;
+	uint32_t rc = 0;
+	char *cur = NULL;
+	char *end = NULL;
+	size_t next = 0;
+
+	TEE_MemFill(&head, 0, sizeof(head));
+
+	if (size < sizeof(struct sks_object_head))
+		return SKS_BAD_PARAM;
+
+	TEE_MemMove(&head, src, sizeof(struct sks_object_head));
+
+	if (size < (sizeof(struct sks_object_head) + head.attrs_size))
+		return SKS_BAD_PARAM;
+
+	rc = init_attributes_head(dst);
+	if (rc != SKS_OK)
+		goto bail;
+
+	rc = sanitize_class_and_type(dst, src);
+	if (rc)
+		goto bail;
+
+	rc = sanitize_boolprops(dst, src);
+	if (rc)
+		goto bail;
+
+	cur = (char *)src + sizeof(struct sks_object_head);
+	end = cur + head.attrs_size;
+
+	for (; cur < end; cur += next) {
+		struct sks_attribute_head cli_ref;
+
+		if (cur + sizeof(cli_ref) > end)
+			return SKS_BAD_PARAM;
+
+		TEE_MemMove(&cli_ref, cur, sizeof(cli_ref));
+		next = sizeof(cli_ref) + cli_ref.size;
+
+		if (sks_attr_is_class(cli_ref.id) ||
+		    sks_attr_is_type(cli_ref.id) ||
+		    sks_attr2boolprop_shift(cli_ref.id) >= 0)
+			continue;
+
+		rc = sanitize_indirect_attr(dst, &cli_ref, cur);
+		if (rc == SKS_OK)
+			continue;
+		if (rc != SKS_NOT_FOUND)
+			goto bail;
+
+		if (!valid_sks_attribute_id(cli_ref.id, cli_ref.size)) {
+			EMSG("Invalid attribute id 0x%" PRIx32, cli_ref.id);
+			rc = SKS_CKR_TEMPLATE_INCONSISTENT;
+			goto bail;
+		}
+
+		rc = add_attribute(dst, cli_ref.id, cur + sizeof(cli_ref),
+				   cli_ref.size);
+		if (rc)
+			goto bail;
+	}
+
+	/* sanity */
+	if (cur != end) {
+		EMSG("Unexpected alignment issue");
+		rc = SKS_FAILED;
+		goto bail;
+	}
+
+bail:
+	return rc;
+}
+
+/*
+ * Debug: dump object attribute array to output trace
+ */
+
+static uint32_t __trace_attributes(char *prefix, void *src, void *end)
+{
+	size_t next = 0;
+	char *prefix2 = NULL;
+	size_t prefix_len = strlen(prefix);
+	char *cur = src;
+	uint32_t rc = 0;
+
+	/* append 4 spaces to the prefix plus terminal '\0' */
+	prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
+	if (!prefix2)
+		return SKS_MEMORY;
+
+	TEE_MemMove(prefix2, prefix, prefix_len + 1);
+	TEE_MemFill(prefix2 + prefix_len, ' ', 4);
+	*(prefix2 + prefix_len + 4) = '\0';
+
+	for (; cur < (char *)end; cur += next) {
+		struct sks_ref sks_ref;
+		uint8_t data[4] = { 0 };
+		uint32_t data_u32 = 0;
+
+		TEE_MemMove(&sks_ref, cur, sizeof(sks_ref));
+		TEE_MemMove(&data[0], cur + sizeof(sks_ref),
+			    MIN(sks_ref.size, sizeof(data)));
+		TEE_MemMove(&data_u32, cur + sizeof(sks_ref), sizeof(data_u32));
+
+		next = sizeof(sks_ref) + sks_ref.size;
+
+		IMSG_RAW("%s Attr %s / %s (0x%04" PRIx32 " %" PRIu32 "-byte)",
+			prefix, sks2str_attr(sks_ref.id),
+			sks2str_attr_value(sks_ref.id, sks_ref.size,
+					   cur + sizeof(sks_ref)),
+			sks_ref.id, sks_ref.size);
+
+		switch (sks_ref.size) {
+		case 0:
+			break;
+		case 1:
+			DMSG_RAW("%s Attr byte value: %02x", prefix, data[0]);
+			break;
+		case 2:
+			DMSG_RAW("%s Attr byte value: %02x %02x",
+				 prefix, data[0], data[1]);
+			break;
+		case 3:
+			DMSG_RAW("%s Attr byte value: %02x %02x %02x",
+				 prefix, data[0], data[1], data[2]);
+			break;
+		case 4:
+			DMSG_RAW("%s Attr byte value: %02x %02x %02x %02x",
+				 prefix, data[0], data[1], data[2], data[3]);
+			break;
+		default:
+			DMSG_RAW("%s Attr byte value: %02x %02x %02x %02x ...",
+				 prefix, data[0], data[1], data[2], data[3]);
+			break;
+		}
+
+		switch (sks_ref.id) {
+		case SKS_CKA_WRAP_TEMPLATE:
+		case SKS_CKA_UNWRAP_TEMPLATE:
+		case SKS_CKA_DERIVE_TEMPLATE:
+			rc = trace_attributes_from_api_head(prefix2,
+							cur + sizeof(sks_ref),
+							(char *)end - cur);
+			if (rc)
+				return rc;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Sanity */
+	if (cur != (char *)end) {
+		EMSG("Warning: unexpected alignment issue");
+	}
+
+	TEE_Free(prefix2);
+	return SKS_OK;
+}
+
+uint32_t trace_attributes_from_api_head(const char *prefix,
+					void *ref, size_t size)
+{
+	struct sks_object_head head;
+	char *pre = NULL;
+	size_t offset = 0;
+	uint32_t rc = 0;
+
+	TEE_MemMove(&head, ref, sizeof(head));
+
+	if (size > sizeof(head) + head.attrs_size) {
+		EMSG("template overflows client buffer (%zu/%zu)",
+			size, sizeof(head) + head.attrs_size);
+		return SKS_FAILED;
+	}
+
+
+	pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
+	if (!pre)
+		return SKS_MEMORY;
+	if (prefix)
+		TEE_MemMove(pre, prefix, strlen(prefix));
+
+	IMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
+	IMSG_RAW("%s| %" PRIx32 " item(s) - %" PRIu32 " bytes",
+		pre, head.attrs_count, head.attrs_size);
+
+	offset = sizeof(head);
+	pre[prefix ? strlen(prefix) : 0] = '|';
+	rc = __trace_attributes(pre, (char *)ref + offset,
+			      (char *)ref + offset + head.attrs_size);
+	if (rc)
+		goto bail;
+
+	IMSG_RAW("%s`-----------------------", prefix ? prefix : "");
+
+bail:
+	TEE_Free(pre);
+	return rc;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sanitize_object.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sanitize_object.h
new file mode 100644
index 0000000..86013d2
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sanitize_object.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SERIAL_SANITIZE_H
+#define __SERIAL_SANITIZE_H
+
+#include "serializer.h"
+
+/*
+ * sanitize_consistent_class_and_type - Check object type matches object class
+ *
+ * @attrs - object attributes
+ * Return true if class/type matches, else return false
+ */
+bool sanitize_consistent_class_and_type(struct sks_attrs_head *attrs);
+
+/**
+ * sanitize_client_object - Setup a serializer from a serialized object
+ *
+ * @dst - output structure tracking the generated serial object
+ * @head - pointer to the formatted serialized object (its head)
+ * @size - byte size of the serialized binary blob
+ *
+ * This function copies an attribute list from a client API attribute head
+ * into a SKS internal attribute structure. It generates a serialized attribute
+ * list with a consistent format and identified attribute IDs.
+ *
+ * ref points to a blob starting with a sks head.
+ * ref may pointer to an unaligned address.
+ * This function allocates, fill and returns a serialized attribute list
+ * into a serializer container.
+ */
+uint32_t sanitize_client_object(struct sks_attrs_head **dst,
+				void *head, size_t size);
+
+/* Debug: dump attribute content as debug traces */
+uint32_t trace_attributes_from_api_head(const char *prefix,
+					void *ref, size_t size);
+
+#endif /*__SERIAL_SANITIZE_H*/
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/serializer.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/serializer.c
new file mode 100644
index 0000000..09b129f
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/serializer.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#include <sks_internal_abi.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string_ext.h>
+#include <tee_internal_api.h>
+#include <tee_internal_api_extensions.h>
+#include <trace.h>
+
+#include "serializer.h"
+#include "sks_helpers.h"
+
+/*
+ * Util routines for serializes unformatted arguments in a client memref
+ */
+void serialargs_init(struct serialargs *args, void *in, size_t size)
+{
+	args->start = in;
+	args->next = in;
+	args->size = size;
+}
+
+uint32_t serialargs_get(struct serialargs *args, void *out, size_t size)
+{
+	if (args->next + size > args->start + args->size) {
+		EMSG("arg too short: full %zd, remain %zd, expect %zd",
+		     args->size, args->size - (args->next - args->start), size);
+		return SKS_BAD_PARAM;
+	}
+
+	TEE_MemMove(out, args->next, size);
+
+	args->next += size;
+
+	return SKS_OK;
+}
+
+uint32_t serialargs_alloc_and_get(struct serialargs *args,
+				  void **out, size_t size)
+{
+	void *ptr = NULL;
+
+	if (!size) {
+		*out = NULL;
+		return SKS_OK;
+	}
+
+	if (args->next + size > args->start + args->size) {
+		EMSG("arg too short: full %zd, remain %zd, expect %zd",
+		     args->size, args->size - (args->next - args->start), size);
+		return SKS_BAD_PARAM;
+	}
+
+	ptr = TEE_Malloc(size, TEE_MALLOC_FILL_ZERO);
+	if (!ptr)
+		return SKS_MEMORY;
+
+	TEE_MemMove(ptr, args->next, size);
+
+	args->next += size;
+	*out = ptr;
+
+	return SKS_OK;
+}
+
+uint32_t serialargs_get_ptr(struct serialargs *args, void **out, size_t size)
+{
+	void *ptr = args->next;
+
+	if (!size) {
+		*out = NULL;
+		return SKS_OK;
+	}
+
+	if (args->next + size > args->start + args->size) {
+		EMSG("arg too short: full %zd, remain %zd, expect %zd",
+		     args->size, args->size - (args->next - args->start), size);
+		return SKS_BAD_PARAM;
+	}
+
+	args->next += size;
+	*out = ptr;
+
+	return SKS_OK;
+}
+
+uint32_t serialargs_alloc_get_one_attribute(struct serialargs *args __unused,
+					    struct sks_attribute_head **out __unused)
+{
+	struct sks_attribute_head head;
+	size_t out_size = sizeof(head);
+	void *pref = NULL;
+
+	TEE_MemFill(&head, 0, sizeof(head));
+
+	if (args->next + out_size > args->start + args->size) {
+		EMSG("arg too short: full %zd, remain %zd, expect at least %zd",
+		     args->size, args->size - (args->next - args->start),
+		     out_size);
+		return SKS_BAD_PARAM;
+	}
+
+	TEE_MemMove(&head, args->next, out_size);
+
+	if (head.size > (SIZE_MAX - out_size)) {
+		EMSG("arg size too big");
+		return SKS_BAD_PARAM;
+	}
+
+	out_size += head.size;
+	if (args->next + out_size > args->start + args->size) {
+		EMSG("arg too short: full %zd, remain %zd, expect %zd",
+		     args->size, args->size - (args->next - args->start),
+		     out_size);
+		return SKS_BAD_PARAM;
+	}
+
+	pref = TEE_Malloc(out_size, TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!pref)
+		return SKS_MEMORY;
+
+	TEE_MemMove(pref, args->next, out_size);
+	args->next += out_size;
+
+	*out = pref;
+
+	return SKS_OK;
+}
+
+uint32_t serialargs_alloc_get_attributes(struct serialargs *args __unused,
+					 struct sks_object_head **out __unused)
+{
+	struct sks_object_head attr;
+	struct sks_object_head *pattr = NULL;
+	size_t attr_size = sizeof(attr);
+
+	TEE_MemFill(&attr, 0, sizeof(attr));
+
+	if (args->next + attr_size > args->start + args->size) {
+		EMSG("arg too short: full %zd, remain %zd, expect at least %zd",
+		     args->size, args->size - (args->next - args->start),
+		     attr_size);
+		return SKS_BAD_PARAM;
+	}
+
+	TEE_MemMove(&attr, args->next, attr_size);
+
+	if (attr.attrs_size > (SIZE_MAX - attr_size)) {
+		EMSG("arg size too big");
+		return SKS_BAD_PARAM;
+	}
+
+	attr_size += attr.attrs_size;
+	if (args->next + attr_size > args->start + args->size) {
+		EMSG("arg too short: full %zd, remain %zd, expect %zd",
+		     args->size, args->size - (args->next - args->start),
+		     attr_size);
+		return SKS_BAD_PARAM;
+	}
+
+	pattr = TEE_Malloc(attr_size, TEE_USER_MEM_HINT_NO_FILL_ZERO);
+	if (!pattr)
+		return SKS_MEMORY;
+
+	TEE_MemMove(pattr, args->next, attr_size);
+	args->next += attr_size;
+
+	*out = pattr;
+
+	return SKS_OK;
+}
+
+/*
+ * serialize - serialize input data in buffer
+ *
+ * Serialize data in provided buffer.
+ * Insure 64byte alignment of appended data in the buffer.
+ */
+uint32_t serialize(char **bstart, size_t *blen, void *data, size_t len)
+{
+	char *buf = NULL;
+	size_t nlen = *blen + len;
+
+	buf = TEE_Realloc(*bstart, nlen);
+	if (!buf)
+		return SKS_MEMORY;
+
+	TEE_MemMove(buf + *blen, data, len);
+
+	*blen = nlen;
+	*bstart = buf;
+
+	return SKS_OK;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/serializer.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/serializer.h
new file mode 100644
index 0000000..05b7c47
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/serializer.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#ifndef __SERIALIZER_H__
+#define __SERIALIZER_H__
+
+#include <sks_internal_abi.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <tee_internal_api.h>
+
+/*
+ * Util routines for serializes unformated arguments in a client memref
+ */
+struct serialargs {
+	char *start;
+	char *next;
+	size_t size;
+};
+
+void serialargs_init(struct serialargs *args, void *in, size_t size);
+
+uint32_t serialargs_get(struct serialargs *args, void *out, size_t sz);
+
+uint32_t serialargs_get_ptr(struct serialargs *args, void **out, size_t size);
+
+uint32_t serialargs_alloc_get_one_attribute(struct serialargs *args,
+					    struct sks_attribute_head **out);
+
+uint32_t serialargs_alloc_get_attributes(struct serialargs *args,
+					 struct sks_object_head **out);
+
+uint32_t serialargs_alloc_and_get(struct serialargs *args,
+				   void **out, size_t size);
+
+#define SKS_MAX_BOOLPROP_SHIFT	64
+#define SKS_MAX_BOOLPROP_ARRAY	(SKS_MAX_BOOLPROP_SHIFT / sizeof(uint32_t))
+
+/**
+ * serialize - Append data into a serialized buffer
+ */
+uint32_t serialize(char **bstart, size_t *blen, void *data, size_t len);
+
+#endif /*__SERIALIZER_H*/
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sks_helpers.c b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sks_helpers.c
new file mode 100644
index 0000000..c33397a
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sks_helpers.c
@@ -0,0 +1,895 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#include <assert.h>
+#include <sks_internal_abi.h>
+#include <sks_ta.h>
+#include <string.h>
+#include <util.h>
+#include <tee_internal_api.h>
+
+#include "attributes.h"
+#include "object.h"
+#include "pkcs11_attributes.h"
+#include "processing.h"
+#include "sks_helpers.h"
+
+static const char __maybe_unused unknown[] = "<unknown-identifier>";
+
+struct attr_size {
+	uint32_t id;
+	uint32_t size;
+#if CFG_TEE_TA_LOG_LEVEL > 0
+	const char *string;
+#endif
+};
+
+#if CFG_TEE_TA_LOG_LEVEL > 0
+#define SKS_ID_SZ(_id, _size)	{ .id = _id, .size = _size, .string = #_id }
+#else
+#define SKS_ID_SZ(_id, _size)	{ .id = _id, .size = _size }
+#endif
+
+static const struct attr_size attr_ids[] = {
+	SKS_ID_SZ(SKS_CKA_CLASS, 4),
+	SKS_ID_SZ(SKS_CKA_KEY_TYPE, 4),
+	SKS_ID_SZ(SKS_CKA_VALUE, 0),
+	SKS_ID_SZ(SKS_CKA_VALUE_LEN, 4),
+	SKS_ID_SZ(SKS_CKA_LABEL, 0),
+	SKS_ID_SZ(SKS_CKA_WRAP_TEMPLATE, 0),
+	SKS_ID_SZ(SKS_CKA_UNWRAP_TEMPLATE, 0),
+	SKS_ID_SZ(SKS_CKA_DERIVE_TEMPLATE, 0),
+	SKS_ID_SZ(SKS_CKA_START_DATE, 4),
+	SKS_ID_SZ(SKS_CKA_END_DATE, 4),
+	SKS_ID_SZ(SKS_CKA_OBJECT_ID, 0),
+	SKS_ID_SZ(SKS_CKA_APPLICATION, 0),
+	SKS_ID_SZ(SKS_CKA_MECHANISM_TYPE, 4),
+	SKS_ID_SZ(SKS_CKA_ID, 0),
+	SKS_ID_SZ(SKS_CKA_ALLOWED_MECHANISMS, 0),
+	SKS_ID_SZ(SKS_CKA_EC_POINT, 0),
+	SKS_ID_SZ(SKS_CKA_EC_PARAMS, 0),
+	SKS_ID_SZ(SKS_CKA_MODULUS, 0),
+	SKS_ID_SZ(SKS_CKA_MODULUS_BITS, 4),
+	SKS_ID_SZ(SKS_CKA_PUBLIC_EXPONENT, 0),
+	SKS_ID_SZ(SKS_CKA_PRIVATE_EXPONENT, 0),
+	SKS_ID_SZ(SKS_CKA_PRIME_1, 0),
+	SKS_ID_SZ(SKS_CKA_PRIME_2, 0),
+	SKS_ID_SZ(SKS_CKA_EXPONENT_1, 0),
+	SKS_ID_SZ(SKS_CKA_EXPONENT_2, 0),
+	SKS_ID_SZ(SKS_CKA_COEFFICIENT, 0),
+	SKS_ID_SZ(SKS_CKA_SUBJECT, 0),
+	SKS_ID_SZ(SKS_CKA_PUBLIC_KEY_INFO, 0),
+	SKS_ID_SZ(SKS_CKA_CERTIFICATE_TYPE, 4),
+	SKS_ID_SZ(SKS_CKA_CERTIFICATE_CATEGORY, 4),
+	SKS_ID_SZ(SKS_CKA_ISSUER, 0),
+	SKS_ID_SZ(SKS_CKA_SERIAL_NUMBER, 0),
+	SKS_ID_SZ(SKS_CKA_URL, 0),
+	SKS_ID_SZ(SKS_CKA_HASH_OF_SUBJECT_PUBLIC_KEY, 0),
+	SKS_ID_SZ(SKS_CKA_HASH_OF_ISSUER_PUBLIC_KEY, 0),
+	SKS_ID_SZ(SKS_CKA_NAME_HASH_ALGORITHM, 4),
+	SKS_ID_SZ(SKS_CKA_KEY_GEN_MECHANISM, 4),
+	/* Below are boolean attributes */
+	SKS_ID_SZ(SKS_CKA_TOKEN, 1),
+	SKS_ID_SZ(SKS_CKA_PRIVATE, 1),
+	SKS_ID_SZ(SKS_CKA_TRUSTED, 1),
+	SKS_ID_SZ(SKS_CKA_SENSITIVE, 1),
+	SKS_ID_SZ(SKS_CKA_ENCRYPT, 1),
+	SKS_ID_SZ(SKS_CKA_DECRYPT, 1),
+	SKS_ID_SZ(SKS_CKA_WRAP, 1),
+	SKS_ID_SZ(SKS_CKA_UNWRAP, 1),
+	SKS_ID_SZ(SKS_CKA_SIGN, 1),
+	SKS_ID_SZ(SKS_CKA_SIGN_RECOVER, 1),
+	SKS_ID_SZ(SKS_CKA_VERIFY, 1),
+	SKS_ID_SZ(SKS_CKA_VERIFY_RECOVER, 1),
+	SKS_ID_SZ(SKS_CKA_DERIVE, 1),
+	SKS_ID_SZ(SKS_CKA_EXTRACTABLE, 1),
+	SKS_ID_SZ(SKS_CKA_LOCAL, 1),
+	SKS_ID_SZ(SKS_CKA_NEVER_EXTRACTABLE, 1),
+	SKS_ID_SZ(SKS_CKA_ALWAYS_SENSITIVE, 1),
+	SKS_ID_SZ(SKS_CKA_MODIFIABLE, 1),
+	SKS_ID_SZ(SKS_CKA_COPYABLE, 1),
+	SKS_ID_SZ(SKS_CKA_DESTROYABLE, 1),
+	SKS_ID_SZ(SKS_CKA_ALWAYS_AUTHENTICATE, 1),
+	SKS_ID_SZ(SKS_CKA_WRAP_WITH_TRUSTED, 1),
+	/* Specific SKS attribute IDs */
+	SKS_ID_SZ(SKS_UNDEFINED_ID, 0),
+};
+
+struct processing_id {
+	uint32_t id;
+	bool supported;
+#if CFG_TEE_TA_LOG_LEVEL > 0
+	const char *string;
+#endif
+};
+
+#if CFG_TEE_TA_LOG_LEVEL > 0
+#define SKS_PROCESSING_ID(_id) \
+			{ .id = _id, .supported = true, .string = #_id }
+#define SKS_UNSUPPORTED_PROCESSING_ID(_id) \
+			{ .id = _id, .supported = false, .string = #_id }
+#else
+#define SKS_PROCESSING_ID(_id) \
+			{ .id = _id, .supported = true }
+#define SKS_UNSUPPORTED_PROCESSING_ID(_id) \
+			{ .id = _id, .supported = false }
+
+#endif
+
+static const struct processing_id __maybe_unused processing_ids[] = {
+	SKS_PROCESSING_ID(SKS_CKM_AES_ECB),
+	SKS_PROCESSING_ID(SKS_CKM_AES_CBC),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_AES_CBC_PAD),
+	SKS_PROCESSING_ID(SKS_CKM_AES_CTR),
+	SKS_PROCESSING_ID(SKS_CKM_AES_GCM),
+	SKS_PROCESSING_ID(SKS_CKM_AES_CCM),
+	SKS_PROCESSING_ID(SKS_CKM_AES_CTS),
+	SKS_PROCESSING_ID(SKS_CKM_AES_GMAC),
+	SKS_PROCESSING_ID(SKS_CKM_AES_CMAC),
+	SKS_PROCESSING_ID(SKS_CKM_AES_CMAC_GENERAL),
+	SKS_PROCESSING_ID(SKS_CKM_AES_ECB_ENCRYPT_DATA),
+	SKS_PROCESSING_ID(SKS_CKM_AES_CBC_ENCRYPT_DATA),
+	SKS_PROCESSING_ID(SKS_CKM_AES_KEY_GEN),
+	SKS_PROCESSING_ID(SKS_CKM_GENERIC_SECRET_KEY_GEN),
+	SKS_PROCESSING_ID(SKS_CKM_MD5_HMAC),
+	SKS_PROCESSING_ID(SKS_CKM_SHA_1_HMAC),
+	SKS_PROCESSING_ID(SKS_CKM_SHA224_HMAC),
+	SKS_PROCESSING_ID(SKS_CKM_SHA256_HMAC),
+	SKS_PROCESSING_ID(SKS_CKM_SHA384_HMAC),
+	SKS_PROCESSING_ID(SKS_CKM_SHA512_HMAC),
+	SKS_PROCESSING_ID(SKS_CKM_AES_XCBC_MAC),
+	SKS_PROCESSING_ID(SKS_CKM_EC_KEY_PAIR_GEN),
+	SKS_PROCESSING_ID(SKS_CKM_ECDSA),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_ECDSA_SHA1),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_ECDSA_SHA224),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_ECDSA_SHA256),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_ECDSA_SHA384),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_ECDSA_SHA512),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_ECDH1_DERIVE),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_ECDH1_COFACTOR_DERIVE),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_ECMQV_DERIVE),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_ECDH_AES_KEY_WRAP),
+	SKS_PROCESSING_ID(SKS_CKM_RSA_PKCS_KEY_PAIR_GEN),
+	SKS_PROCESSING_ID(SKS_CKM_RSA_PKCS),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_RSA_9796),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_RSA_X_509),
+	SKS_PROCESSING_ID(SKS_CKM_SHA1_RSA_PKCS),
+	SKS_PROCESSING_ID(SKS_CKM_RSA_PKCS_OAEP),
+	SKS_PROCESSING_ID(SKS_CKM_SHA1_RSA_PKCS_PSS),
+	SKS_PROCESSING_ID(SKS_CKM_SHA256_RSA_PKCS),
+	SKS_PROCESSING_ID(SKS_CKM_SHA384_RSA_PKCS),
+	SKS_PROCESSING_ID(SKS_CKM_SHA512_RSA_PKCS),
+	SKS_PROCESSING_ID(SKS_CKM_SHA256_RSA_PKCS_PSS),
+	SKS_PROCESSING_ID(SKS_CKM_SHA384_RSA_PKCS_PSS),
+	SKS_PROCESSING_ID(SKS_CKM_SHA512_RSA_PKCS_PSS),
+	SKS_PROCESSING_ID(SKS_CKM_SHA224_RSA_PKCS),
+	SKS_PROCESSING_ID(SKS_CKM_SHA224_RSA_PKCS_PSS),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_RSA_AES_KEY_WRAP),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_MD5),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_SHA_1),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_SHA224),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_SHA256),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_SHA384),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_CKM_SHA512),
+	SKS_UNSUPPORTED_PROCESSING_ID(SKS_UNDEFINED_ID)
+};
+
+struct string_id {
+	uint32_t id;
+#if CFG_TEE_TA_LOG_LEVEL > 0
+	const char *string;
+#endif
+};
+
+#if CFG_TEE_TA_LOG_LEVEL > 0
+#define SKS_ID(_id)		{ .id = _id, .string = #_id }
+#else
+#define SKS_ID(_id)		{ .id = _id }
+#endif
+
+static const struct string_id __maybe_unused string_cmd[] = {
+	SKS_ID(SKS_CMD_PING),
+	SKS_ID(SKS_CMD_CK_SLOT_LIST),
+	SKS_ID(SKS_CMD_CK_SLOT_INFO),
+	SKS_ID(SKS_CMD_CK_TOKEN_INFO),
+	SKS_ID(SKS_CMD_CK_MECHANISM_IDS),
+	SKS_ID(SKS_CMD_CK_MECHANISM_INFO),
+	SKS_ID(SKS_CMD_CK_INIT_TOKEN),
+	SKS_ID(SKS_CMD_CK_INIT_PIN),
+	SKS_ID(SKS_CMD_CK_SET_PIN),
+	SKS_ID(SKS_CMD_CK_OPEN_RO_SESSION),
+	SKS_ID(SKS_CMD_CK_OPEN_RW_SESSION),
+	SKS_ID(SKS_CMD_CK_CLOSE_SESSION),
+	SKS_ID(SKS_CMD_CK_SESSION_INFO),
+	SKS_ID(SKS_CMD_CK_CLOSE_ALL_SESSIONS),
+	SKS_ID(SKS_CMD_IMPORT_OBJECT),
+	SKS_ID(SKS_CMD_DESTROY_OBJECT),
+	SKS_ID(SKS_CMD_ENCRYPT_INIT),
+	SKS_ID(SKS_CMD_DECRYPT_INIT),
+	SKS_ID(SKS_CMD_ENCRYPT_UPDATE),
+	SKS_ID(SKS_CMD_DECRYPT_UPDATE),
+	SKS_ID(SKS_CMD_ENCRYPT_FINAL),
+	SKS_ID(SKS_CMD_DECRYPT_FINAL),
+	SKS_ID(SKS_CMD_GENERATE_SYMM_KEY),
+	SKS_ID(SKS_CMD_SIGN_INIT),
+	SKS_ID(SKS_CMD_VERIFY_INIT),
+	SKS_ID(SKS_CMD_SIGN_UPDATE),
+	SKS_ID(SKS_CMD_VERIFY_UPDATE),
+	SKS_ID(SKS_CMD_SIGN_FINAL),
+	SKS_ID(SKS_CMD_VERIFY_FINAL),
+	SKS_ID(SKS_CMD_FIND_OBJECTS_INIT),
+	SKS_ID(SKS_CMD_FIND_OBJECTS),
+	SKS_ID(SKS_CMD_FIND_OBJECTS_FINAL),
+	SKS_ID(SKS_CMD_GET_OBJECT_SIZE),
+	SKS_ID(SKS_CMD_GET_ATTRIBUTE_VALUE),
+	SKS_ID(SKS_CMD_SET_ATTRIBUTE_VALUE),
+	SKS_ID(SKS_CMD_DERIVE_KEY),
+	SKS_ID(SKS_CMD_INIT_PIN),
+	SKS_ID(SKS_CMD_SET_PIN),
+	SKS_ID(SKS_CMD_LOGIN),
+	SKS_ID(SKS_CMD_LOGOUT),
+	SKS_ID(SKS_CMD_GENERATE_KEY_PAIR),
+	SKS_ID(SKS_CMD_ENCRYPT_ONESHOT),
+	SKS_ID(SKS_CMD_DECRYPT_ONESHOT),
+	SKS_ID(SKS_CMD_SIGN_ONESHOT),
+	SKS_ID(SKS_CMD_VERIFY_ONESHOT),
+};
+
+static const struct string_id __maybe_unused string_rc[] = {
+	SKS_ID(SKS_CKR_OK),
+	SKS_ID(SKS_CKR_GENERAL_ERROR),
+	SKS_ID(SKS_CKR_DEVICE_MEMORY),
+	SKS_ID(SKS_CKR_ARGUMENTS_BAD),
+	SKS_ID(SKS_CKR_BUFFER_TOO_SMALL),
+	SKS_ID(SKS_CKR_FUNCTION_FAILED),
+	SKS_ID(SKS_CKR_SIGNATURE_INVALID),
+	SKS_ID(SKS_CKR_ATTRIBUTE_TYPE_INVALID),
+	SKS_ID(SKS_CKR_ATTRIBUTE_VALUE_INVALID),
+	SKS_ID(SKS_CKR_OBJECT_HANDLE_INVALID),
+	SKS_ID(SKS_CKR_KEY_HANDLE_INVALID),
+	SKS_ID(SKS_CKR_MECHANISM_INVALID),
+	SKS_ID(SKS_CKR_SESSION_HANDLE_INVALID),
+	SKS_ID(SKS_CKR_SLOT_ID_INVALID),
+	SKS_ID(SKS_CKR_MECHANISM_PARAM_INVALID),
+	SKS_ID(SKS_CKR_TEMPLATE_INCONSISTENT),
+	SKS_ID(SKS_CKR_TEMPLATE_INCOMPLETE),
+	SKS_ID(SKS_CKR_PIN_INCORRECT),
+	SKS_ID(SKS_CKR_PIN_LOCKED),
+	SKS_ID(SKS_CKR_PIN_EXPIRED),
+	SKS_ID(SKS_CKR_PIN_INVALID),
+	SKS_ID(SKS_CKR_PIN_LEN_RANGE),
+	SKS_ID(SKS_CKR_SESSION_EXISTS),
+	SKS_ID(SKS_CKR_SESSION_READ_ONLY),
+	SKS_ID(SKS_CKR_SESSION_READ_WRITE_SO_EXISTS),
+	SKS_ID(SKS_CKR_OPERATION_ACTIVE),
+	SKS_ID(SKS_CKR_KEY_TYPE_INCONSISTENT),
+	SKS_ID(SKS_CKR_KEY_FUNCTION_NOT_PERMITTED),
+	SKS_ID(SKS_CKR_OPERATION_NOT_INITIALIZED),
+	SKS_ID(SKS_CKR_TOKEN_WRITE_PROTECTED),
+	SKS_ID(SKS_CKR_TOKEN_NOT_PRESENT),
+	SKS_ID(SKS_CKR_TOKEN_NOT_RECOGNIZED),
+	SKS_ID(SKS_CKR_ACTION_PROHIBITED),
+	SKS_ID(SKS_CKR_ATTRIBUTE_READ_ONLY),
+	SKS_ID(SKS_CKR_PIN_TOO_WEAK),
+	SKS_ID(SKS_CKR_CURVE_NOT_SUPPORTED),
+	SKS_ID(SKS_CKR_DOMAIN_PARAMS_INVALID),
+	SKS_ID(SKS_CKR_USER_ALREADY_LOGGED_IN),
+	SKS_ID(SKS_CKR_USER_ANOTHER_ALREADY_LOGGED_IN),
+	SKS_ID(SKS_CKR_USER_NOT_LOGGED_IN),
+	SKS_ID(SKS_CKR_USER_PIN_NOT_INITIALIZED),
+	SKS_ID(SKS_CKR_USER_TOO_MANY_TYPES),
+	SKS_ID(SKS_CKR_USER_TYPE_INVALID),
+	SKS_ID(SKS_CKR_SESSION_READ_ONLY_EXISTS),
+	SKS_ID(SKS_CKR_KEY_SIZE_RANGE),
+	SKS_ID(SKS_CKR_ATTRIBUTE_SENSITIVE),
+	SKS_ID(SKS_CKR_SIGNATURE_LEN_RANGE),
+	SKS_ID(SKS_CKR_DATA_LEN_RANGE),
+	SKS_ID(SKS_CKR_ENCRYPTED_DATA_LEN_RANGE),
+	SKS_ID(SKS_NOT_FOUND),
+	SKS_ID(SKS_NOT_IMPLEMENTED),
+};
+
+static const struct string_id __maybe_unused string_slot_flags[] = {
+	SKS_ID(SKS_CKFS_TOKEN_PRESENT),
+	SKS_ID(SKS_CKFS_REMOVABLE_DEVICE),
+	SKS_ID(SKS_CKFS_HW_SLOT),
+};
+
+static const struct string_id __maybe_unused string_token_flags[] = {
+	SKS_ID(SKS_CKFT_RNG),
+	SKS_ID(SKS_CKFT_WRITE_PROTECTED),
+	SKS_ID(SKS_CKFT_LOGIN_REQUIRED),
+	SKS_ID(SKS_CKFT_USER_PIN_INITIALIZED),
+	SKS_ID(SKS_CKFT_RESTORE_KEY_NOT_NEEDED),
+	SKS_ID(SKS_CKFT_CLOCK_ON_TOKEN),
+	SKS_ID(SKS_CKFT_PROTECTED_AUTHENTICATION_PATH),
+	SKS_ID(SKS_CKFT_DUAL_CRYPTO_OPERATIONS),
+	SKS_ID(SKS_CKFT_TOKEN_INITIALIZED),
+	SKS_ID(SKS_CKFT_USER_PIN_COUNT_LOW),
+	SKS_ID(SKS_CKFT_USER_PIN_FINAL_TRY),
+	SKS_ID(SKS_CKFT_USER_PIN_LOCKED),
+	SKS_ID(SKS_CKFT_USER_PIN_TO_BE_CHANGED),
+	SKS_ID(SKS_CKFT_SO_PIN_COUNT_LOW),
+	SKS_ID(SKS_CKFT_SO_PIN_FINAL_TRY),
+	SKS_ID(SKS_CKFT_SO_PIN_LOCKED),
+	SKS_ID(SKS_CKFT_SO_PIN_TO_BE_CHANGED),
+	SKS_ID(SKS_CKFT_ERROR_STATE),
+};
+
+static const struct string_id __maybe_unused string_class[] = {
+	SKS_ID(SKS_CKO_SECRET_KEY),
+	SKS_ID(SKS_CKO_PUBLIC_KEY),
+	SKS_ID(SKS_CKO_PRIVATE_KEY),
+	SKS_ID(SKS_CKO_OTP_KEY),
+	SKS_ID(SKS_CKO_CERTIFICATE),
+	SKS_ID(SKS_CKO_DATA),
+	SKS_ID(SKS_CKO_DOMAIN_PARAMETERS),
+	SKS_ID(SKS_CKO_HW_FEATURE),
+	SKS_ID(SKS_CKO_MECHANISM),
+	SKS_ID(SKS_UNDEFINED_ID)
+};
+
+static const struct string_id __maybe_unused string_key_type[] = {
+	SKS_ID(SKS_CKK_AES),
+	SKS_ID(SKS_CKK_GENERIC_SECRET),
+	SKS_ID(SKS_CKK_MD5_HMAC),
+	SKS_ID(SKS_CKK_SHA_1_HMAC),
+	SKS_ID(SKS_CKK_SHA224_HMAC),
+	SKS_ID(SKS_CKK_SHA256_HMAC),
+	SKS_ID(SKS_CKK_SHA384_HMAC),
+	SKS_ID(SKS_CKK_SHA512_HMAC),
+	SKS_ID(SKS_CKK_EC),
+	SKS_ID(SKS_CKK_RSA),
+	SKS_ID(SKS_UNDEFINED_ID)
+};
+
+static const struct string_id __maybe_unused string_certificate_type[] = {
+	SKS_ID(SKS_CKC_X_509),
+	SKS_ID(SKS_CKC_X_509_ATTR_CER),
+	SKS_ID(SKS_CKC_WTLS),
+	SKS_ID(SKS_UNDEFINED_ID)
+};
+
+/* Processing IDs not exported in the TA API */
+static const struct string_id __maybe_unused string_internal_processing[] = {
+	SKS_ID(SKS_PROCESSING_IMPORT),
+	SKS_ID(SKS_PROCESSING_COPY),
+};
+
+static const struct string_id __maybe_unused string_proc_flags[] = {
+	SKS_ID(SKS_CKFM_HW),
+	SKS_ID(SKS_CKFM_ENCRYPT),
+	SKS_ID(SKS_CKFM_DECRYPT),
+	SKS_ID(SKS_CKFM_DIGEST),
+	SKS_ID(SKS_CKFM_SIGN),
+	SKS_ID(SKS_CKFM_SIGN_RECOVER),
+	SKS_ID(SKS_CKFM_VERIFY),
+	SKS_ID(SKS_CKFM_VERIFY_RECOVER),
+	SKS_ID(SKS_CKFM_GENERATE),
+	SKS_ID(SKS_CKFM_GENERATE_PAIR),
+	SKS_ID(SKS_CKFM_WRAP),
+	SKS_ID(SKS_CKFM_UNWRAP),
+	SKS_ID(SKS_CKFM_DERIVE),
+	SKS_ID(SKS_CKFM_EC_F_P),
+	SKS_ID(SKS_CKFM_EC_F_2M),
+	SKS_ID(SKS_CKFM_EC_ECPARAMETERS),
+	SKS_ID(SKS_CKFM_EC_NAMEDCURVE),
+	SKS_ID(SKS_CKFM_EC_UNCOMPRESS),
+	SKS_ID(SKS_CKFM_EC_COMPRESS),
+};
+
+static const struct string_id __maybe_unused string_functions[] = {
+	SKS_ID(SKS_FUNCTION_ENCRYPT),
+	SKS_ID(SKS_FUNCTION_DECRYPT),
+	SKS_ID(SKS_FUNCTION_SIGN),
+	SKS_ID(SKS_FUNCTION_VERIFY),
+	SKS_ID(SKS_FUNCTION_DERIVE),
+};
+
+/*
+ * Helper functions to analyse SKS identifiers
+ */
+
+size_t sks_attr_is_class(uint32_t attribute_id)
+{
+	if (attribute_id == SKS_CKA_CLASS)
+		return sizeof(uint32_t);
+	else
+		return 0;
+}
+
+size_t sks_attr_is_type(uint32_t attribute_id)
+{
+	switch (attribute_id) {
+	case SKS_CKA_CERTIFICATE_TYPE:
+	case SKS_CKA_KEY_TYPE:
+	case SKS_CKA_MECHANISM_TYPE:
+	case SKS_CKA_KEY_GEN_MECHANISM:
+		return sizeof(uint32_t);
+	default:
+		return 0;
+	}
+}
+
+bool sks_class_has_type(uint32_t class)
+{
+	switch (class) {
+	case SKS_CKO_CERTIFICATE:
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+	case SKS_CKO_SECRET_KEY:
+	case SKS_CKO_MECHANISM:
+	case SKS_CKO_HW_FEATURE:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+bool sks_attr_class_is_key(uint32_t class)
+{
+	switch (class) {
+	case SKS_CKO_SECRET_KEY:
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/* Returns shift position or -1 on error */
+int sks_attr2boolprop_shift(uint32_t attr)
+{
+	COMPILE_TIME_ASSERT(SKS_BOOLPROPS_BASE == 0);
+
+	if (attr > SKS_BOOLPROPS_LAST)
+		return -1;
+
+	return attr;
+}
+
+/*
+ * Conversion between SKS and GPD TEE return codes
+ */
+
+TEE_Result sks2tee_error(uint32_t rv)
+{
+	switch (rv) {
+	case SKS_CKR_OK:
+		return TEE_SUCCESS;
+
+	case SKS_CKR_ARGUMENTS_BAD:
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	case SKS_CKR_DEVICE_MEMORY:
+		return TEE_ERROR_OUT_OF_MEMORY;
+
+	case SKS_CKR_BUFFER_TOO_SMALL:
+		return TEE_ERROR_SHORT_BUFFER;
+
+	default:
+		return TEE_ERROR_GENERIC;
+	}
+}
+
+TEE_Result sks2tee_noerr(uint32_t rc)
+{
+	switch (rc) {
+	case SKS_CKR_ARGUMENTS_BAD:
+		return TEE_ERROR_BAD_PARAMETERS;
+
+	case SKS_CKR_DEVICE_MEMORY:
+		return TEE_ERROR_OUT_OF_MEMORY;
+
+	case SKS_CKR_BUFFER_TOO_SMALL:
+		return TEE_ERROR_SHORT_BUFFER;
+
+	case SKS_CKR_GENERAL_ERROR:
+		return TEE_ERROR_GENERIC;
+
+	default:
+		return TEE_SUCCESS;
+	}
+}
+
+uint32_t tee2sks_error(TEE_Result res)
+{
+	switch (res) {
+	case TEE_SUCCESS:
+		return SKS_CKR_OK;
+
+	case TEE_ERROR_BAD_PARAMETERS:
+		return SKS_CKR_ARGUMENTS_BAD;
+
+	case TEE_ERROR_OUT_OF_MEMORY:
+		return SKS_CKR_DEVICE_MEMORY;
+
+	case TEE_ERROR_SHORT_BUFFER:
+		return SKS_CKR_BUFFER_TOO_SMALL;
+
+	case TEE_ERROR_MAC_INVALID:
+		return SKS_CKR_SIGNATURE_INVALID;
+
+	case TEE_ERROR_SIGNATURE_INVALID:
+		return SKS_CKR_SIGNATURE_INVALID;
+
+	default:
+		return SKS_CKR_GENERAL_ERROR;
+	}
+}
+
+bool valid_sks_attribute_id(uint32_t id, uint32_t size)
+{
+	size_t n = 0;
+
+	for (n = 0; n < ARRAY_SIZE(attr_ids); n++) {
+		if (id != attr_ids[n].id)
+			continue;
+
+		/* Check size matches if provided */
+		return !attr_ids[n].size || size == attr_ids[n].size;
+	}
+
+	return false;
+}
+
+bool key_type_is_symm_key(uint32_t id)
+{
+	switch (id) {
+	case SKS_CKK_AES:
+	case SKS_CKK_GENERIC_SECRET:
+	case SKS_CKK_MD5_HMAC:
+	case SKS_CKK_SHA_1_HMAC:
+	case SKS_CKK_SHA224_HMAC:
+	case SKS_CKK_SHA256_HMAC:
+	case SKS_CKK_SHA384_HMAC:
+	case SKS_CKK_SHA512_HMAC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+bool key_type_is_asymm_key(uint32_t id)
+{
+	switch (id) {
+	case SKS_CKK_EC:
+	case SKS_CKK_RSA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+bool certificate_is_valid(uint32_t id)
+{
+	switch (id) {
+	case SKS_CKC_X_509:
+	case SKS_CKC_X_509_ATTR_CER:
+	case SKS_CKC_WTLS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+bool mechanism_is_valid(uint32_t id)
+{
+	size_t n = 0;
+
+	for (n = 0; n < ARRAY_SIZE(processing_ids); n++)
+		if (id == processing_ids[n].id)
+			return true;
+
+	return false;
+}
+
+bool mechanism_is_supported(uint32_t id)
+{
+	size_t n = 0;
+
+	for (n = 0; n < ARRAY_SIZE(processing_ids); n++) {
+		if (processing_ids[n].id == id)
+			return processing_ids[n].supported;
+	}
+
+	return false;
+}
+
+size_t get_supported_mechanisms(uint32_t *array, size_t array_count)
+{
+	size_t n = 0;
+	size_t m = 0;
+	size_t count = 0;
+
+	for (n = 0; n < ARRAY_SIZE(processing_ids); n++) {
+		if (processing_ids[n].supported)
+			count++;
+	}
+
+	if (array_count == 0)
+		return count;
+
+	if (array_count < count) {
+		EMSG("Expect well sized array");
+		return 0;
+	}
+
+	if (!array) {
+		EMSG("array is NULL");
+		TEE_Panic(0);
+	}
+
+	for (n = 0, m = 0; n < ARRAY_SIZE(processing_ids); n++) {
+		if (processing_ids[n].supported) {
+			array[m] = processing_ids[n].id;
+			m++;
+		}
+	}
+
+	assert(m == count);
+
+	return m;
+}
+
+/* Initialize a TEE attribute for a target SKS attribute in an object */
+bool sks2tee_load_attr(TEE_Attribute *tee_ref, uint32_t tee_id,
+			struct sks_object *obj, uint32_t sks_id)
+{
+	void *a_ptr = NULL;
+	uint32_t a_size = 0;
+	uint32_t data32 = 0;
+
+	switch (tee_id) {
+	case TEE_ATTR_ECC_PUBLIC_VALUE_X:
+	case TEE_ATTR_ECC_PUBLIC_VALUE_Y:
+	case TEE_ATTR_ECC_CURVE:
+		if (get_attribute_ptr(obj->attributes, SKS_CKA_EC_PARAMS,
+					&a_ptr, &a_size)) {
+			EMSG("Missing EC_PARAMS attribute");
+			return false;
+		}
+
+		if (tee_id == TEE_ATTR_ECC_CURVE) {
+			data32 = ec_params2tee_curve(a_ptr, a_size);
+			TEE_InitValueAttribute(tee_ref, TEE_ATTR_ECC_CURVE,
+					data32, 0);
+			return true;
+		}
+
+		data32 = (ec_params2tee_keysize(a_ptr, a_size) + 7) / 8;
+
+		if (get_attribute_ptr(obj->attributes, SKS_CKA_EC_POINT,
+					&a_ptr, &a_size)) {
+			/*
+			 * Public X/Y is required for both TEE keypair and
+			 * public key, so abort if EC_POINT is not provided
+			 * during object import.
+			 */
+			EMSG("Missing EC_POINT attribute");
+			return false;
+		}
+
+		/* TODO: Support DER long definitive form */
+		if (a_size >= 0x80) {
+			EMSG("DER long definitive form not yet supported");
+			return false;
+		}
+		if (((char *)a_ptr)[2] != 0x04) {
+			EMSG("Unsupported EC_POINT form");
+			return false;
+		}
+		if (a_size != 2 + 2 * data32 + 1) {
+			EMSG("Invalid EC_POINT attribute");
+			return false;
+		}
+
+		if (tee_id == TEE_ATTR_ECC_PUBLIC_VALUE_X)
+			TEE_InitRefAttribute(tee_ref, tee_id,
+					(uint8_t *)a_ptr + 3, data32);
+		else
+			TEE_InitRefAttribute(tee_ref, tee_id,
+					(uint8_t *)a_ptr + 3 + data32, data32);
+
+		return true;
+
+	default:
+		break;
+	}
+
+	if (get_attribute_ptr(obj->attributes, sks_id, &a_ptr, &a_size))
+		return false;
+
+	TEE_InitRefAttribute(tee_ref, tee_id, a_ptr, a_size);
+
+	return true;
+}
+
+/* Easy conversion between SKS function of TEE crypto mode */
+void sks2tee_mode(uint32_t *tee_id, uint32_t function)
+{
+	switch (function) {
+	case SKS_FUNCTION_ENCRYPT:
+		*tee_id = TEE_MODE_ENCRYPT;
+		break;
+	case SKS_FUNCTION_DECRYPT:
+		*tee_id = TEE_MODE_DECRYPT;
+		break;
+	case SKS_FUNCTION_SIGN:
+		*tee_id = TEE_MODE_SIGN;
+		break;
+	case SKS_FUNCTION_VERIFY:
+		*tee_id = TEE_MODE_VERIFY;
+		break;
+	case SKS_FUNCTION_DERIVE:
+		*tee_id = TEE_MODE_DERIVE;
+		break;
+	default:
+		TEE_Panic(function);
+	}
+}
+
+#if CFG_TEE_TA_LOG_LEVEL > 0
+/*
+ * Convert a SKS ID into its label string
+ */
+const char *sks2str_attr(uint32_t id)
+{
+	size_t n = 0;
+
+	for (n = 0; n < ARRAY_SIZE(attr_ids); n++) {
+		if (id != attr_ids[n].id)
+			continue;
+
+		/* Skip SKS_ prefix */
+		return (char *)attr_ids[n].string + strlen("SKS_CKA_");
+	}
+
+	return unknown;
+}
+
+static const char *sks2str_mechanism_type(uint32_t id)
+{
+	size_t n = 0;
+
+	for (n = 0; n < ARRAY_SIZE(processing_ids); n++) {
+		if (id != processing_ids[n].id)
+			continue;
+
+		/* Skip SKS_ prefix */
+		return (char *)processing_ids[n].string + strlen("SKS_CKM_");
+	}
+
+	return unknown;
+}
+
+static const char *id2str(uint32_t id, const struct string_id *table,
+			  size_t count, const char *prefix)
+{
+	size_t n = 0;
+	const char *str = NULL;
+
+	for (n = 0; n < count; n++) {
+		if (id != table[n].id)
+			continue;
+
+		str = table[n].string;
+
+		/* Skip prefix provided matches found */
+		if (prefix && !TEE_MemCompare(str, prefix, strlen(prefix)))
+			str += strlen(prefix);
+
+		return str;
+	}
+
+	return unknown;
+}
+
+#define ID2STR(id, table, prefix)	\
+	id2str(id, table, ARRAY_SIZE(table), prefix)
+
+const char *sks2str_class(uint32_t id)
+{
+	return ID2STR(id, string_class, "SKS_CKO_");
+}
+
+const char *sks2str_type(uint32_t id, uint32_t class)
+{
+	switch (class) {
+	case SKS_CKO_SECRET_KEY:
+	case SKS_CKO_PUBLIC_KEY:
+	case SKS_CKO_PRIVATE_KEY:
+		return sks2str_key_type(id);
+	default:
+		return unknown;
+	}
+}
+const char *sks2str_key_type(uint32_t id)
+{
+	return ID2STR(id, string_key_type, "SKS_CKK_");
+}
+
+const char *sks2str_certificate_type(uint32_t id)
+{
+	return ID2STR(id, string_certificate_type, "SKS_CKC_");
+}
+
+const char *sks2str_boolprop(uint32_t id)
+{
+	if (id < 64)
+		return sks2str_attr(id);
+
+	return unknown;
+}
+
+const char *sks2str_proc(uint32_t id)
+{
+	const char *str = ID2STR(id, string_internal_processing,
+				 "SKS_PROCESSING_");
+
+	if (str != unknown)
+		return str;
+
+	return sks2str_mechanism_type(id);
+}
+
+const char *sks2str_proc_flag(uint32_t id)
+{
+	return ID2STR(id, string_proc_flags, "SKS_CKFM_");
+}
+
+const char *sks2str_rc(uint32_t id)
+{
+	return ID2STR(id, string_rc, "SKS_CKR_");
+}
+
+const char *sks2str_skscmd(uint32_t id)
+{
+	return ID2STR(id, string_cmd, NULL);
+}
+
+const char *sks2str_slot_flag(uint32_t id)
+{
+	return ID2STR(id, string_slot_flags, "SKS_CKFS_");
+}
+
+const char *sks2str_token_flag(uint32_t id)
+{
+	return ID2STR(id, string_token_flags, "SKS_CKFT_");
+}
+
+const char *sks2str_attr_value(uint32_t id, size_t size, void *value)
+{
+	static const char str_true[] = "TRUE";
+	static const char str_false[] = "FALSE";
+	static const char str_unkwon[] = "*";
+	uint32_t type = 0;
+
+	if (sks_attr2boolprop_shift(id) >= 0)
+		return !!*(uint8_t *)value ? str_true : str_false;
+
+	if (size < sizeof(uint32_t))
+		return str_unkwon;
+
+	TEE_MemMove(&type, value, sizeof(uint32_t));
+
+	if (sks_attr_is_class(id))
+		return sks2str_class(type);
+
+	if (id == SKS_CKA_KEY_TYPE)
+		return sks2str_key_type(type);
+
+	if (id == SKS_CKA_MECHANISM_TYPE)
+		return sks2str_mechanism_type(type);
+
+	return str_unkwon;
+}
+
+const char *sks2str_function(uint32_t id)
+{
+	return ID2STR(id, string_functions, "SKS_FUNCTION_");
+}
+#endif /*CFG_TEE_TA_LOG_LEVEL*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sks_helpers.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sks_helpers.h
new file mode 100644
index 0000000..c394a7a
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sks_helpers.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#ifndef __SKS_HELPERS_H
+#define __SKS_HELPERS_H
+
+#include <sks_ta.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <tee_internal_api.h>
+
+/* Short aliases for return code */
+#define SKS_OK				SKS_CKR_OK
+#define SKS_ERROR			SKS_CKR_GENERAL_ERROR
+#define SKS_MEMORY			SKS_CKR_DEVICE_MEMORY
+#define SKS_BAD_PARAM			SKS_CKR_ARGUMENTS_BAD
+#define SKS_SHORT_BUFFER		SKS_CKR_BUFFER_TOO_SMALL
+#define SKS_FAILED			SKS_CKR_FUNCTION_FAILED
+
+struct sks_object;
+
+/*
+ * Helper functions to analyse CK fields
+ */
+bool valid_sks_attribute_id(uint32_t id, uint32_t size);
+
+size_t sks_attr_is_class(uint32_t attribute_id);
+size_t sks_attr_is_type(uint32_t attribute_id);
+bool sks_class_has_boolprop(uint32_t class);
+bool sks_class_has_type(uint32_t class);
+bool sks_attr_class_is_key(uint32_t class);
+int sks_attr2boolprop_shift(uint32_t attr);
+
+bool key_type_is_symm_key(uint32_t id);
+bool key_type_is_asymm_key(uint32_t id);
+bool certificate_is_valid(uint32_t id);
+bool mechanism_is_valid(uint32_t id);
+size_t get_supported_mechanisms(uint32_t *array, size_t array_count);
+bool mechanism_is_supported(uint32_t id);
+
+void sks2tee_mode(uint32_t *tee_id, uint32_t function);
+bool sks2tee_load_attr(TEE_Attribute *tee_ref, uint32_t tee_id,
+			struct sks_object *obj, uint32_t sks_id);
+
+/*
+ * Convert SKS return code into a GPD TEE result ID when matching.
+ * If not, return a TEE success (_noerr) or generic error (_error).
+ */
+TEE_Result sks2tee_noerr(uint32_t rv);
+TEE_Result sks2tee_error(uint32_t rv);
+uint32_t tee2sks_error(TEE_Result res);
+
+/* Id-to-string conversions when CFG_TEE_TA_LOG_LEVEL > 0 */
+const char *sks2str_attr(uint32_t id);
+const char *sks2str_class(uint32_t id);
+const char *sks2str_type(uint32_t id, uint32_t class);
+const char *sks2str_key_type(uint32_t id);
+const char *sks2str_certificate_type(uint32_t id);
+const char *sks2str_boolprop(uint32_t id);
+const char *sks2str_proc(uint32_t id);
+const char *sks2str_proc_flag(uint32_t id);
+const char *sks2str_slot_flag(uint32_t id);
+const char *sks2str_token_flag(uint32_t id);
+const char *sks2str_rc(uint32_t id);
+const char *sks2str_skscmd(uint32_t id);
+const char *sks2str_attr_value(uint32_t id, size_t size, void *value);
+const char *sks2str_function(uint32_t id);
+
+#endif /*__CK_HELPERS_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sks_hsm_debug.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sks_hsm_debug.h
new file mode 100644
index 0000000..5c5d0df
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sks_hsm_debug.h
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#ifndef __SKS_HSM_DEBUG_H__
+#define __SKS_HSM_DEBUG_H__
+
+/****************************************
+ * # 0: none
+ * # 1: error
+ * # 2: error + warning
+ * # 3: error + warning + debug
+ * # 4: error + warning + debug + flow
+ ****************************************/
+#define SKS_HSM_LOG_LEVEL             3
+
+#define SKS_HSM_ERROR_LOG_LEVEL       1
+#define SKS_HSM_INFO_LOG_LEVEL        2
+#define SKS_HSM_DEBUG_LOG_LEVEL       3
+#define SKS_HSM_FLOW_LOG_LEVEL        4
+
+#if (SKS_HSM_FLOW_LOG_LEVEL <= SKS_HSM_LOG_LEVEL)
+#define SKS_HSM_FLOW(x...) FMSG(x)
+#else
+#define SKS_HSM_FLOW(x...)
+#endif
+
+#if (SKS_HSM_DEBUG_LOG_LEVEL <= SKS_HSM_LOG_LEVEL)
+#define SKS_HSM_DEBUG(x...) DMSG(x)
+#else
+#define SKS_HSM_DEBUG(x...)
+#endif
+
+#if (SKS_HSM_INFO_LOG_LEVEL <= SKS_HSM_LOG_LEVEL)
+#define SKS_HSM_INFO(x...) IMSG(x)
+#else
+#define SKS_HSM_INFO(x...)
+#endif
+
+#if (SKS_HSM_ERROR_LOG_LEVEL <= SKS_HSM_LOG_LEVEL)
+#define SKS_HSM_ERROR(x...) EMSG(x)
+#else
+#define SKS_HSM_ERROR(x...)
+#endif
+
+
+#endif /*__SKS_HSM_DEBUG_H__*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sub.mk
new file mode 100644
index 0000000..f5a3d15
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/sub.mk
@@ -0,0 +1,18 @@
+srcs-y += entry.c
+srcs-y += sks_helpers.c
+srcs-y += handle.c
+srcs-y += pkcs11_token.c
+srcs-y += persistent_token.c
+srcs-y += serializer.c
+srcs-y += sanitize_object.c
+srcs-y += object.c
+srcs-y += processing.c
+srcs-y += processing_aes.c
+srcs-y += pkcs11_attributes.c
+srcs-y += attributes.c
+srcs-y += processing_symm.c
+srcs-y += processing_ec.c
+srcs-y += processing_rsa.c
+srcs-y += processing_asymm.c
+srcs-y += processing_mtk_hsm.c
+srcs-y += processing_mtk_key.c
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/user_ta_header_defines.h b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/user_ta_header_defines.h
new file mode 100644
index 0000000..1d33a3e
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/src/user_ta_header_defines.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2017-2018, Linaro Limited
+ */
+
+#ifndef USER_TA_HEADER_DEFINES_H
+#define USER_TA_HEADER_DEFINES_H
+
+#include <sks_ta.h>
+
+#define TA_UUID				TA_SKS_UUID
+
+#define TA_FLAGS			(TA_FLAG_SINGLE_INSTANCE | \
+						TA_FLAG_MULTI_SESSION | \
+						TA_FLAG_EXEC_DDR | \
+						TA_FLAG_INSTANCE_KEEP_ALIVE)
+
+#define TA_STACK_SIZE			(2 * 1024)
+#define TA_DATA_SIZE			(16 * 1024)
+
+#define TA_CURRENT_TA_EXT_PROPERTIES \
+    { "gp.ta.description", USER_TA_PROP_TYPE_STRING, \
+        "Secure key services trusted application" }, \
+    { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0000 } }
+
+#endif /*USER_TA_HEADER_DEFINES_H*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/sub.mk
new file mode 100644
index 0000000..b927f9b
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/sub.mk
@@ -0,0 +1,6 @@
+global-incdirs-y += include
+global-incdirs-y += src
+subdirs-y += src
+
+CFG_SKS_TA_TOKEN_COUNT ?= 3
+CPPFLAGS += -DCFG_SKS_TA_TOKEN_COUNT=$(CFG_SKS_TA_TOKEN_COUNT)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/ta.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/ta.mk
new file mode 100644
index 0000000..19c6061
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/ta.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH := $(call my-dir)
+local_module := fd02c9da-306c-48c7-a49c-bbd827ae86ee.ta
+include $(BUILD_OPTEE_MK)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/user_ta.mk b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/user_ta.mk
new file mode 100644
index 0000000..f3ada68
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/optee_services/secure_key_services/ta/user_ta.mk
@@ -0,0 +1 @@
+user-ta-uuid := fd02c9da-306c-48c7-a49c-bbd827ae86ee
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/gpt.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/gpt.c
new file mode 100644
index 0000000..aba6236
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/gpt.c
@@ -0,0 +1,196 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2019. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+#include <kernel/pseudo_ta.h>
+#include <kernel/thread.h>
+#include <kernel/interrupt.h>
+#include <kernel/misc.h>
+#include <mm/core_memprot.h>
+#include <kernel/tee_time.h>
+#include <io.h>
+#include "gpt.h"
+// #include <initcall.h>
+
+register_phys_mem(MEM_AREA_IO_NSEC, GPT_BASE, GPT_SIZE);
+vaddr_t gpt_base;
+extern bool itr_set_polarity(unsigned int irq, unsigned int polarity);
+
+void dump_gpt(void){
+	DMSG("-------------gpt dump start---------------------");
+	DMSG("GPT_IRQEN:%x at %p", read32(gpt_base+GPT_IRQEN),gpt_base+GPT_IRQEN);
+	DMSG("GPT_IRQSTA:%x at %p", read32(gpt_base+GPT_IRQSTA),gpt_base+GPT_IRQSTA);
+	DMSG("GPT_IRQACK:%x at %p", read32(gpt_base+GPT_IRQACK),gpt_base+GPT_IRQACK);
+	int i=0;
+	for (i=0;i<6;i++){
+		DMSG("GPT(%d) GPT_CON:%x at %p", i, read32(gpt_base+GPT_CON(i)), gpt_base+GPT_CON(i));
+		DMSG("GPT(%d) GPT_CLK:%x at %p", i, read32(gpt_base+GPT_CLK(i)), gpt_base+GPT_CLK(i));
+		DMSG("GPT(%d) GPT_COUNT:%x at %p", i, read32(gpt_base+GPT_COUNT(i)), gpt_base+GPT_COUNT(i));
+		DMSG("GPT(%d) GPT_COMPARE:%x at %p", i, read32(gpt_base+GPT_COMPARE(i)), gpt_base+GPT_COMPARE(i));
+	}
+	DMSG("-------------gpt dump end---------------------");
+}
+void gpt_irqen(uint8_t gpt_num)
+{
+	uint32_t value = read32(gpt_base+GPT_IRQEN);
+	value |= (1<<(gpt_num));
+	write32(value, gpt_base+GPT_IRQEN);
+	DMSG("write %x to %p", value, gpt_base+GPT_IRQEN);
+}
+
+void gpt_irqdisableall(void)
+{
+	write32(0, gpt_base+GPT_IRQEN);
+	DMSG("write %x to %p", 0, gpt_base+GPT_IRQEN);
+}
+
+void gpt_irqackall(void)
+{
+	write32(0x3F, gpt_base+GPT_IRQACK);
+	DMSG("write %x to %p", 0x3F, gpt_base+GPT_IRQEN);
+}
+
+void gpt_reset(uint8_t gpt_num)
+{
+	write32(0x2, gpt_base+GPT_CON(gpt_num));
+	write32(0, gpt_base+GPT_CLK(gpt_num));
+	write32(0, gpt_base+GPT_COMPARE(gpt_num));
+}
+
+uint8_t gpt_irqsta_all()
+{
+	return read32(gpt_base+GPT_IRQSTA);
+}
+
+uint8_t gpt_irqsta(uint8_t gpt_num)
+{
+	return (read32(gpt_base+GPT_IRQSTA) & (1<<gpt_num));
+}
+
+void gpt_ackirq(uint8_t gpt_num)
+{
+	write32((0x1<<gpt_num), gpt_base+GPT_IRQACK);
+}
+
+void gpt_enable(uint8_t gpt_num, uint8_t mode)
+{
+    //clear
+	write32(0x2, gpt_base+GPT_CON(gpt_num));
+	uint32_t value = (mode & 0x30) | 0x1;
+	DMSG("write %x to %p", value, gpt_base+GPT_CON(gpt_num));
+	write32(value, gpt_base+GPT_CON(gpt_num));
+}
+
+void gpt_set_compare(uint8_t gpt_num, uint32_t value)
+{
+	DMSG("write %x to %p", value, gpt_base+GPT_COMPARE(gpt_num));
+	write32(value, gpt_base+GPT_COMPARE(gpt_num));
+}
+
+static enum itr_return gpt_itr_cb(struct itr_handler *h)
+{
+    uint8_t data = *((uint8_t*)(h->data));
+	EMSG("cpu %zu: got gpt interrupt for gpt :%d.", get_core_pos(), data);
+	//dump_gpt();
+	gpt_ackirq(data);
+	//dump_gpt();
+    return ITRR_HANDLED;
+}
+
+uint8_t gpt_itr_data = 0;
+static struct itr_handler gpt_itr = {
+        .it = IT_GPT_NUMBER,
+        .flags = ITRF_TRIGGER_LEVEL,
+        .handler = gpt_itr_cb,
+		.data = &gpt_itr_data,
+};
+KEEP_PAGER(gpt_itr);
+
+static TEE_Result init_gpt_itr(uint8_t gpt_num)
+{
+    *((uint8_t*)(gpt_itr.data)) = gpt_num;
+	itr_add(&gpt_itr);
+	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!Attention!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+	// This is for mtk mt2712 platform specificlly.
+	// If the irq is low level trigger, need to invert the trigger polarity.
+	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!Attention!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+	itr_set_polarity(IT_GPT_NUMBER, (gpt_itr.flags & ITRF_TRIGGER_LEVEL)==ITRF_TRIGGER_LEVEL);
+    itr_enable(IT_GPT_NUMBER);
+    return TEE_SUCCESS;
+}
+
+void gpt_init(uint8_t gpt_num, uint32_t time)
+{
+	gpt_base = (vaddr_t)phys_to_virt_io(GPT_BASE);
+	IMSG("gpt_base: %p\n", gpt_base);
+	//dump_gpt();
+	// Clear the status of gpt as they may used in NWD.
+	gpt_irqdisableall();
+	gpt_irqackall();
+	gpt_reset(0);
+	gpt_reset(1);
+	gpt_set_compare(gpt_num, time*13000000);
+	init_gpt_itr(gpt_num);
+	gpt_irqen(gpt_num);
+	gpt_enable(gpt_num, 0/*mode*/);
+	//dump_gpt();
+}
+
+static TEE_Result invoke_command(void *pSessionContext __unused,
+				 uint32_t nCommandID, uint32_t nParamTypes,
+				 TEE_Param pParams[TEE_NUM_PARAMS])
+{
+	IMSG("GPT nCommandID(%x)\n", nCommandID);
+	switch (nCommandID) {
+	case PTA_CMD_GPT_INIT:
+		if (TEE_PARAM_TYPE_GET(nParamTypes, 0) !=
+			TEE_PARAM_TYPE_VALUE_INPUT)
+			return TEE_ERROR_BAD_PARAMETERS;
+		uint32_t gpt_num = pParams[0].value.a;
+		uint32_t time_value = pParams[0].value.b;
+		IMSG("input value gpt num:%d, time:%d s\n", gpt_num, time_value);
+		gpt_init(gpt_num, time_value);
+		return TEE_SUCCESS;
+
+	default:
+		break;
+	}
+
+	return TEE_ERROR_NOT_IMPLEMENTED;
+}
+
+pseudo_ta_register(.uuid = PTA_GPT_TEST_PTA_UUID, .name = "gpt",
+		   .flags = PTA_DEFAULT_FLAGS,
+		   .invoke_command_entry_point = invoke_command);
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/gpt.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/gpt.h
new file mode 100644
index 0000000..a5f7668
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/gpt.h
@@ -0,0 +1,60 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2019. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+#ifndef __GPT_H__
+#define __GPT_H__
+
+#include <sm/optee_smc.h>
+
+#define PTA_GPT_TEST_PTA_UUID { 0x472567ad, 0xa180, 0x402c, \
+			{ 0x50, 0x95, 0x7b, 0x4e, 0xd3, 0xe0, 0x5e, 0x83 } }
+
+#define GPT_BASE          0x10008000
+#define GPT_SIZE          0xA0
+#define GPT_IRQEN         (0x0)
+#define GPT_IRQSTA        (0x4)
+#define GPT_IRQACK        (0x8)
+   
+#define GPT_N(n)          ((n+1)<<4)
+#define GPT_CON(n)        (GPT_N(n)+(0x0))
+#define GPT_CLK(n)        (GPT_N(n)+(0x4))
+#define GPT_COUNT(n)      (GPT_N(n)+(0x8))
+#define GPT_COMPARE(n)    (GPT_N(n)+(0xC))
+
+
+#define IT_GPT_NUMBER     184
+
+#define PTA_CMD_GPT_INIT   0
+#endif  /* __GPT_H__ */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/pta.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/pta.mk
new file mode 100644
index 0000000..e82d4fa
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/pta.mk
@@ -0,0 +1,5 @@
+libdir := $(call my-dir)
+libname := gpt
+
+include $(BUILD_OPTEE_OS_LIB)
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/sub.mk
new file mode 100644
index 0000000..6bdb8bd
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/gpt/sub.mk
@@ -0,0 +1,4 @@
+srcs-y := \
+          gpt.c \
+
+$(call add-pta-src, gpt.c)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/address.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/address.h
new file mode 100644
index 0000000..e72b758
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/address.h
@@ -0,0 +1,47 @@
+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+#ifndef _ADDRESS_H_

+#define _ADDRESS_H_

+

+typedef struct addr_t

+{

+	void *pa; // physical address in AP view

+	void *va; // virtual address

+	void *ha; // physical address in HSM view

+} addr_t;

+

+#endif /* end of include guard: _ADDRESS_H_ */

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/buddy.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/buddy.c
new file mode 100644
index 0000000..1206eae
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/buddy.c
@@ -0,0 +1,354 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <mm/core_memprot.h>
+#include <tee/cache.h>
+#include "buddy.h"
+#include "buddy_config.h"
+#include "share_memmap.h"
+
+#if BUDDY_MEMPOOL_SIZE > BUDDY_MEMPOOL_BUF_LEN
+#error "[buddy system] not enough memory..."
+#endif
+
+#define max(a, b) (((a)>(b))?(a):(b))
+#define min(a, b) (((a)<(b))?(a):(b))
+
+typedef uint16_t node_len_t ;
+
+struct buddy {
+	uint32_t size;
+	node_len_t longest[];
+};
+
+static struct buddy *__instance = NULL;
+// static uint8_t buddy_table[sizeof(struct buddy) + 2 * BUDDY_TOTAL_BLOCKS * sizeof(node_len_t)];
+static uint8_t *memory_pool = NULL;
+static vaddr_t v_memory_pool;
+
+static inline int left_child(int index)
+{
+	/* index * 2 + 1 */
+	return ((index << 1) + 1);
+}
+
+static inline int right_child(int index)
+{
+	/* index * 2 + 2 */
+	return ((index << 1) + 2);
+}
+
+static inline int parent(int index)
+{
+	/* (index+1)/2 - 1 */
+	return (((index + 1) >> 1) - 1);
+}
+
+static inline bool is_power_of_2(int index)
+{
+	return !(index & (index - 1));
+}
+
+static inline unsigned next_power_of_2(unsigned size)
+{
+	/* depend on the fact that size < 2^32 */
+	size -= 1;
+	size |= (size >> 1);
+	size |= (size >> 2);
+	size |= (size >> 4);
+	size |= (size >> 8);
+	size |= (size >> 16);
+	return size + 1;
+}
+
+static inline uint8_t *get_va_in_mempool(int idx)
+{
+	return (v_memory_pool + (idx << BUDDY_BLOCK_SIZE_ORDER));
+}
+
+static inline uint8_t *get_pa_in_mempool(int idx)
+{
+	return (memory_pool + (idx << BUDDY_BLOCK_SIZE_ORDER));
+}
+
+static inline int map_pa_2_idx_in_mempool(uint8_t * ptr)
+{
+	return (((int)ptr - (int)memory_pool) >> BUDDY_BLOCK_SIZE_ORDER);
+}
+
+void buddy_init(void)
+{
+	if (__instance != NULL) {
+		return;
+	}
+
+	struct buddy *self = NULL;
+	node_len_t node_size;
+	unsigned num_of_fragments = BUDDY_TOTAL_BLOCKS;
+	int i;
+	int table_size = sizeof(struct buddy) + 2 * BUDDY_TOTAL_BLOCKS * sizeof(node_len_t);
+
+	/* alloacte an array to represent a complete binary tree */
+	self = (struct buddy *) malloc(table_size);
+	memset(self, 0, table_size);
+
+	self->size = num_of_fragments;
+	node_size = num_of_fragments * 2;
+
+	/* initialize *longest* array for buddy structure */
+	int iter_end = num_of_fragments * 2 - 1;
+	for (i = 0; i < iter_end; i++) {
+		if (is_power_of_2(i + 1)) {
+			node_size >>= 1;
+		}
+		self->longest[i] = node_size;
+	}
+
+	core_mmu_add_mapping(MEM_AREA_RAM_SEC, TEE_BUDDY_MEMPOOL_BUF_BASE, TEE_BUDDY_MEMPOOL_BUF_LEN);
+	v_memory_pool = (vaddr_t)phys_to_virt(TEE_BUDDY_MEMPOOL_BUF_BASE, MEM_AREA_RAM_SEC);
+
+	if (cache_operation(TEE_CACHEINVALIDATE, v_memory_pool, TEE_BUDDY_MEMPOOL_BUF_LEN) != TEE_SUCCESS) {
+		EMSG("[\x1b[31m%s\033[0m][%d] cache invalidate fail\n", __FUNCTION__, __LINE__);
+		return;
+	}
+
+	memory_pool = (uint8_t *)TEE_BUDDY_MEMPOOL_BUF_BASE;
+	__instance = (void*)self;
+
+
+}
+
+void buddy_deinit(void)
+{
+	memory_pool = NULL;
+	__instance = NULL;
+}
+
+/* choose the child with smaller longest value which is still larger
+ * than *size* */
+unsigned choose_better_child(struct buddy *self, unsigned index, size_t size)
+{
+	struct compound {
+		size_t size;
+		unsigned index;
+	} children[2];
+
+	children[0].index = left_child(index);
+	children[0].size = self->longest[children[0].index];
+	children[1].index = right_child(index);
+	children[1].size = self->longest[children[1].index];
+
+	int min_idx = (children[0].size <= children[1].size) ? 0 : 1;
+
+	if (size > children[min_idx].size) {
+		min_idx = 1 - min_idx;
+	}
+
+	return children[min_idx].index;
+}
+
+/** allocate *size* from a buddy system *self*
+ * @return the offset from the beginning of memory to be managed */
+int buddy_alloc_blk(size_t size)
+{
+	struct buddy *self = __instance;
+
+	if (self == NULL || self->size < size || size <= 0) {
+		return -1;
+	}
+
+	size = next_power_of_2(size);
+
+	unsigned index = 0;
+	if (self->longest[index] < size) {
+		return -1;
+	}
+
+	/* search recursively for the child */
+	unsigned node_size = 0;
+	for (node_size = self->size; node_size != size; node_size >>= 1) {
+		/* choose the child with smaller longest value which is still larger
+		 * than *size* */
+		/* TODO */
+		index = choose_better_child(self, index, size);
+	}
+
+	/* update the *longest* value back */
+	self->longest[index] = 0;
+	int offset = (index + 1) * node_size - self->size;
+
+	while (index) {
+		index = parent(index);
+		self->longest[index] =
+		    max(self->longest[left_child(index)],
+		        self->longest[right_child(index)]);
+	}
+
+	return offset;
+}
+
+void buddy_free_blk(int offset)
+{
+	struct buddy *self = __instance;
+
+	if (self == NULL || offset < 0 || offset > self->size) {
+		return;
+	}
+
+	node_len_t node_size;
+	unsigned index;
+
+	/* get the corresponding index from offset */
+	node_size = 1;
+	index = offset + self->size - 1;
+
+	for (; self->longest[index] != 0; index = parent(index)) {
+		node_size <<= 1;    /* node_size *= 2; */
+
+		if (index == 0) {
+			break;
+		}
+	}
+
+	self->longest[index] = node_size;
+
+	while (index) {
+		index = parent(index);
+		node_size <<= 1;
+
+		node_len_t left_longest = self->longest[left_child(index)];
+		node_len_t right_longest = self->longest[right_child(index)];
+
+		if (left_longest + right_longest == node_size) {
+			self->longest[index] = node_size;
+		} else {
+			self->longest[index] = max(left_longest, right_longest);
+		}
+	}
+}
+
+void buddy_dump(void)
+{
+	struct buddy *self = __instance;
+
+	int len = self->size << 1;
+	int max_col = self->size << 1;
+	int level = 0;
+	int i, j;
+
+	char cs[] = {'/', '\\'};
+	int idx = 0;
+	char c;
+
+	for (i = 0, max_col = len, level = 0; i < len - 1; i++) {
+		if (is_power_of_2(i + 1)) {
+			max_col >>= 1;
+			level ++;
+			idx = 0;
+			// LOGE("\n%d(%3d): ", level, max_col);
+		}
+
+		// LOGE("%*d", max_col, self->longest[i]);
+	}
+
+	for (i = 0, max_col = len, level = 0; i < len - 1; i++) {
+		if (is_power_of_2(i + 1)) {
+			max_col >>= 1;
+			level ++;
+			idx = 0;
+			// LOGE("\n%d(%3d): ", level, max_col);
+		}
+
+		if (self->longest[i] > 0) {
+			c = '-';
+		} else {
+			c = cs[idx];
+			idx ^= 0x1;
+		}
+
+		for (j = 0; j < max_col; j++) {
+			// LOGE("%c", c);
+		}
+	}
+	// LOGE("\n");
+}
+
+int buddy_size(int offset)
+{
+	struct buddy *self = __instance;
+	unsigned node_size = 1;
+	unsigned index = offset + self->size - 1;
+
+	for (; self->longest[index]; index = parent(index)) {
+		node_size >>= 1;
+	}
+
+	return node_size;
+}
+
+int buddy_malloc(uint32_t size, addr_t *addr)
+{
+	int idx = -1;
+	int blks = 0;
+
+	blks = (size >> BUDDY_BLOCK_SIZE_ORDER) + 1;
+	idx = buddy_alloc_blk(blks);
+	if (idx < 0) {
+		// LOGE("[\x1b[34m%s\033[0m][%d] allocate fail\r\n", __FUNCTION__, __LINE__);
+		return BUDDY_FAIL;
+	}
+
+	addr->pa = get_pa_in_mempool(idx);
+	addr->va = get_va_in_mempool(idx);
+
+	return BUDDY_OK;
+}
+
+
+void buddy_free(addr_t *addr)
+{
+	int idx = -1;
+
+	idx = map_pa_2_idx_in_mempool(addr->pa);
+
+	buddy_free_blk(idx);
+}
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/buddy.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/buddy.h
new file mode 100644
index 0000000..cf8c49b
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/buddy.h
@@ -0,0 +1,50 @@
+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+#ifndef BUDDY_H

+#define BUDDY_H

+

+#include <stdint.h>

+#include "address.h"

+

+#define BUDDY_OK    (0)

+#define BUDDY_FAIL (-1)

+

+void buddy_init(void);

+int buddy_malloc(uint32_t size, addr_t *addr);

+void buddy_free(addr_t *addr);

+

+#endif /* end of include guard: BUDDY_H */

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/buddy_config.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/buddy_config.h
new file mode 100644
index 0000000..49f77f2
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/buddy_config.h
@@ -0,0 +1,44 @@
+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+#ifndef _BUDDY_CONFIG_H_

+

+#define BUDDY_TOTAL_BLOCKS (128)

+#define BUDDY_BLOCK_SIZE_ORDER (6)

+#define BUDDY_BLOCK_SIZE (1<<BUDDY_BLOCK_SIZE_ORDER) //64

+#define BUDDY_MEMPOOL_SIZE (BUDDY_BLOCK_SIZE*BUDDY_TOTAL_BLOCKS)

+

+#endif /* end of include guard: _BUDDY_CONFIG_H_ */
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_dump.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_dump.c
new file mode 100644
index 0000000..9c43efe
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_dump.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: BSD-2-Clause

+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * Copyright  (C) 2020  MediaTek Inc. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+

+#include <stdio.h>

+#include <string.h>

+#include <stdint.h>

+#include <stdlib.h>

+#include <stdbool.h>

+#include <assert.h>

+#include <io.h>

+#include <kernel/delay.h>

+#include <tee/cache.h>

+#include <optee_msg.h>

+#include <mm/core_memprot.h>

+#include "hsm_dump.h"

+#include "share_memmap.h"

+

+#define OPTEE_BUFFER_SHIFT (24) // specific for optee

+#define HSM_LOG_FMT_BUF_LEN 256UL

+

+#define HSM_LOG_BUF_LEN     (LOG_BUF_LEN - sizeof(struct hsm_log))  /* 16KB  - size of log buffer var*/

+#define HSM_LOG_BUF_BASE    (JOB_PHYSICAL_BUF_BASE - HSM_LOG_BUF_LEN)

+#define HSM_LOG_BUF_VAR_LEN     (sizeof(struct hsm_log))  /* size of log buffer var */

+#define HSM_LOG_BUF_VAR_BASE    (HSM_LOG_BUF_BASE - HSM_LOG_BUF_VAR_LEN)

+

+struct hsm_log {

+	uint64_t log_next_seq;

+	uint64_t log_next_idx;

+	uint64_t log_first_seq;

+	uint64_t log_first_idx;

+} __attribute__ ((packed));

+

+struct log_header {

+	uint32_t next_idx;

+	uint32_t text_len;

+	uint32_t log_len;

+	int32_t  loglevel;

+};

+

+uint8_t *gvBuffAddr = NULL;

+uint8_t *gvBuffVarAddr = NULL;

+

+static inline uint8_t *log_text(const struct log_header *msg)

+{

+	return (uint8_t *)msg + sizeof(struct log_header);

+}

+

+static void flush_to_console(uint8_t *msg, uint32_t len)

+{

+	uint32_t i = 0;

+	unsigned char str[256];

+	memset(str, 0, sizeof(str));

+	if (len > 255)

+	{

+		IMSG("ingore messge!!!");

+	}

+

+	for (i = 0; i < len; i++)

+	{

+		str[i] = *((char *)msg + i);

+		// IMSG("[%s][%d]\r\n", __FUNCTION__, __LINE__);

+	}

+	str[i] = '\0';

+	IMSG("%s", str);

+	mdelay(1);

+}

+

+static int clean_and_invalidate_log_buffer(void)

+{

+	if (gvBuffAddr == NULL || gvBuffVarAddr == NULL)

+	{

+		EMSG("== BUFFER NULL!! ==\n");

+		return -1;

+	}

+	if (cache_operation(TEE_CACHECLEAN, gvBuffAddr, HSM_LOG_BUF_LEN) != TEE_SUCCESS)

+	{

+		EMSG("== CACHE FAIL!! ==\n");

+		return -1;

+	}

+	if (cache_operation(TEE_CACHEINVALIDATE, gvBuffAddr, HSM_LOG_BUF_LEN) != TEE_SUCCESS)

+	{

+		EMSG("== CACHE INVALIDATE FAIL!! ==\n");

+		return -1;

+	}

+	if (cache_operation(TEE_CACHECLEAN, gvBuffVarAddr, HSM_LOG_BUF_VAR_LEN) != TEE_SUCCESS)

+	{

+		EMSG("== CACHE FAIL!! ==\n");

+		return -1;

+	}

+	if (cache_operation(TEE_CACHEINVALIDATE, gvBuffVarAddr, HSM_LOG_BUF_VAR_LEN) != TEE_SUCCESS)

+	{

+		EMSG("== CACHE INVALIDATE FAIL!! ==\n");

+		return -1;

+	}

+	return 0;

+}

+

+int hsm_dump_init(void)

+{

+	core_mmu_add_mapping(MEM_AREA_RAM_SEC, HSM_LOG_BUF_BASE, HSM_LOG_BUF_LEN);

+	gvBuffAddr = (vaddr_t)phys_to_virt(HSM_LOG_BUF_BASE, MEM_AREA_RAM_SEC);

+

+	if (gvBuffAddr == NULL)

+	{

+		EMSG("[%s][%d] memory map fail.\r\n", __FUNCTION__, __LINE__);

+		return -1;

+	}

+

+	core_mmu_add_mapping(MEM_AREA_RAM_SEC, HSM_LOG_BUF_VAR_BASE, HSM_LOG_BUF_VAR_LEN);

+	gvBuffVarAddr = (vaddr_t)phys_to_virt(HSM_LOG_BUF_VAR_BASE, MEM_AREA_RAM_SEC);

+

+	if (gvBuffVarAddr == NULL)

+	{

+		EMSG("[%s][%d] memory map fail.\r\n", __FUNCTION__, __LINE__);

+		return -1;

+	}

+

+	return 0;

+}

+

+

+int hsm_dump_log(void)

+{

+	struct hsm_log *Buff_log_Var_Addr;

+	uint32_t local_idx;

+	uint64_t local_first_seq;

+	struct log_header *msg;

+	volatile uint64_t *log_first_idx;

+	volatile uint64_t *log_first_seq;

+	volatile uint64_t *log_next_seq;

+

+	if(clean_and_invalidate_log_buffer() != 0)

+	{

+		EMSG("[%s][%d] clean & invalidate fail.\r\n", __FUNCTION__, __LINE__);

+		return -1;

+	}

+

+	msg = (struct log_header *)gvBuffAddr;

+	Buff_log_Var_Addr = (struct hsm_log *)gvBuffVarAddr;

+

+	log_first_idx = (uint32_t *) & (Buff_log_Var_Addr->log_first_idx);

+	log_first_seq = &(Buff_log_Var_Addr->log_first_seq);

+	log_next_seq = &(Buff_log_Var_Addr->log_next_seq);

+

+	local_idx = *log_first_idx;

+	local_first_seq = *log_first_seq;

+	while (local_first_seq < *log_next_seq) {

+		msg = (struct log_header *)(gvBuffAddr + local_idx);

+

+		/* The log entry may be overwritten by the new log entry and

+		 * the header becomes invalid due to slow UART TX speed.

+		 * IF the header meets following conditions, we assume that

+		 * the log entry is courrupted.

+		 * 1. The text length is greater then LOG_FMT_BUF_LEN.

+		 * 2. The text buffer address is out of range.

+		 */

+

+		if ((msg->log_len > HSM_LOG_FMT_BUF_LEN) ||

+		        (log_text(msg) > (gvBuffAddr + HSM_LOG_BUF_LEN)) ||

+		        (log_text(msg) < gvBuffAddr)) {

+			IMSG("[%s][%d]\r\n", __FUNCTION__, __LINE__);

+			break;

+		}

+

+		flush_to_console((uint8_t *)log_text(msg), msg->text_len);

+		local_idx = msg->next_idx;

+		local_first_seq++;

+	}

+

+	return 0;

+}

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_dump.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_dump.h
new file mode 100644
index 0000000..ddf1753
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_dump.h
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: BSD-2-Clause

+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * Copyright  (C) 2020  MediaTek Inc. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+

+#ifndef __HSM_DUMP_H__

+#define __HSM_DUMP_H__

+

+extern int hsm_dump_init(void);

+extern int hsm_dump_log(void);

+

+#endif //__HSM_DUMP_H__
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.c
new file mode 100644
index 0000000..365b9e0
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.c
@@ -0,0 +1,773 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#include <kernel/misc.h>
+#include <io.h>
+#include <stdio.h>
+#include <string.h>
+#include <tee/cache.h>
+#include <kernel/delay.h>
+#include "system_event.h"
+#include "mbox_serv.h"
+#include "km_ipc.h"
+#include "address.h"
+#include "sync_obj.h"
+#include "buddy.h"
+#include "hsm_job.h"
+#include "mtk_crypto.h"
+#include "share_memmap.h"
+#include "hsm_pta_debug.h"
+
+#define HSM_IN_BUF_OFFSET   (0)
+#define HSM_IN_BUF_LEN      (0x2000)                                // IN BUF 1  --> 8KB
+
+#define HSM_IN_BUF2_OFFSET  (HSM_IN_BUF_LEN)
+#define HSM_IN_BUF2_LEN     (0x400)                                 // IN BUF 2  --> 1KB
+
+#define HSM_IN_BUF3_OFFSET  (HSM_IN_BUF2_OFFSET + HSM_IN_BUF2_LEN)
+#define HSM_IN_BUF3_LEN     (0x400)                                 // IN BUF 3  --> 1KB
+
+#define HSM_OUT_BUF_OFFSET  (HSM_IN_BUF3_OFFSET + HSM_IN_BUF3_LEN)
+#define HSM_OUT_BUF_LEN     (0x2000)                                // OUT BUF 1 --> 8KB
+
+#define HSM_OUT_BUF2_OFFSET (HSM_OUT_BUF_OFFSET + HSM_OUT_BUF_LEN)
+#define HSM_OUT_BUF2_LEN    (0x400)                                 // OUT BUF 2 --> 1KB
+
+#define HSM_OUT_JOB_OFFSET  (HSM_OUT_BUF2_OFFSET + HSM_OUT_BUF2_LEN)
+#define HSM_OUT_JOB_LEN     (0x80)                                  // JOB BUF   --> 128B
+
+#define HSM_OUT_RET_OFFSET  (HSM_OUT_JOB_OFFSET + HSM_OUT_JOB_LEN)
+#define HSM_OUT_RET_LEN     (0x10)                                  // RET BUF   --> 16B
+
+vaddr_t mbox_io_buf_base;
+
+static uint32_t algo_2_eventid(uint32_t algo_type)
+{
+	uint32_t event_id = 0xffffffff;
+
+	switch (algo_type)
+	{
+	case CRYPTO_ALGOFAM_SHA1:
+	case CRYPTO_ALGOFAM_SHA2_224:
+	case CRYPTO_ALGOFAM_SHA2_256:
+	case CRYPTO_ALGOFAM_SHA2_384:
+	case CRYPTO_ALGOFAM_SHA2_512:
+	case CRYPTO_ALGOFAM_AES:
+		event_id = SYS_EVENT_CRY_AES_SHA;
+		break;
+	case CRYPTO_ALGOFAM_ECCNIST:
+		event_id = SYS_EVENT_CRY_ECC;
+		break;
+	case CRYPTO_ALGOFAM_RNG:
+	case CRYPTO_ALGOFAM_SECURECOUNTER:
+		event_id = SYS_EVENT_CRY_TRNG;
+		break;
+	case CRYPTO_ALGOFAM_NOT_SET:
+	default:
+		break;
+	}
+
+	return event_id;
+}
+
+static inline void _set_mbox_tx_header(struct sys_event *tx, int cpu_serial, int event_id)
+{
+	if (tx == NULL) {
+		HSM_PTA_ERROR("[%s][%d] invalid input ptr\n", __FUNCTION__, __LINE__);
+		return;
+	}
+	memset(tx, 0, sizeof(struct sys_event));
+	tx->cpu_serial = CPU_SERIAL_HSM;
+	tx->event_id = SYS_EVENT_KEY_MANAGEMENT;
+}
+
+
+int hsm_export_key(uint8_t *pblob, uint32_t blobsize, uint8_t *ppubkey, uint32_t *ppubkeylength) {
+	struct sys_event tx;
+	uint8_t mbox_ret = -1;
+	sync_handle sync = {0};
+	addr_t in_share_buffer = {0};
+	addr_t out_share_buffer = {0};
+	addr_t keylength = {0};
+	int hsm_ret = -1;
+
+	if (allocate_sync_handle(&sync) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(blobsize, &in_share_buffer) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(*ppubkeylength, &out_share_buffer) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(sizeof(uint32_t), &keylength) != 0 ) {
+		goto fail;
+	}
+	memput_and_cclean(&in_share_buffer, pblob, blobsize);
+	memput_and_cclean(&keylength, ppubkeylength, sizeof(uint32_t));
+
+	_set_mbox_tx_header(&tx, CPU_SERIAL_HSM, SYS_EVENT_KEY_MANAGEMENT);
+
+	tx.data.data[0] = KM_MBOX_CMD_EXPORT_KEY;
+	tx.data.data[1] = get_hsm_address(&in_share_buffer);
+	tx.data.data[2] = blobsize;
+	tx.data.data[3] = get_hsm_address(&out_share_buffer);
+	tx.data.data[4] = get_hsm_address(&keylength);
+	tx.data.data[14] = get_hsm_address(&sync);
+
+	mbox_ret = mbox_serv_tx(&tx);
+	if (mbox_ret != MBOX_SERV_OK) {
+		goto fail;
+	}
+
+	wait_remote_sync_done(&sync);
+	hsm_ret = get_hsm_return_value(&sync);
+	if (hsm_ret != 0) {
+		goto fail;
+	}
+	release_sync_handle(&sync);
+
+	cclean_and_memcopy(ppubkeylength, &keylength, sizeof(int));
+	cclean_and_memcopy(ppubkey, &out_share_buffer, *ppubkeylength);
+
+	physical_free(&in_share_buffer);
+	physical_free(&out_share_buffer);
+	physical_free(&keylength);
+
+	return hsm_ret;
+fail:
+	release_sync_handle(&sync);
+	physical_free(&in_share_buffer);
+	physical_free(&out_share_buffer);
+	physical_free(&keylength);
+
+	return hsm_ret;
+
+}
+
+int hsm_import_key(uint8_t *keybuffer, int size, int *pkey_id, int algo_id) {
+	struct sys_event tx;
+	uint8_t mbox_ret = -1;
+	sync_handle sync = {0};
+	addr_t keyid = {0};
+	addr_t share_buffer = {0};
+	int hsm_ret = -1;
+
+	if (allocate_sync_handle(&sync) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(sizeof(int), &keyid) != 0) {
+		goto fail;
+	}
+	if (physical_malloc(size, &share_buffer) != 0 ) {
+		goto fail;
+	}
+	memput_and_cclean(&share_buffer, keybuffer, size);
+
+	_set_mbox_tx_header(&tx, CPU_SERIAL_HSM, SYS_EVENT_KEY_MANAGEMENT);
+
+	tx.data.data[0] = KM_MBOX_CMD_IMPORT_KEY;
+	tx.data.data[1] = get_hsm_address(&share_buffer);
+	tx.data.data[2] = size;
+	tx.data.data[3] = get_hsm_address(&keyid);
+	tx.data.data[4] = algo_id;
+	tx.data.data[14] = get_hsm_address(&sync);
+
+	mbox_ret = mbox_serv_tx(&tx);
+	if (mbox_ret != MBOX_SERV_OK) {
+		goto fail;
+	}
+
+	wait_remote_sync_done(&sync);
+	hsm_ret = get_hsm_return_value(&sync);
+	if (hsm_ret != 0) {
+		goto fail;
+	}
+	release_sync_handle(&sync);
+
+	cclean_and_memcopy(pkey_id, &keyid, sizeof(int));
+
+	physical_free(&keyid);
+	physical_free(&share_buffer);
+
+	return hsm_ret;
+fail:
+	release_sync_handle(&sync);
+	physical_free(&keyid);
+	physical_free(&share_buffer);
+
+	return hsm_ret;
+}
+
+int hsm_delete_key(int key_id) {
+	struct sys_event tx;
+	uint8_t mbox_ret = -1;
+	sync_handle sync = {0};
+	int hsm_ret = -1;
+	if (allocate_sync_handle(&sync) != 0 ) {
+		goto fail;
+	}
+	_set_mbox_tx_header(&tx, CPU_SERIAL_HSM, SYS_EVENT_KEY_MANAGEMENT);
+
+	tx.data.data[0] = KM_MBOX_CMD_DELETE_KEY;
+	tx.data.data[1] = key_id;
+	tx.data.data[14] = get_hsm_address(&sync);
+	mbox_ret = mbox_serv_tx(&tx);
+	if (mbox_ret != MBOX_SERV_OK) {
+		goto fail;
+	}
+
+	wait_remote_sync_done(&sync);
+	hsm_ret = get_hsm_return_value(&sync);
+	if (hsm_ret != 0) {
+		goto fail;
+	}
+
+	release_sync_handle(&sync);
+	return hsm_ret;
+fail:
+	release_sync_handle(&sync);
+	return hsm_ret;
+}
+
+int hsm_gen_key_pair(int size, int uECC_curve_id, int *pkey_id) {
+	struct sys_event tx;
+	uint8_t mbox_ret = -1;
+	sync_handle sync = {0};
+	addr_t keyid = {0};
+	int hsm_ret = -1;
+
+	if (allocate_sync_handle(&sync) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(sizeof(int), &keyid) != 0) {
+		goto fail;
+	}
+
+	_set_mbox_tx_header(&tx, CPU_SERIAL_HSM, SYS_EVENT_KEY_MANAGEMENT);
+
+	tx.data.data[0] = KM_MBOX_CMD_KEY_PAIR_GENERATION;
+	tx.data.data[1] = size;
+	tx.data.data[2] = uECC_curve_id;
+	tx.data.data[3] = get_hsm_address(&keyid);
+	tx.data.data[14] = get_hsm_address(&sync);
+
+	mbox_ret = mbox_serv_tx(&tx);
+	if (mbox_ret != MBOX_SERV_OK) {
+		goto fail;
+	}
+
+	wait_remote_sync_done(&sync);
+	hsm_ret = get_hsm_return_value(&sync);
+	if (hsm_ret != 0) {
+		goto fail;
+	}
+	release_sync_handle(&sync);
+
+	cclean_and_memcopy(pkey_id, &keyid, sizeof(int));
+
+	physical_free(&keyid);
+	return hsm_ret;
+fail:
+	release_sync_handle(&sync);
+	physical_free(&keyid);
+
+	return hsm_ret;
+}
+
+int hsm_gen_symm_key(int size, int *pkeyid) {
+	struct sys_event tx;
+	uint8_t mbox_ret = -1;
+	sync_handle sync = {0};
+	addr_t keyid = {0};
+	int hsm_ret = -1;
+
+	if (allocate_sync_handle(&sync) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(sizeof(int), &keyid) != 0) {
+		goto fail;
+	}
+
+	_set_mbox_tx_header(&tx, CPU_SERIAL_HSM, SYS_EVENT_KEY_MANAGEMENT);
+
+	tx.data.data[0] = KM_MBOX_CMD_SYMM_KEY_GENERATION;
+	tx.data.data[1] = size;
+	tx.data.data[2] = get_hsm_address(&keyid);
+	tx.data.data[14] = get_hsm_address(&sync);
+
+	mbox_ret = mbox_serv_tx(&tx);
+	if (mbox_ret != MBOX_SERV_OK) {
+		goto fail;
+	}
+	wait_remote_sync_done(&sync);
+	hsm_ret = get_hsm_return_value(&sync);
+	if (hsm_ret != 0) {
+		goto fail;
+	}
+	release_sync_handle(&sync);
+
+	cclean_and_memcopy(pkeyid, &keyid, sizeof(int));
+
+	physical_free(&keyid);
+	return hsm_ret;
+fail:
+	HSM_PTA_ERROR("[%s][%d] mbox if fail ret : %d\n", __FUNCTION__, __LINE__, hsm_ret);
+	release_sync_handle(&sync);
+	physical_free(&keyid);
+
+	return hsm_ret;
+}
+
+
+int hsm_get_key_blob(uint8_t *dst, int size, int key_id, int algo_id, int *pblobsize) {
+	struct sys_event tx;
+	uint8_t mbox_ret = -1;
+	sync_handle sync = {0};
+	addr_t buffer = {0};
+	addr_t blob_size = {0};
+	int bsize = 0;
+	int hsm_ret = -1;
+
+	if (dst == NULL || pblobsize == NULL) {
+		goto fail;
+	}
+	if (allocate_sync_handle(&sync) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(size, &buffer) != 0) {
+		goto fail;
+	}
+	if (physical_malloc(sizeof(int), &blob_size) != 0) {
+		goto fail;
+	}
+
+	_set_mbox_tx_header(&tx, CPU_SERIAL_HSM, SYS_EVENT_KEY_MANAGEMENT);
+
+	tx.data.data[0] = KM_MBOX_CMD_GET_KEY_BLOB;
+	tx.data.data[1] = get_hsm_address(&buffer);
+	tx.data.data[2] = size;
+	tx.data.data[3] = key_id;
+	tx.data.data[4] = algo_id;
+	tx.data.data[5] = get_hsm_address(&blob_size);
+	tx.data.data[14] = get_hsm_address(&sync);
+
+	mbox_ret = mbox_serv_tx(&tx);
+	if (mbox_ret != MBOX_SERV_OK) {
+		goto fail;
+	}
+	wait_remote_sync_done(&sync);
+	hsm_ret = get_hsm_return_value(&sync);
+	if (hsm_ret != 0) {
+		goto fail;
+	}
+	release_sync_handle(&sync);
+
+	cclean_and_memcopy(&bsize, &blob_size, sizeof(int));
+
+	if (size < bsize) {
+		goto fail;
+	}
+	*pblobsize = bsize;
+
+	cclean_and_memcopy(dst, &buffer, bsize);
+
+	physical_free(&buffer);
+	physical_free(&blob_size);
+
+	return hsm_ret;
+
+fail:
+	HSM_PTA_ERROR("[%s][%d] mbox if fail ret : %d\n", __FUNCTION__, __LINE__, hsm_ret);
+	release_sync_handle(&sync);
+	physical_free(&buffer);
+	physical_free(&blob_size);
+
+	return hsm_ret;
+
+}
+
+int hsm_get_key_table(uint8_t *dst, int size, int *ptablesize) {
+	struct sys_event tx;
+	uint8_t mbox_ret = -1;
+	int hsm_ret = -1;
+	sync_handle sync = {0};
+	addr_t buffer = {0};
+	addr_t table_size = {0};
+	int tblsize = 0;
+
+	if (dst == NULL || ptablesize == NULL) {
+		goto fail;
+	}
+	if (allocate_sync_handle(&sync) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(size, &buffer) != 0) {
+		goto fail;
+	}
+	if (physical_malloc(sizeof(int), &table_size) != 0) {
+		goto fail;
+	}
+
+	_set_mbox_tx_header(&tx, CPU_SERIAL_HSM, SYS_EVENT_KEY_MANAGEMENT);
+
+	tx.data.data[0] = KM_MBOX_CMD_GET_KEY_TABLE;
+	tx.data.data[1] = get_hsm_address(&buffer);
+	tx.data.data[2] = size;
+	tx.data.data[3] = get_hsm_address(&table_size);
+	tx.data.data[14] = get_hsm_address(&sync);
+
+	mbox_ret = mbox_serv_tx(&tx);
+	if (mbox_ret != MBOX_SERV_OK) {
+		goto fail;
+	}
+	wait_remote_sync_done(&sync);
+	hsm_ret = get_hsm_return_value(&sync);
+	if (hsm_ret != 0) {
+		goto fail;
+	}
+	release_sync_handle(&sync);
+
+	cclean_and_memcopy(&tblsize, &table_size, sizeof(int));
+
+	if (size < tblsize) {
+		goto fail;
+	}
+	*ptablesize = tblsize;
+
+	cclean_and_memcopy(dst, &buffer, tblsize);
+
+	physical_free(&buffer);
+	physical_free(&table_size);
+
+	return hsm_ret;
+
+fail:
+	HSM_PTA_ERROR("[%s][%d] mbox if fail ret : %d\n", __FUNCTION__, __LINE__, hsm_ret);
+	release_sync_handle(&sync);
+	physical_free(&buffer);
+	physical_free(&table_size);
+
+	return hsm_ret;
+}
+
+int hsm_rebuild_key_table(uint8_t *buffer, int table_size) {
+	struct sys_event tx;
+	uint8_t mbox_ret = -1;
+	int hsm_ret = -1;
+	sync_handle sync = {0};
+	addr_t share_buffer = {0};
+	int tblsize = 0;
+
+	if (buffer == NULL) {
+		goto fail;
+	}
+	if (allocate_sync_handle(&sync) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(table_size, &share_buffer) != 0 ) {
+		goto fail;
+	}
+	memput_and_cclean(&share_buffer, buffer, table_size);
+
+	_set_mbox_tx_header(&tx, CPU_SERIAL_HSM, SYS_EVENT_KEY_MANAGEMENT);
+
+	tx.data.data[0] = KM_MBOX_CMD_REBUILD_KEY_TABLE;
+	tx.data.data[1] = get_hsm_address(&share_buffer);
+	tx.data.data[2] = table_size;
+	tx.data.data[14] = get_hsm_address(&sync);
+
+	mbox_ret = mbox_serv_tx(&tx);
+	if (mbox_ret != MBOX_SERV_OK) {
+		goto fail;
+	}
+	wait_remote_sync_done(&sync);
+	hsm_ret = get_hsm_return_value(&sync);
+	if (hsm_ret != 0) {
+		goto fail;
+	}
+	release_sync_handle(&sync);
+	physical_free(&share_buffer);
+
+	return hsm_ret;
+
+fail:
+	HSM_PTA_ERROR("[%s][%d] mbox if fail ret : %d\n", __FUNCTION__, __LINE__, hsm_ret);
+	release_sync_handle(&sync);
+	physical_free(&share_buffer);
+
+	return hsm_ret;
+}
+
+int hsm_rebuild_key_blob(uint8_t *buffer, int blob_size, int key_id)
+{
+	struct sys_event tx;
+	uint8_t mbox_ret = -1;
+	int hsm_ret = -1;
+	sync_handle sync = {0};
+	addr_t share_buffer = {0};
+	int tblsize = 0;
+
+	if (buffer == NULL) {
+		goto fail;
+	}
+	if (allocate_sync_handle(&sync) != 0 ) {
+		goto fail;
+	}
+	if (physical_malloc(blob_size, &share_buffer) != 0 ) {
+		goto fail;
+	}
+	memput_and_cclean(&share_buffer, buffer, blob_size);
+
+	_set_mbox_tx_header(&tx, CPU_SERIAL_HSM, SYS_EVENT_KEY_MANAGEMENT);
+
+	tx.data.data[0] = KM_MBOX_CMD_REBUILD_KEY_BLOB;
+	tx.data.data[1] = get_hsm_address(&share_buffer);
+	tx.data.data[2] = blob_size;
+	tx.data.data[3] = key_id;
+	tx.data.data[14] = get_hsm_address(&sync);
+
+	mbox_ret = mbox_serv_tx(&tx);
+	if (mbox_ret != MBOX_SERV_OK) {
+		goto fail;
+	}
+	wait_remote_sync_done(&sync);
+	hsm_ret = get_hsm_return_value(&sync);
+	if (hsm_ret != 0) {
+		goto fail;
+	}
+	release_sync_handle(&sync);
+	physical_free(&share_buffer);
+
+	return hsm_ret;
+
+fail:
+	HSM_PTA_ERROR("[%s][%d] mbox if fail ret : %d\n", __FUNCTION__, __LINE__, hsm_ret);
+	release_sync_handle(&sync);
+	physical_free(&share_buffer);
+
+	return hsm_ret;
+}
+
+int hsm_send_job(job_struct *pjob)
+{
+	uint32_t in_len, in_len2, in_len3;
+	uint8_t *in_buf = NULL;
+	uint8_t *in_buf3 = NULL;
+	uint32_t out_len = 0, out_len2 = 0;
+	uint8_t *out_buf = NULL;
+	uint8_t *out_buf2 = NULL;
+	uint8_t *IV = NULL;
+	job_struct job2hsm;
+	uint32_t hsmaddr_job = 0;
+	int ret = -1;
+	struct sys_event tx = {0};
+
+	HSM_PTA_DEBUG("[\x1b[31m%s\033[0m][%d]\n", __FUNCTION__, __LINE__);
+	memcpy(&job2hsm, pjob, sizeof(job_struct));
+
+	tx.event_id = algo_2_eventid(job2hsm.family);
+
+	// In buffer #1
+	HSM_PTA_DEBUG("\x1b[1;32m  inputLength: %d  \033[0m \n", job2hsm.inputLength);
+	in_len = job2hsm.inputLength;
+	if (in_len != 0)
+	{
+		in_buf = (uint8_t *)job2hsm.inputPtr;
+		memcpy(mbox_io_buf_base + HSM_IN_BUF_OFFSET, in_buf, in_len);
+		ret = hsm_addr_remap((uint32_t)HSM_ALL_IO_BUF_BASE + HSM_IN_BUF_OFFSET, &hsmaddr_job);
+		if (ret != 0)
+		{
+			HSM_PTA_ERROR("[\x1b[31m%s\033[0m] remap error : %d\n", __func__, ret);
+			return -1;
+		}
+		job2hsm.inputPtr = hsmaddr_job;
+	}
+
+	// In buffer #2
+	HSM_PTA_DEBUG("\x1b[1;32m  secondaryInputLength: %d  \033[0m \n", job2hsm.secondaryInputLength);
+	in_len2 = job2hsm.secondaryInputLength;
+	if (in_len2 != 0)
+	{
+		IV = (uint8_t *)job2hsm.secondaryInputPtr;
+		memcpy(mbox_io_buf_base + HSM_IN_BUF2_OFFSET, IV, in_len2);
+		ret = hsm_addr_remap((uint32_t)HSM_ALL_IO_BUF_BASE + HSM_IN_BUF2_OFFSET, &hsmaddr_job);
+		if (ret != 0)
+		{
+			HSM_PTA_ERROR("[\x1b[31m%s\033[0m] remap error : %d\n", __func__, ret);
+			return -1;
+		}
+		job2hsm.secondaryInputPtr = hsmaddr_job;
+	}
+
+	// In buffer #3
+	HSM_PTA_DEBUG("\x1b[1;32m  tertiaryInputLength: %d  \033[0m \n", job2hsm.tertiaryInputLength);
+	in_len3 = job2hsm.tertiaryInputLength;
+	if (in_len3 != 0)
+	{
+		in_buf3 = (uint8_t *)job2hsm.tertiaryInputPtr;
+		memcpy(mbox_io_buf_base + HSM_IN_BUF3_OFFSET, in_buf3, in_len2);
+		ret = hsm_addr_remap((uint32_t)HSM_ALL_IO_BUF_BASE + HSM_IN_BUF3_OFFSET, &hsmaddr_job);
+		if (ret != 0)
+		{
+			HSM_PTA_ERROR("[\x1b[31m%s\033[0m] remap error : %d\n", __func__, ret);
+			return -1;
+		}
+		job2hsm.tertiaryInputPtr = hsmaddr_job;
+	}
+
+	// Out buffer #1
+	HSM_PTA_DEBUG("\x1b[1;32m  OutputLength: %d  \033[0m \n", job2hsm.outputLength);
+	out_len = job2hsm.outputLength;
+	out_buf = (uint8_t *)job2hsm.outputPtr;
+	if (out_len != 0)
+	{
+		ret = hsm_addr_remap((uint32_t)HSM_ALL_IO_BUF_BASE + HSM_OUT_BUF_OFFSET, &hsmaddr_job);
+		if (ret != 0)
+		{
+			HSM_PTA_ERROR("[\x1b[31m%s\033[0m] remap error : %d\n", __func__, ret);
+			return -1;
+		}
+		job2hsm.outputPtr = hsmaddr_job;
+	}
+
+	// Out buffer #2
+	HSM_PTA_DEBUG("\x1b[1;32m  secondaryOutputLength: %d  \033[0m \n", job2hsm.secondaryOutputLength);
+	out_len2 = job2hsm.secondaryOutputLength;
+	out_buf2 = (uint8_t *)job2hsm.secondaryOutputPtr;
+	if (out_len2 != 0)
+	{
+		ret = hsm_addr_remap((uint32_t)HSM_ALL_IO_BUF_BASE + HSM_OUT_BUF2_OFFSET, &hsmaddr_job);
+		if (ret != 0)
+		{
+			HSM_PTA_ERROR("[\x1b[31m%s\033[0m] remap error : %d\n", __func__, ret);
+			return -1;
+		}
+		job2hsm.secondaryOutputPtr = hsmaddr_job;
+	}
+
+	// Return value pointer
+	ret = hsm_addr_remap((uint32_t)HSM_ALL_IO_BUF_BASE + HSM_OUT_RET_OFFSET, &hsmaddr_job);
+	if (ret != 0)
+	{
+		HSM_PTA_ERROR("[\x1b[31m%s\033[0m] remap error : %d\n", __func__, ret);
+		return -1;
+	}
+	job2hsm.retValPtr = hsmaddr_job;
+
+
+	HSM_PTA_DEBUG(" job2hsm.event_id :              0x%x\r\n", (uint32_t)job2hsm.event_id);
+	HSM_PTA_DEBUG(" job2hsm.priority :              0x%x\r\n", (uint32_t)job2hsm.priority);
+	HSM_PTA_DEBUG(" job2hsm.job_id :                0x%x\r\n", (uint32_t)job2hsm.job_id);
+	HSM_PTA_DEBUG(" job2hsm.service :               0x%x\r\n", (uint32_t)job2hsm.service);
+	HSM_PTA_DEBUG(" job2hsm.family :                0x%x\r\n", (uint32_t)job2hsm.family);
+	HSM_PTA_DEBUG(" job2hsm.operation_mode :        0x%x\r\n", (uint32_t)job2hsm.operation_mode);
+	HSM_PTA_DEBUG(" job2hsm.mode :                  0x%x\r\n", (uint32_t)job2hsm.mode);
+	HSM_PTA_DEBUG(" job2hsm.cryptoKeyId :           0x%x\r\n", (uint32_t)job2hsm.cryptoKeyId);
+	HSM_PTA_DEBUG(" job2hsm.keyLength :             0x%x\r\n", (uint32_t)job2hsm.keyLength);
+
+	// Job buffer
+	memcpy(mbox_io_buf_base + HSM_OUT_JOB_OFFSET, &job2hsm, sizeof(job_struct));
+	if (cache_operation(TEE_CACHECLEAN, mbox_io_buf_base, HSM_OUT_RET_OFFSET) != TEE_SUCCESS)
+	{
+		HSM_PTA_ERROR("\x1b[31m == CACHE FAIL!! == \033[0m\n");
+		return -1;
+	}
+	if (cache_operation(TEE_CACHEINVALIDATE, mbox_io_buf_base, (HSM_OUT_RET_OFFSET + HSM_OUT_RET_LEN)) != TEE_SUCCESS)
+	{
+		HSM_PTA_ERROR("\x1b[31m == CACHE INVALIDATE FAIL!! == \033[0m\n");
+		return -1;
+	}
+
+
+	ret = hsm_addr_remap((uint32_t)HSM_ALL_IO_BUF_BASE + HSM_OUT_JOB_OFFSET, &hsmaddr_job);
+	if (ret != 0)
+	{
+		HSM_PTA_ERROR("[\x1b[31m%s\033[0m] remap error : %d\n", __func__, ret);
+		return -1;
+	}
+	tx.data.data[0] = hsmaddr_job;
+
+
+	// Give return value a initial value
+	write8(MBOX_SERV_FEEDBACK_INIT_VAL, mbox_io_buf_base + HSM_OUT_RET_OFFSET);
+
+	// Send job with physical address to HSM, and wait for job done.
+	ret = mbox_serv_tx(&tx);
+
+	// Waiting for HSM done the job
+	uint8_t hsm_feedback_result = MBOX_SERV_FEEDBACK_INIT_VAL;
+	while (1)
+	{
+		// Invalidating cache
+		if (cache_operation(TEE_CACHECLEAN, mbox_io_buf_base, (HSM_OUT_RET_OFFSET + HSM_OUT_RET_LEN)) != TEE_SUCCESS)
+		{
+			HSM_PTA_ERROR("\x1b[31m == CACHE CLEAN FAIL!! == \033[0m\n");
+			return -1;
+		}
+		if (cache_operation(TEE_CACHEINVALIDATE, mbox_io_buf_base, (HSM_OUT_RET_OFFSET + HSM_OUT_RET_LEN)) != TEE_SUCCESS)
+		{
+			HSM_PTA_ERROR("\x1b[31m == CACHE INVALIDATE FAIL!! == \033[0m\n");
+			return -1;
+		}
+
+		hsm_feedback_result = read8(mbox_io_buf_base + HSM_OUT_RET_OFFSET);
+		// HSM_PTA_ERROR("hsm_feedback_result  %d \033[0m\n", hsm_feedback_result);
+		if (hsm_feedback_result != MBOX_SERV_FEEDBACK_INIT_VAL)
+		{
+			HSM_PTA_DEBUG("\x1b[33m Got HSM feedback: 0x%x \033[0m\n", hsm_feedback_result);
+			break;
+		}
+		mdelay(1);
+	}
+
+	if (hsm_feedback_result == MBOX_SERV_FEEDBACK_VERIFY_FAIL) {
+		HSM_PTA_ERROR("\x1b[31m == Verification FAIL!! == \033[0m\n");
+		return TEE_ERROR_SIGNATURE_INVALID;
+	}
+
+
+	if (out_len != 0) {
+		memcpy(out_buf, mbox_io_buf_base + HSM_OUT_BUF_OFFSET, out_len);
+	}
+
+	if (out_len2 != 0) {
+		memcpy(out_buf2, mbox_io_buf_base + HSM_OUT_BUF2_OFFSET, out_len2);
+	}
+
+	return 0;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.h
new file mode 100644
index 0000000..b85081a
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_if_impl.h
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#ifndef __HSM_IF_IMPL_H__
+#define __HSM_IF_IMPL_H__
+
+#include "hsm_job.h"
+
+extern int hsm_gen_key_pair(int size, int uECC_curve_id, int *pkey_id);
+extern int hsm_gen_symm_key(int size, int *pkeyid);
+extern int hsm_get_key_blob(uint8_t *dst, int size, int key_id, int algo_id, int *pblobsize);
+extern int hsm_get_key_table(uint8_t *dst, int size, int *ptablesize);
+extern int hsm_rebuild_key_table(uint8_t *buffer, int table_size);
+extern int hsm_rebuild_key_blob(uint8_t *buffer, int blob_size, int key_id);
+extern int hsm_import_key(uint8_t *keybuffer, int size, int *pkey_id, int algo_id);
+extern int hsm_export_key(uint8_t *pblob, uint32_t blobsize, uint8_t *ppubkey, uint32_t *ppubkeylength);
+extern int hsm_send_job(job_struct *pjob);
+extern int hsm_delete_key(int key_id);
+
+#endif /*__HSM_IF_IMPL_H__*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_mbox_if.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_mbox_if.c
new file mode 100644
index 0000000..6ddaa77
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_mbox_if.c
@@ -0,0 +1,326 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#include <io.h>
+#include <kernel/pseudo_ta.h>
+#include <tee_api_defines.h>
+#include <kernel/thread.h>
+#include <kernel/interrupt.h>
+#include <kernel/misc.h>
+#include <mm/core_memprot.h>
+#include <kernel/tee_time.h>
+
+// For memcpy
+#include <string.h>
+
+// For cache clean and invalidate
+#include <mm/core_memprot.h>
+#include <mm/core_mmu.h>
+#include <tee/cache.h>
+
+#include "hsm_mbox_if.h"
+#include "hsm_if_impl.h"
+#include "hsm_pta_debug.h"
+#include "system_event.h"
+#include "mbox_serv.h"
+#include "mtk_crypto.h"
+
+#include "buddy.h"
+#include "share_memmap.h"
+#include "sync_obj.h"
+#include "hsm_dump.h"
+
+extern vaddr_t mbox_io_buf_base;
+
+static void _pta_hsm_gen_key_pair_handler(TEE_Param *pParams)
+{
+	int *phsmret, *pkeyid;
+	int size;
+	int uECC_curve_id;
+
+	phsmret = (int*)pParams[0].value.a;
+	size = (int)pParams[0].value.b;
+	uECC_curve_id = (int)pParams[1].value.a;
+	pkeyid = (int*)pParams[1].value.b;
+
+	*phsmret = hsm_gen_key_pair(size, uECC_curve_id, pkeyid);
+
+	return;
+}
+
+static void _pta_hsm_gen_symm_key_handler(TEE_Param *pParams)
+{
+	int *phsmret, *pkeyid;
+	int key_size;
+
+	phsmret = (int*)pParams[0].value.a;
+	pkeyid = (int*)pParams[0].value.b;
+	key_size = (int)pParams[1].value.a;
+
+	*phsmret = hsm_gen_symm_key(key_size, pkeyid);
+
+	return;
+}
+
+static void _pta_hsm_get_key_blob_handler(TEE_Param *pParams)
+{
+	int *phsmret, *pblobsize;
+	int buf_size, key_id, algo_id;
+	uint8_t *buffer;
+
+	phsmret = (int*) pParams[0].value.a;
+	key_id = (int) pParams[0].value.b;
+	buffer = (uint8_t *) pParams[1].value.a;
+	buf_size = (int) pParams[1].value.b;
+	algo_id = (int) pParams[2].value.a;
+	pblobsize = (int*) pParams[2].value.b;
+
+	*phsmret = hsm_get_key_blob(buffer, buf_size, key_id, algo_id, pblobsize);
+
+	return;
+}
+
+static void _pta_hsm_get_key_table_handler(TEE_Param *pParams)
+{
+	int *phsmret, *ptablesize;
+	int buf_size;
+	uint8_t *buffer;
+
+	phsmret = (int*)pParams[0].value.a;
+	buffer = (uint8_t *)pParams[0].value.b;
+	buf_size = (int)pParams[1].value.a;
+	ptablesize = (int*)pParams[1].value.b;
+
+	*phsmret = hsm_get_key_table(buffer, buf_size, ptablesize);
+
+	return;
+}
+
+static void _pta_hsm_rebuild_key_table_handler(TEE_Param *pParams)
+{
+	int *phsmret;
+	int table_size;
+	uint8_t *buffer;
+
+	phsmret = (int*)pParams[0].value.a;
+	buffer = (uint8_t *)pParams[0].value.b;
+	table_size = (int)pParams[1].value.a;
+
+	*phsmret = hsm_rebuild_key_table(buffer, table_size);
+
+	return;
+}
+
+static void _pta_hsm_rebuild_key_blob_handler(TEE_Param *pParams)
+{
+	int *phsmret;
+	int blob_size;
+	int key_id;
+	uint8_t *buffer;
+
+	phsmret = (int*)pParams[0].value.a;
+	buffer = (uint8_t *)pParams[0].value.b;
+	blob_size = (int)pParams[1].value.a;
+	key_id = (int)pParams[1].value.b;
+
+	*phsmret = hsm_rebuild_key_blob(buffer, blob_size, key_id);
+
+	return;
+}
+
+
+static void _pta_hsm_import_key(TEE_Param *pParams)
+{
+	int *phsmret;
+	uint8_t *keybuffer;
+	int size;
+	int *pkeyid;
+	int algo_id;
+
+	phsmret = (int*)pParams[0].value.a;
+	keybuffer = (uint8_t *)pParams[0].value.b;
+	size = (int)pParams[1].value.a;
+	pkeyid = (int*)pParams[1].value.b;
+	algo_id = (int*)pParams[2].value.a;
+
+	*phsmret = hsm_import_key(keybuffer, size, pkeyid, algo_id);
+
+	return;
+}
+
+static void _pta_hsm_export_key(TEE_Param *pParams)
+{
+	int *phsmret;
+	uint8_t *pblob;
+	uint32_t blobsize;
+	uint8_t *ppubkey;
+	uint32_t *ppubkeylength;
+
+	phsmret = (int*)pParams[0].value.a;
+	pblob = (uint8_t *)pParams[0].value.b;
+	blobsize = (int)pParams[1].value.a;
+	ppubkey = (uint8_t *)pParams[1].value.b;
+	ppubkeylength = (int*)pParams[2].value.a;
+
+	*phsmret = hsm_export_key(pblob, blobsize, ppubkey, ppubkeylength);
+
+	return;
+}
+
+static void _pta_hsm_send_job_handler(TEE_Param *pParams)
+{
+	int *phsmret;
+	job_struct *pjob;
+	uint32_t in_size;
+
+	pjob = (job_struct *)(pParams[0].value.a);
+	in_size = pParams[0].value.b;
+	phsmret = (int*)pParams[1].value.a;
+
+	*phsmret = hsm_send_job(pjob);
+}
+
+static void _pta_hsm_delete_key(TEE_Param *pParams)
+{
+	int *phsmret;
+	uint32_t keyid;
+
+	phsmret = (int*)pParams[0].value.a;
+	keyid = (uint32_t)pParams[0].value.b;
+
+	*phsmret = hsm_delete_key(keyid);
+
+	return;
+}
+
+TEE_Result TA_CreateEntryPoint(void)
+{
+	static int inited = 0;
+
+	if (inited)
+		return TEE_SUCCESS;
+
+	/* Allocate some resources, init something, ... */
+	mbox_serv_init();
+	hsm_dump_init();
+	buddy_init();
+
+	core_mmu_add_mapping(MEM_AREA_RAM_SEC, HSM_ALL_IO_BUF_BASE, HSM_ALL_IO_BUF_LEN);
+	mbox_io_buf_base = (vaddr_t)phys_to_virt(HSM_ALL_IO_BUF_BASE, MEM_AREA_RAM_SEC);
+
+	inited = 1;
+
+	/* Return with a status */
+	return TEE_SUCCESS;
+}
+
+void TA_DestroyEntryPoint(void)
+{
+	/* Release resources if required before TA destruction */
+}
+
+/* Static Function */
+static TEE_Result invoke_command(void *pSessionContext __unused,
+                                 uint32_t nCommandID, uint32_t nParamTypes,
+                                 TEE_Param pParams[TEE_NUM_PARAMS])
+{
+	if(pParams == NULL){
+		return TEE_ERROR_BAD_PARAMETERS;
+	}
+
+	HSM_PTA_DEBUG("\x1b[1;31m MBOX receives nCommandID(%x)  \033[0m\n", nCommandID);
+
+	switch (nCommandID)
+	{
+	case PTA_CMD_HSM_SEND_JOB:
+		_pta_hsm_send_job_handler(pParams);
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_GEN_KEY_PAIR:
+		_pta_hsm_gen_key_pair_handler(pParams);
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_GEN_SYMM_KEY:
+		_pta_hsm_gen_symm_key_handler(pParams);
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_GET_KEY_BLOB:
+		_pta_hsm_get_key_blob_handler(pParams);
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_GET_KEY_TABLE:
+		_pta_hsm_get_key_table_handler(pParams);
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_REBUILD_KEY_TABLE:
+		_pta_hsm_rebuild_key_table_handler(pParams);
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_REBUILD_KEY_BLOB:
+		_pta_hsm_rebuild_key_blob_handler(pParams);
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_IMPORT_KEY:
+		_pta_hsm_import_key(pParams);
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_EXPORT_KEY:
+		_pta_hsm_export_key(pParams);
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_DUMP_LOG:
+		hsm_dump_log();
+		return TEE_SUCCESS;
+
+	case PTA_CMD_HSM_DELETE_KEY:
+		_pta_hsm_delete_key(pParams);
+		return TEE_SUCCESS;
+
+	default:
+		break;
+	}
+
+	return TEE_ERROR_NOT_IMPLEMENTED;
+}
+
+pseudo_ta_register(.uuid = PTA_MBOX_UUID, .name = "mbox",
+                   .flags = PTA_DEFAULT_FLAGS,
+                   .invoke_command_entry_point = invoke_command,
+                   .create_entry_point = TA_CreateEntryPoint,
+                   .destroy_entry_point = TA_DestroyEntryPoint);
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_pta_debug.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_pta_debug.h
new file mode 100644
index 0000000..596f453
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/hsm_pta_debug.h
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#ifndef __HSM_PTA_DEBUG_H__
+#define __HSM_PTA_DEBUG_H__
+
+/****************************************
+ * # 0: none
+ * # 1: error
+ * # 2: error + warning
+ * # 3: error + warning + debug
+ * # 4: error + warning + debug + flow
+ ****************************************/
+#define HSM_PTA_LOG_LEVEL             3
+
+#define HSM_PTA_ERROR_LOG_LEVEL       1
+#define HSM_PTA_INFO_LOG_LEVEL        2
+#define HSM_PTA_DEBUG_LOG_LEVEL       3
+#define HSM_PTA_FLOW_LOG_LEVEL        4
+
+#if (HSM_PTA_FLOW_LOG_LEVEL <= HSM_PTA_LOG_LEVEL)
+#define HSM_PTA_FLOW(x...) FMSG(x)
+#else
+#define HSM_PTA_FLOW(x...)
+#endif
+
+#if (HSM_PTA_DEBUG_LOG_LEVEL <= HSM_PTA_LOG_LEVEL)
+#define HSM_PTA_DEBUG(x...) DMSG(x)
+#else
+#define HSM_PTA_DEBUG(x...)
+#endif
+
+#if (HSM_PTA_INFO_LOG_LEVEL <= HSM_PTA_LOG_LEVEL)
+#define HSM_PTA_INFO(x...) IMSG(x)
+#else
+#define HSM_PTA_INFO(x...)
+#endif
+
+#if (HSM_PTA_ERROR_LOG_LEVEL <= HSM_PTA_LOG_LEVEL)
+#define HSM_PTA_ERROR(x...) EMSG(x)
+#else
+#define HSM_PTA_ERROR(x...)
+#endif
+
+
+#endif /*__HSM_PTA_DEBUG_H__*/
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/km_ipc.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/km_ipc.h
new file mode 100644
index 0000000..864597b
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/km_ipc.h
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: BSD-2-Clause

+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+#ifndef __KEY_IPC_H__

+#define __KEY_IPC_H__

+

+typedef enum KM_MBOX_CMD

+{

+	KM_MBOX_CMD_START = 0,

+	/* TEE <-> HSM*/

+	KM_MBOX_CMD_TRIGGER_REMOTE_TO_RECV,

+	KM_MBOX_CMD_TRIGGER_HSM_TO_READ_ELEMENT,

+	/* TEE <- HSM*/

+	KM_MBOX_CMD_STORE_KEY_ELEMET,

+	KM_MBOX_CMD_GET_ELEMET_CBK,

+	KM_MBOX_CMD_READ_KE_TABLE_ELEMENTS,

+	KM_MBOX_CMD_HSM_BUILDUP_TABLE_DONE,

+	/* TEE -> HSM*/

+	KM_MBOX_CMD_SET_ELEMENT,

+	KM_MBOX_CMD_GET_ELEMENT,

+	KM_MBOX_CMD_STORE_KEY_ELEMET_DONE,

+	KM_MBOX_CMD_TRIGGER_REBUILD_KE_TABLE,

+	KM_MBOX_CMD_READ_KE_TABLE_ELEMENTS_DONE,

+	/* OPTEE USED */

+	KM_MBOX_CMD_KEY_PAIR_GENERATION,

+	KM_MBOX_CMD_SYMM_KEY_GENERATION,

+	KM_MBOX_CMD_GET_KEY_BLOB,

+	KM_MBOX_CMD_GET_KEY_TABLE,

+	KM_MBOX_CMD_REBUILD_KEY_TABLE,

+	KM_MBOX_CMD_REBUILD_KEY_BLOB,

+	KM_MBOX_CMD_IMPORT_KEY,

+	KM_MBOX_CMD_EXPORT_KEY,

+	KM_MBOX_CMD_DELETE_KEY,

+	KM_MBOX_CMD_END,

+} km_mbox_cmd;

+

+#endif //__KEY_IPC_H__

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_common.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_common.h
new file mode 100644
index 0000000..9770d89
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_common.h
@@ -0,0 +1,57 @@
+/*

+ * Copyright (c) 2018 MediaTek Inc.

+ *

+ * 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 __MBOX_COMMON_H__

+#define __MBOX_COMMON_H__

+

+#include <stdint.h>

+// #include <drStd.h>

+// #include <DrApi/DrApi.h>

+// #include <DrApi/DrApiLogging.h>

+// #include <DrApi/DrApiThread.h>

+#include "drCommon.h"

+

+#include "tee_common.h"

+#include "mbox_hw.h"

+#include "mbox_sw.h"

+#include "reg_op.h"

+#include "processor.h"

+#include "system_event.h"

+

+#define MBOX_DEBUG      0

+

+#if MBOX_DEBUG

+#define TEE_MBOX_DEBUG(string, args...)            \

+	if(1) {                                   \

+		drDbgPrintf("[MBOX]"string, ##args);  \

+	}

+#else

+#define TEE_MBOX_DEBUG(string, args...)

+#endif

+

+#define TEE_MBOX_ERR(string, args...)              \

+	if(1) {                                   \

+		drDbgPrintf("[MBOX]"string, ##args);  \

+	}

+

+#endif  // __MBOX_COMMON_H__

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_drv.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_drv.c
new file mode 100644
index 0000000..c62756b
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_drv.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * 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 <stdio.h>
+#include <kernel/interrupt.h>
+#include <mm/core_memprot.h>
+
+#include "reg_op.h"
+#include "mbox_hw.h"
+#include "mbox_sw.h"
+#include "mbox_drv.h"
+
+// extern void mtk_mbox_irq_start_thread(int irq);
+// extern void mtk_mbox_irq_stop_thread(int irq);
+
+
+struct mbox_info {
+	const uint32_t base;
+	struct mbox_reg *vbase;
+	uint32_t irq;
+	uint32_t err_irq_num;
+};
+
+struct erm_info {
+	const uint32_t base;
+	struct erm_reg *vbase;
+	uint32_t irq;
+};
+
+
+register_phys_mem(MEM_AREA_IO_SEC, HSM_MBOX_BASE, MBOX_REGISTER_RANGE);
+register_phys_mem(MEM_AREA_IO_SEC, HSM_ERMST_BASE, ERMST_REGISTER_RANGE);
+
+/* MBOX base mapping */
+static struct mbox_info mbox[CPU_SERIAL_CNT] = {
+	{(const uint32_t)HSM_MBOX_BASE, (struct mbox_reg*)NULL, IVALID_IRQ_ID,  INVALID_MBOX_E_IRQ},
+	{(const uint32_t)HSM_MBOX_BASE, (struct mbox_reg*)NULL, IVALID_IRQ_ID,  INVALID_MBOX_E_IRQ},
+};
+
+static struct erm_info erm = {
+	.base = HSM_ERMST_BASE,
+	.vbase = NULL,
+	.irq = ERM_IRQ_ID,
+};
+
+/* pointer to self */
+static const struct mbox_info *p_mbox;
+
+/* callback function */
+static void (*mbox_user_isr)(uint8_t msg_id);
+
+static uint8_t ca53_itr_msg_id = -1;
+
+
+void mbox_reset(void)
+{
+	uint8_t i = 0;
+	write32(&p_mbox->vbase->msg_irq_en, 0UL);
+	write32(&p_mbox->vbase->region_irq_en, 0UL);
+
+	for (i = MBOX_MSG_ID_MIN; i <= MBOX_MSG_ID_MAX; i++) {
+		write32(&p_mbox->vbase->msg[i], 0UL);
+	}
+
+	write32(&p_mbox->vbase->msg_pending, 0xFFFFFFFFUL);
+}
+
+/* MBOX_REQ_MSG_PENDING */
+static inline uint32_t mbox_get_msg_bit_offset(uint8_t msg_id)
+{
+	return BIT(31UL - (uint32_t)(msg_id));
+}
+
+/* MBOX_NS_DOMAIN_CFG */
+static inline uint32_t mbox_get_domain_offset(enum mbox_regions region)
+{
+	return (28UL - ((uint32_t)(region) * 4UL));
+}
+
+static inline uint32_t mbox_get_sec_offset(enum mbox_regions region)
+{
+	return (31UL - ((uint32_t)(region) * 4UL));
+}
+
+static inline uint32_t mbox_get_boundary_offset(uint8_t boundary)
+{
+	return (24UL - ((uint32_t)(boundary) * 8UL));
+}
+
+static inline int8_t mbox_is_pending(uint8_t msg_id, uint32_t pending)
+{
+	int8_t result = MBOX_FAIL;
+
+	if ((pending & mbox_get_msg_bit_offset(msg_id)) > 0UL) {
+		result = MBOX_SUCC;
+	}
+
+	return result;
+}
+
+static void __mbox_register_interrupt(void)
+{
+	uint32_t irq = erm.irq;
+
+	// mtk_mbox_irq_start_thread(irq);
+}
+
+static void __mbox_unregister_interrupt(void)
+{
+	uint32_t irq = erm.irq;
+
+	// mtk_mbox_irq_stop_thread(irq);
+}
+
+static enum itr_return mbox_isr(struct itr_handler *h)
+{
+	EMSG("[%s: %d]\n", __func__, __LINE__);
+	uint32_t pending = read32(&erm.vbase->pending);
+
+	/*
+	 * clear pending.
+	 * Please clear it before callback to avoid racing condition in the
+	 * MBOX service.
+	 */
+	write32(&erm.vbase->pending, pending);
+
+	if ((mbox_user_isr != NULL) && ((pending & BIT(ERM_LBIST_BIT) ) != 0UL)) {
+		mbox_user_isr(ca53_itr_msg_id);
+		mbox_irq_done();
+	}
+	return ITRR_HANDLED;
+}
+KEEP_PAGER(mbox_isr);
+
+uint8_t mbox_itr_data = 0;
+static struct itr_handler mbox_itr = {
+	.it = ERM_IRQ_ID,
+	.flags = ITRF_TRIGGER_LEVEL,
+	.handler = mbox_isr,
+	.data = &mbox_itr_data,
+};
+KEEP_PAGER(mbox_itr);
+
+extern bool itr_set_polarity(unsigned int irq, unsigned int polarity);
+static int init_mbox_itr(void)
+{
+	*((uint8_t*)(mbox_itr.data)) = 321;
+	itr_add(&mbox_itr);
+	itr_enable(ERM_IRQ_ID);
+	return 0;
+}
+
+void mbox_init(enum CPU_SERIAL cpu_serial,
+               void (*p_mbox_msg_isr)(uint8_t msg_id))
+{
+	// uint8_t *RegBase_virtual;
+
+	/* point to self */
+	p_mbox = &mbox[cpu_serial];
+
+	for (int i = 0; i < CPU_SERIAL_CNT; ++i)
+	{
+		if (mbox[i].base != (const uint32_t)NULL)
+		{
+			mbox[i].vbase = (vaddr_t)phys_to_virt_io(mbox[i].base);
+			IMSG("[%s] mbox[i].vbase : 0x%x\n", __FUNCTION__, mbox[i].vbase);
+		}
+	}
+	erm.vbase = (vaddr_t)phys_to_virt_io(erm.base);
+	IMSG("[%s] erm.vbase : 0x%x\n", __FUNCTION__, erm.vbase);
+	// mbox_reset();
+
+	/* store callback */
+	mbox_user_isr = p_mbox_msg_isr;
+
+	// init_mbox_itr();
+
+}
+
+void mbox_deinit(void)
+{
+
+}
+
+void mbox_irq_done(void)
+{
+	uint32_t pending = read32(&erm.vbase->pending);
+	write32(&erm.vbase->pending, pending);
+
+	clrbits_le32(&erm.vbase->irq_set, BIT(ERM_LBIST_BIT));
+}
+
+void mbox_msg_tx(enum CPU_SERIAL send_to, uint8_t msg_id, uint32_t msg)
+{
+	if (msg_id <= MBOX_MSG_ID_MAX) {
+		write32(&mbox[send_to].vbase->msg[msg_id], msg);
+	}
+}
+
+void mbox_msg_rx(enum CPU_SERIAL send_to, uint8_t msg_id, uint32_t *pmsg)
+{
+	if ((msg_id <= MBOX_MSG_ID_MAX) && (pmsg != NULL)) {
+		*pmsg = read32(&mbox[send_to].vbase->msg[msg_id]);
+	}
+}
+
+void mbox_set_ca53_intr_msg_id(uint8_t msg_id)
+{
+	ca53_itr_msg_id = msg_id;
+}
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_drv.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_drv.h
new file mode 100644
index 0000000..4f516e7
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_drv.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 MediaTek Inc.
+ *
+ * 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 __MBOX_DRV_H__

+#define __MBOX_DRV_H__

+

+#include <stdint.h>

+#include "processor.h"

+

+#define MBOX_SUCC 		0

+#define MBOX_FAIL 		-1

+

+#define MBOX_MSG_ID_MIN 	0U

+#define MBOX_MSG_ID_MAX 	31U

+#define MBOX_INVALID 		0xFFU

+

+#define MBOX_REGION_SIZE_MIN 	0U

+#define MBOX_REGION_SIZE_MAX 	32U

+

+enum mbox_regions {

+	MBOX_REGION_0,

+	MBOX_REGION_1,

+	MBOX_REGION_2,

+	MBOX_REGION_3,

+	MBOX_REGION_RX,

+	MBOX_DOMAIN_CNT,

+	MBOX_REGION_INVALID = -1,

+};

+

+/* Give boundary of r0,r1,r2, then the rest space is for r3 */

+#define MBOX_BOUNDARY_01	0U

+#define MBOX_BOUNDARY_12	1U

+#define MBOX_BOUNDARY_CNT	2U

+

+#define ISR(x) void x(void)

+

+// extern void mbox_init(void);

+extern void mbox_deinit(void);

+// extern void mbox_write(int idx, int val);

+// extern void mbox_read(int idx, uint32_t *pmsg);

+extern void mbox_irq_done(void);

+

+extern void mbox_init(enum CPU_SERIAL cpu_serial, void (*p_mbox_msg_isr)(uint8_t msg_id));

+

+extern void mbox_msg_tx(enum CPU_SERIAL send_to, uint8_t msg_id, uint32_t msg);

+extern void mbox_msg_rx(enum CPU_SERIAL send_to, uint8_t msg_id, uint32_t *pmsg);

+

+extern void mbox_set_ca53_intr_msg_id(uint8_t msg_id);

+

+#endif //__MBOX_DRV_H__

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_hw.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_hw.h
new file mode 100644
index 0000000..073b6ba
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_hw.h
@@ -0,0 +1,46 @@
+/*

+ * Copyright (c) 2018 MediaTek Inc.

+ *

+ * 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 __MBOX_HW_H__

+#define __MBOX_HW_H__

+

+// #include "reg_base.h"

+

+#define IO_PHYS  0x10000000

+

+#define HSM_MBOX_BASE       (IO_PHYS + 0x00651000)

+#define HSM_ERMST_BASE		(IO_PHYS + 0x00650000)

+

+#define MBOX_REGISTER_RANGE           0x180

+#define ERMST_REGISTER_RANGE          0x28

+

+#define IVALID_IRQ_ID               0

+#define ERM_IRQ_ID                196//91

+

+#define ERM_LBIST_BIT             2

+

+#define CA53_INTR_MSG_ID          15

+

+#define INVALID_MBOX_E_IRQ        (-1)

+

+#endif //__MBOX_HW_H__
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_serv.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_serv.c
new file mode 100644
index 0000000..cecac1d
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_serv.c
@@ -0,0 +1,408 @@
+/*

+ * Copyright (c) 2018 MediaTek Inc.

+ *

+ * 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 <stdio.h>

+#include <string.h>

+#include <kernel/interrupt.h>

+#include <mm/core_memprot.h>

+

+#include "mbox_drv.h"

+#include "mbox_serv.h"

+#include "system_event.h"

+#include "processor.h"

+

+#define MBOX_SERV_MAGIC_NUM     0x5AA52731UL

+#define MBOX_SERV_MAGIC_ERROR   0xCCE2911BUL

+

+#define MBOX_SERV_TX_DELAY_MS     1UL

+#define MBOX_SERV_TX_DELAY_CNT    1UL

+#define MBOX_SERV_TX_DELAY	(MBOX_SERV_TX_DELAY_MS / MBOX_SERV_TX_DELAY_CNT)

+

+struct mbox_domain {

+	uint8_t domain;

+	uint8_t security;

+};

+

+struct mbox_serv_table {

+	enum mbox_regions region;

+	enum CPU_SERIAL cpu_serial;

+};

+

+static const struct mbox_serv_table mbox_serv_tb[][MBOX_SERV_ENTRY_CNT] = {

+	/* CA53 */

+	{

+		{MBOX_REGION_0,  CPU_SERIAL_HSM},

+		{MBOX_REGION_1,  CPU_SERIAL_CA53},

+	},

+

+	/* HSM */

+	{

+		{MBOX_REGION_0,  CPU_SERIAL_HSM},

+		{MBOX_REGION_1,  CPU_SERIAL_CA53},

+	},

+};

+

+static enum CPU_SERIAL mbox_serv_serial;

+static const struct mbox_serv_table *p_mbox_serv;

+static struct mbox_serv_registry mbox_serv_registry_tb[SYS_EVENT_CNT];

+static int8_t mbox_serv_mutex[MBOX_DOMAIN_CNT];

+

+static inline void mbox_serv_ack(uint8_t msg_id)

+{

+	/* clear macgic number. Let sender knows that we received the msg */

+	mbox_msg_tx(mbox_serv_serial, msg_id, MBOX_SERV_MAGIC_NUM);

+}

+

+static inline void mbox_serv_ack_error(uint8_t msg_id)

+{

+	/* clear macgic number. Let sender knows that there is something wrong in isr */

+	mbox_msg_tx(mbox_serv_serial, msg_id, MBOX_SERV_MAGIC_ERROR);

+}

+

+static int8_t wait_remote_ack(enum CPU_SERIAL dest, uint8_t msg_id)

+{

+	uint32_t data = 0;

+	int8_t result = MBOX_SERV_ERR_FAIL;

+

+	/* wait remote set MBOX_SERV_MAGIC_NUM or MBOX_SERV_MAGIC_ERROR to mail box*/

+	while(1)

+	{

+		mbox_msg_rx(dest, msg_id, &data);

+		if (data == MBOX_SERV_MAGIC_NUM)

+		{

+			result = MBOX_SERV_OK;

+			break;

+		}

+		else if (data == MBOX_SERV_MAGIC_ERROR)

+		{

+			result = MBOX_SERV_ERR_REMOTE_FAIL;

+			// mbox_msg_rx(dest, msg_id + 1, &data);

+			mbox_msg_tx(dest, msg_id, MBOX_SERV_MAGIC_NUM);

+			mbox_msg_rx(dest, msg_id + 1, &data);

+			result = (int8_t)data;

+			break;

+		}

+		// drApiThreadSleep(1/*ms*/); //TODO

+	}

+

+	return result;

+}

+

+static int8_t mbox_serv_get_res(enum mbox_regions region)

+{

+	uint8_t i;

+	int8_t result = MBOX_SERV_ERR_BUSY;

+

+	for (i = 0; i < MBOX_SERV_TX_DELAY_CNT; i++) {

+		// SuspendAllInterrupts();

+		if (mbox_serv_mutex[(uint8_t)region] == false) {

+			mbox_serv_mutex[(uint8_t)region] = true;

+			// ResumeAllInterrupts();

+			result = 0;

+			break;

+		}

+		// ResumeAllInterrupts();

+

+		// drApiThreadSleep(MBOX_SERV_TX_DELAY); //TODO

+	}

+	return result;

+}

+

+static void mbox_serv_release_res(enum mbox_regions region)

+{

+	mbox_serv_mutex[(uint8_t)region] = false;

+}

+

+static int8_t mbox_serv_is_ack(enum CPU_SERIAL dest, uint8_t msg_id)

+{

+	int8_t result = false;

+	uint8_t i;

+	uint32_t data = 0;

+

+

+	for (i = 0; i < MBOX_SERV_TX_DELAY_CNT; i++) {

+		/* Get target header to check that it received the msg or not */

+		mbox_msg_rx(dest, msg_id, &data);

+

+		/* Data is cleared after msg is taken */

+		if (data == MBOX_SERV_MAGIC_NUM)  {

+			result = true;

+			break;

+		}

+

+		// drApiThreadSleep(MBOX_SERV_TX_DELAY); //TODO

+	}

+

+	return result;

+}

+

+static inline uint8_t mbox_serv_convert_msg_id(uint8_t idx)

+{

+	return idx * MBOX_ENTRY_SIZE;

+}

+

+static int8_t mbox_serv_search_msg_id(enum CPU_SERIAL src,

+                                      enum CPU_SERIAL dest,

+                                      enum mbox_regions *region,

+                                      uint8_t *msg_id)

+{

+	uint8_t i;

+	int8_t result = MBOX_SERV_ERR_FAIL;

+

+	for (i = 0; i < MBOX_SERV_ENTRY_CNT; i++) {

+		if (mbox_serv_tb[dest][i].cpu_serial == src) {

+			*msg_id = mbox_serv_convert_msg_id(i);

+			*region = mbox_serv_tb[dest][i].region;

+			result = 0;

+			break;

+		}

+	}

+

+	return result;

+}

+

+static inline int8_t mbox_serv_q_is_empty(const struct mbox_serv_queue *q)

+{

+	int8_t result = false;

+

+	if (q->in_idx == q->out_idx) {

+		result = true;

+	}

+

+	return result;

+}

+

+static inline int8_t mbox_serv_q_is_full(const struct mbox_serv_queue *q)

+{

+	uint8_t idx;

+	int8_t result = false;

+

+	idx = (q->in_idx + 1U) % MBOX_SERV_QUEUE_SIZE;

+

+	if (idx == q->out_idx) {

+		result = true;

+	}

+

+	return result;

+}

+

+static inline void mbox_serv_enqueue(struct mbox_serv_queue *const q)

+{

+	if (q != NULL) {

+		q->in_idx = (q->in_idx + 1U) % MBOX_SERV_QUEUE_SIZE;

+	}

+}

+

+void mbox_serv_dequeue(struct mbox_serv_queue *const q)

+{

+	if (q != NULL) {

+		q->out_idx = (q->out_idx + 1U) % MBOX_SERV_QUEUE_SIZE;

+	}

+}

+

+void mbox_serv_isr(uint8_t msg_id)

+{

+	/* receive msg and put to rx queue */

+	uint8_t i;

+	uint8_t idx;

+	uint8_t event_id;

+	uint8_t offset;

+	uint32_t header;

+	const struct mbox_serv_registry *p_registry;

+	struct sys_event *p_event;

+	int8_t result = MBOX_SERV_OK;

+

+	/*

+	 * Interrupt at lastest message queue.

+	 * Get the first message queue on each entry

+	 */

+	offset = msg_id - MBOX_DATA_SIZE;

+

+	/* decode msg */

+	mbox_msg_rx(mbox_serv_serial, offset, &header);

+	event_id = (uint8_t)(header & MBOX_SERV_EVENT_ID_MASK);

+	idx = offset / MBOX_ENTRY_SIZE;

+

+	/* if event id is not in the range or can't find callback, ignore it */

+	if ((event_id < (uint8_t)SYS_EVENT_CNT) &&

+	        (idx < MBOX_SERV_ENTRY_CNT)) {

+		p_registry = &mbox_serv_registry_tb[event_id];

+

+		if (p_registry->q != NULL) {

+			/* if qeueu full, ignore the msg */

+			if (mbox_serv_q_is_full(p_registry->q) == false) {

+				p_event = &p_registry->q->event[p_registry->q->in_idx];

+

+				/* put to user event */

+				p_event->event_id = event_id;

+				p_event->cpu_serial = p_mbox_serv[idx].cpu_serial;

+

+				for (i = 0; i < MBOX_DATA_SIZE; i++) {

+					mbox_msg_rx(mbox_serv_serial,

+					            offset + 1U + i,

+					            &p_event->data.data[i]);

+				}

+

+				/* update queue status */

+				mbox_serv_enqueue(p_registry->q);

+

+				if (p_registry->cbk.status == MBOX_SERV_CBK_STATUS_ENABLE)

+					p_registry->cbk.fpCallback();

+

+			} else {

+				// TEE_MBOX_ERR("[\x1b[31m%s, %d\033[0m] MBOX_SERV_ERR_Q_FULL\n", __func__, __LINE__); //TODO

+				result = MBOX_SERV_ERR_Q_FULL;

+			}

+		} else {

+			// TEE_MBOX_ERR("[\x1b[31m%s, %d\033[0m] MBOX_SERV_ERR_NO_REGISTRY\n", __func__, __LINE__); //TODO

+			result = MBOX_SERV_ERR_NO_REGISTRY;

+		}

+	} else {

+		// TEE_MBOX_ERR("[\x1b[31m%s, %d\033[0m] MBOX_SERV_ERR_INVALID_ID\n", __func__, __LINE__); //TODO

+		result = MBOX_SERV_ERR_INVALID_ID;

+	}

+	/* clear header as ACK. Let this region free */

+	mbox_serv_ack(offset);

+

+	// workaround, TEMP USED

+	// if ((result == MBOX_SERV_OK) && (p_registry->cbk.status == MBOX_SERV_CBK_STATUS_ENABLE))

+	// {

+	// 	p_registry->cbk.fpCallback();

+	// }

+

+	(void)result;

+}

+void mbox_serv_init(void)

+{

+	uint8_t msg_id = -1;

+	int i;

+	enum mbox_regions region = MBOX_REGION_INVALID;

+

+	/* init table pointer */

+	mbox_serv_serial = CPU_SERIAL_CA53;

+	p_mbox_serv = mbox_serv_tb[mbox_serv_serial];

+

+	/* init event */

+	(void)memset(&mbox_serv_registry_tb, 0, sizeof(mbox_serv_registry_tb));

+

+	/* init mutex*/

+	(void)memset(&mbox_serv_mutex, 0, sizeof(mbox_serv_mutex));

+

+	/* init mbox driver and set callback function */

+	mbox_init(mbox_serv_serial, mbox_serv_isr);

+

+	for (i = 0; i < MBOX_SERV_ENTRY_CNT; i++) {

+		/* enable latest message interrupt on each entry */

+		// mbox_irq_enable(mbox_serv_convert_msg_id(i) + MBOX_DATA_SIZE);

+

+		/* set Magic to show initial done */

+		mbox_msg_tx(mbox_serv_serial,

+		            mbox_serv_convert_msg_id(i),

+		            MBOX_SERV_MAGIC_NUM);

+	}

+

+

+	mbox_serv_search_msg_id(CPU_SERIAL_HSM, CPU_SERIAL_CA53, &region, &msg_id);

+

+	mbox_set_ca53_intr_msg_id(mbox_serv_convert_msg_id(region) + MBOX_DATA_SIZE);

+}

+

+int8_t mbox_serv_register_event(uint8_t event_id,

+                                const struct mbox_serv_registry *registry)

+{

+	int8_t result = MBOX_SERV_ERR_FAIL;

+

+	if ((event_id < (uint8_t)SYS_EVENT_CNT) && (registry != NULL)) {

+		mbox_serv_registry_tb[event_id] = *registry;

+		result = 0;

+	}

+

+	return result;

+}

+

+int8_t mbox_serv_tx(const struct sys_event *event)

+{

+	int8_t result;

+	uint8_t msg_id = -1;

+	uint8_t i;

+	enum CPU_SERIAL dest;

+	enum CPU_SERIAL src;

+	enum mbox_regions region = MBOX_REGION_INVALID;

+	uint32_t header;

+

+	dest = event->cpu_serial;

+	src = mbox_serv_serial;

+	result = mbox_serv_search_msg_id(src, dest, &region, &msg_id);

+

+

+	if ((result == 0) && (event->event_id < (uint8_t)SYS_EVENT_CNT)) {

+		if (mbox_serv_get_res(region) == 0) {

+			if (mbox_serv_is_ack(dest, msg_id) == true) {

+

+				header = ((event->priority & 0xFFFF) << 16) | event->event_id;

+				/* Put header first */

+				mbox_msg_tx(dest,

+				            msg_id,

+				            header);

+				/*

+				 * Finally write the data to the latest message

+				 * queue. We use latest msg q to trigger target

+				 * MCU interrupt.

+				 */

+				for (i = 0; i < MBOX_DATA_SIZE; i++) {

+					mbox_msg_tx(dest,

+					            msg_id + i + 1U,

+					            event->data.data[i]);

+				}

+

+				result = wait_remote_ack(dest, msg_id);

+

+			} else {

+				result = MBOX_SERV_ERR_BUSY;

+			}

+

+			mbox_serv_release_res(region);

+		} else {

+			result = MBOX_SERV_ERR_NO_RES;

+		}

+	} else {

+		result = MBOX_SERV_ERR_INVALID_ID;

+	}

+

+	return result;

+}

+

+

+struct sys_event *mbox_serv_rx(struct mbox_serv_queue *const q)

+{

+	struct sys_event *event = NULL;

+

+	if (q != NULL) {

+		if (mbox_serv_q_is_empty(q) == false) {

+			event = &q->event[q->out_idx];

+		}

+	}

+

+	return event;

+}

+

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_serv.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_serv.h
new file mode 100644
index 0000000..cb81cf5
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_serv.h
@@ -0,0 +1,82 @@
+/*

+ * Copyright (c) 2018 MediaTek Inc.

+ *

+ * 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 _MBOX_SERV_H_

+#define _MBOX_SERV_H_

+

+#include <stdbool.h>

+#include <stdint.h>

+#include "system_event.h"

+

+#define MBOX_SERV_EVENT_ID_MASK	0xffUL

+

+#define MBOX_SERV_ENTRY_CNT     2U

+#define MBOX_SERV_QUEUE_SIZE    8U

+

+#define MBOX_SERV_JOB_IN_ACTIVE         (1)

+#define MBOX_SERV_OK                    (0)

+#define MBOX_SERV_ERR_FAIL              (-1)

+#define MBOX_SERV_ERR_BUSY              (-2)

+#define MBOX_SERV_ERR_Q_FULL            (-3)

+#define MBOX_SERV_ERR_NO_REGISTRY       (-4)

+#define MBOX_SERV_ERR_INVALID_ID        (-5)

+#define MBOX_SERV_ERR_NO_RES            (-6)

+#define MBOX_SERV_ERR_REMOTE_FAIL       (-7)

+#define MBOX_SERV_ERR_NO_JOB_CANCELED   (-8)

+

+#define MBOX_SERV_CBK_STATUS_IDLE    (0)

+#define MBOX_SERV_CBK_STATUS_ENABLE  (1)

+#define MBOX_SERV_CBK_STATUS_DISABLE (2)

+

+#define MBOX_SERV_FEEDBACK_INIT_VAL     (0x33)

+#define MBOX_SERV_FEEDBACK_MAGIC_NUM    (0xAD)

+#define MBOX_SERV_FEEDBACK_VERIFY_FAIL  (0xDC)

+

+struct mbox_callback

+{

+	uint32_t status;

+	void (*fpCallback)(void);

+};

+

+struct mbox_serv_queue {

+	uint8_t in_idx;

+	uint8_t out_idx;

+	struct sys_event event[MBOX_SERV_QUEUE_SIZE];

+};

+

+struct mbox_serv_registry {

+	uint32_t task_id;

+	uint32_t rx_mask;

+	struct mbox_callback cbk;

+	struct mbox_serv_queue *q;

+};

+

+void mbox_serv_init(void);

+int8_t mbox_serv_register_event(uint8_t event_id,

+				const struct mbox_serv_registry *registry);

+int8_t mbox_serv_tx(const struct sys_event *event);

+struct sys_event* mbox_serv_rx(struct mbox_serv_queue * const q);

+// void mbox_serv_set_region(int8_t lock_enable);

+void mbox_serv_dequeue(struct mbox_serv_queue *const q);

+

+#endif //_MBOX_SERV_H_

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_sw.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_sw.h
new file mode 100644
index 0000000..8365e7e
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/mbox_sw.h
@@ -0,0 +1,52 @@
+/*

+ * Copyright (c) 2018 MediaTek Inc.

+ *

+ * 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 __MBOX_SW_H__

+#define __MBOX_SW_H__

+

+struct mbox_reg {

+	uint32_t msg_pending;     //0x00

+	uint32_t msg_irq_en;      //0x04

+	uint32_t ns_domain_cfg;   //0x08

+	uint32_t reserved0;       //0x0c

+	uint32_t region_size;     //0x10

+	uint32_t region_err;      //0x14

+	uint32_t region_irq_en;   //0x18

+	uint32_t reserved1[57];   //0x20

+	uint32_t msg[32];         //0x100~0x180

+};

+

+struct erm_reg {

+	uint32_t pending;           //0x00

+	uint32_t irq_en;            //0x04

+	uint32_t irq_set;           //0x08

+	uint32_t reserved0;         //0x0c

+	uint32_t gdma_sram_tsel;    //0x10

+	uint32_t mcu_sram_tsel;     //0x14

+	uint32_t mcu_dcls_mask_h;   //0x18

+	uint32_t mcu_dcls_mask_l;   //0x1c

+	uint32_t eco1;              //0x20

+	uint32_t eco2;              //0x24

+};

+

+#endif //__MBOX_SW_H__
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/pta.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/pta.mk
new file mode 100644
index 0000000..f7716f7
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/pta.mk
@@ -0,0 +1,5 @@
+libdir := $(call my-dir)
+libname := hsm_mbox_if
+
+include $(BUILD_OPTEE_OS_LIB)
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/reg_op.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/reg_op.h
new file mode 100644
index 0000000..f8f9953
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/reg_op.h
@@ -0,0 +1,96 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2018. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+
+#ifndef _REG_OP_H_
+#define _REG_OP_H_
+
+#include <stdint.h>
+
+#define BIT(x) ((0x1ul) << ((uint32_t)(x)))
+
+#ifndef read8
+#define read8(addr) (*(volatile uint8_t*)(addr))
+#endif
+#ifndef write8
+#define write8(addr, val) ((*(volatile uint8_t*)(addr)) = (val))
+#endif
+
+#ifndef read16
+#define read16(addr) (*(volatile uint16_t*)(addr))
+#endif
+#ifndef write16
+#define write16(addr, val) ((*(volatile uint16_t*)(addr)) = (val))
+#endif
+
+#ifndef read32
+#define read32(addr) (*(volatile uint32_t*)(addr))
+#endif
+#ifndef write32
+#define write32(addr, val) ((*(volatile uint32_t*)(addr)) = (val))
+#endif
+
+
+
+
+#define setbits_le8(addr, set) \
+		write8((addr), (read8((addr)) | (uint8_t)(set)))
+
+#define clrbits_le8(addr, clear) \
+		write8((addr), (read8((addr)) & ~(uint8_t)(clear)))
+
+#define clrsetbits_le8(addr, clear, set) \
+		write8((addr), ((read8((addr)) & ~((uint8_t)(clear))) | (uint8_t)(set)))
+
+#define setbits_le16(addr, set) \
+		write16((addr), (read16((addr)) | (uint16_t)(set)))
+
+#define clrbits_le16(addr, clear) \
+		write16((addr), (read16((addr)) & ~(uint16_t)(clear)))
+
+#define clrsetbits_le16(addr, clear, set) \
+		write16((addr), ((read16((addr)) & ~((uint16_t)(clear))) | (uint16_t)(set)))
+
+#define setbits_le32(addr, set) \
+		write32((addr), (read32((addr)) | (uint32_t)(set)))
+
+#define clrbits_le32(addr, clear) \
+		write32((addr), (read32((addr)) & ~(uint32_t)(clear)))
+
+#define clrsetbits_le32(addr, clear, set) \
+		write32((addr), ((read32((addr)) & ~((uint32_t)(clear))) | (uint32_t)(set)))
+
+#endif /* _REG_OP_H */
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/share_memmap.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/share_memmap.h
new file mode 100644
index 0000000..4e94f39
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/share_memmap.h
@@ -0,0 +1,60 @@
+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+#ifndef __SHARE_MEMMAP_H__

+#define __SHARE_MEMMAP_H__

+

+#define HSM_BUF_END                   (0x44270000)

+

+#define JOB_PHYSICAL_BUF_LEN         0x2800 /*10KB*/

+#define JOB_PHYSICAL_BUF_BASE        (HSM_BUF_END - JOB_PHYSICAL_BUF_LEN)

+

+#define LOG_BUF_LEN                  0x4000 /*16KB*/

+#define LOG_BUF_BASE                 (JOB_PHYSICAL_BUF_BASE - LOG_BUF_LEN)

+

+#define KEY_IPC_PHYSICAL_BUF_LEN     0x2800 /*10KB*/

+#define KEY_IPC_PHYSICAL_BUF_BASE    (LOG_BUF_BASE - KEY_IPC_PHYSICAL_BUF_LEN)

+

+#define BUDDY_MEMPOOL_BUF_LEN        0x10000 /*64KB*/

+#define BUDDY_MEMPOOL_BUF_BASE       (KEY_IPC_PHYSICAL_BUF_BASE - BUDDY_MEMPOOL_BUF_LEN)

+

+#define TEE_BUDDY_MEMPOOL_BUF_LEN    0x10000 /*64KB*/

+#define TEE_BUDDY_MEMPOOL_BUF_BASE   (BUDDY_MEMPOOL_BUF_BASE - TEE_BUDDY_MEMPOOL_BUF_LEN)

+

+#define HSM_ALL_IO_BUF_LEN           0x4000 /*16KB*/

+#define HSM_ALL_IO_BUF_BASE          (TEE_BUDDY_MEMPOOL_BUF_BASE - HSM_ALL_IO_BUF_LEN)

+

+#endif //__SHARE_MEMMAP_H__
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/sub.mk
new file mode 100644
index 0000000..2197b24
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/sub.mk
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: BSD-2-Clause
+srcs-y := \
+	hsm_mbox_if.c \
+	hsm_if_impl.c \
+	mbox_drv.c \
+	mbox_serv.c \
+	buddy.c \
+	sync_obj.c \
+	hsm_dump.c
+
+incdirs-lib-y = \
+    include/ \
+    ../../../../optee_services/secure_key_services/ta/include/
+
+$(call add-pta-src, hsm_mbox_if.c)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/sync_obj.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/sync_obj.c
new file mode 100644
index 0000000..5d73d1b
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/sync_obj.c
@@ -0,0 +1,204 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein is
+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+ * the prior written permission of MediaTek inc. and/or its licensors, any
+ * reproduction, modification, use or disclosure of MediaTek Software, and
+ * information contained herein, in whole or in part, shall be strictly
+ * prohibited.
+ *
+ * MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek
+ * Software") have been modified by MediaTek Inc. All revisions are subject to
+ * any receiver's applicable license agreements with MediaTek Inc.
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <kernel/delay.h>
+#include <tee/cache.h>
+#include "buddy.h"
+#include "address.h"
+#include "sync_obj.h"
+
+/* map physical address from CA53 to HSM */
+int hsm_addr_remap(uint32_t phyaddr, uint32_t *p_remaped)
+{
+	uint32_t hbit = (phyaddr & 0xf0000000) >> 28;
+	int ret = 0;
+
+	switch (hbit)
+	{
+	case 0x0:
+		*p_remaped = phyaddr | 0x90000000;
+		break;
+	case 0x1:
+		*p_remaped = phyaddr | 0xf0000000;
+		break;
+	case 0x2:
+	case 0x3:
+		ret = -1;
+		break;
+	case 0x4:
+	case 0x5:
+	case 0x6:
+	case 0x7:
+	case 0x8:
+	case 0x9:
+	case 0xa:
+	case 0xb:
+		*p_remaped = phyaddr - 0x30000000;
+		break;
+	case 0xc:
+	case 0xd:
+	case 0xe:
+	case 0xf:
+		*p_remaped = phyaddr - 0x20000000;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+int allocate_sync_handle(sync_handle *handle)
+{
+	uint32_t *phsm;
+	addr_t *p = handle;
+	int ret = buddy_malloc(sizeof(sync_object), p);
+	if (ret != BUDDY_OK) {
+		EMSG("[\x1b[31m%s\033[0m][%d] buddy_malloc fail \n", __FUNCTION__, __LINE__);
+		return -1;
+	}
+
+	memset(p->va, 0, sizeof(sync_object));
+	hsm_addr_remap(p->pa, &phsm);
+	p->ha = phsm;
+
+	// IMSG("[\x1b[31m%s\033[0m][%d] p->pa : 0x%x\n", __FUNCTION__, __LINE__, p->pa);
+	// IMSG("[\x1b[31m%s\033[0m][%d] p->va : 0x%x\n", __FUNCTION__, __LINE__, p->va);
+	// IMSG("[\x1b[31m%s\033[0m][%d] p->ha : 0x%x\n", __FUNCTION__, __LINE__, p->ha);
+
+	return 0;
+}
+
+int release_sync_handle(sync_handle *handle)
+{
+	buddy_free(handle);
+}
+
+void wait_remote_sync_done(sync_handle *handle)
+{
+	sync_object *psyncobj;
+	addr_t *p = handle;
+
+	psyncobj = (sync_object *)p->va;
+
+	while (1) {
+		if (cache_operation(TEE_CACHECLEAN, psyncobj, sizeof(sync_object)) != TEE_SUCCESS)
+			EMSG("\x1b[31m == CACHE FAIL!! == \033[0m\n");
+
+		if (psyncobj->done == 1)
+			break;
+
+		mdelay(1);
+	}
+}
+
+void *get_hsm_address(sync_handle *p)
+{
+	return p->ha;
+}
+
+int get_hsm_return_value(sync_handle *p)
+{
+	sync_object *psyncobj;
+
+	psyncobj = (sync_object *)p->va;
+	if (cache_operation(TEE_CACHECLEAN, psyncobj, sizeof(sync_object)) != TEE_SUCCESS)
+		EMSG("\x1b[31m == CACHE FAIL!! == \033[0m\n");
+
+	return psyncobj->status;
+}
+
+void cclean_and_memcopy(void *dest, addr_t *src, size_t n)
+{
+	uint8_t *vsrc;
+	vsrc = (uint8_t *)src->va;
+	if (cache_operation(TEE_CACHECLEAN, vsrc, n) != TEE_SUCCESS)
+		EMSG("\x1b[31m == CACHE FAIL!! == \033[0m\n");
+
+	memcpy(dest, vsrc, n);
+}
+
+void memput_and_cclean(addr_t *dest, void *src, size_t n)
+{
+	uint8_t *vdst;
+	vdst = (uint8_t *)dest->va;
+
+	memcpy(vdst, src, n);
+
+	if (cache_operation(TEE_CACHECLEAN, vdst, n) != TEE_SUCCESS)
+		EMSG("\x1b[31m == CACHE FAIL!! == \033[0m\n");
+}
+
+
+int physical_malloc(uint32_t size, addr_t *addr)
+{
+	addr_t tmp = {0};
+
+	if (addr == NULL) {
+		goto fail;
+	}
+
+	if (buddy_malloc(size, &tmp) != BUDDY_OK) {
+		goto fail;
+	}
+
+	if (hsm_addr_remap(tmp.pa, &tmp.ha) != 0) {
+		goto fail;
+	}
+
+ok:
+	memcpy(addr, &tmp, sizeof(addr_t));
+	return 0;
+fail:
+	if (tmp.va != NULL) {
+		buddy_free(&tmp);
+	}
+	return -1;
+}
+
+
+void physical_free(addr_t *addr)
+{
+	if (addr == NULL) {
+		return;
+	}
+	buddy_free(addr);
+}
\ No newline at end of file
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/sync_obj.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/sync_obj.h
new file mode 100644
index 0000000..1e2bfbf
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/mbox/sync_obj.h
@@ -0,0 +1,68 @@
+/* Copyright Statement:

+ *

+ * This software/firmware and related documentation ("MediaTek Software") are

+ * protected under relevant copyright laws. The information contained herein is

+ * confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+ * the prior written permission of MediaTek inc. and/or its licensors, any

+ * reproduction, modification, use or disclosure of MediaTek Software, and

+ * information contained herein, in whole or in part, shall be strictly

+ * prohibited.

+ *

+ * MediaTek Inc. (C) 2020. All rights reserved.

+ *

+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+ * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+ * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+ * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+ * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+ * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+ * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+ * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+ * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+ * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+ * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+ * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+ * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.

+ *

+ * The following software/firmware and/or related documentation ("MediaTek

+ * Software") have been modified by MediaTek Inc. All revisions are subject to

+ * any receiver's applicable license agreements with MediaTek Inc.

+ */

+#ifndef _SYNC_OBJ_H_

+#define _SYNC_OBJ_H_

+

+#include "address.h"

+

+typedef struct sync_object_t

+{

+	uint32_t done;

+	uint32_t status;

+} sync_object;

+

+typedef addr_t sync_handle;

+

+/*

+ * sync obj APIs

+ */

+int allocate_sync_handle(sync_handle *handle);

+int release_sync_handle(sync_handle *handle);

+void wait_remote_sync_done(sync_handle *handle);

+void *get_hsm_address(sync_handle *p);

+int get_hsm_return_value(sync_handle *p);

+

+/*

+ * memory opreation APIs

+ */

+int hsm_addr_remap(uint32_t phyaddr, uint32_t *p_remaped);

+void cclean_and_memcopy(void *dest, addr_t *src, size_t n);

+void memput_and_cclean(addr_t *dest, void *src, size_t n);

+int physical_malloc(uint32_t size, addr_t *addr);

+void physical_free(addr_t *addr);

+

+#endif /* end of include guard: _SYNC_OBJ_H_ */

diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/pta.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/pta.mk
new file mode 100644
index 0000000..d45f9bf
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/app/pta.mk
@@ -0,0 +1 @@
+include $(call all-pta-mk-under, $(call my-dir))
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/common/pta.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/pta.mk
new file mode 100644
index 0000000..d45f9bf
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/common/pta.mk
@@ -0,0 +1 @@
+include $(call all-pta-mk-under, $(call my-dir))
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta.mk
new file mode 100644
index 0000000..d45f9bf
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta.mk
@@ -0,0 +1 @@
+include $(call all-pta-mk-under, $(call my-dir))
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/include/pta_dapc.h b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/include/pta_dapc.h
new file mode 100644
index 0000000..c2b188c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/include/pta_dapc.h
@@ -0,0 +1,46 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+#ifndef __TEE_PTA_TTDAPC_H__
+#define __TEE_PTA_TTDAPC_H__
+
+#define PTA_DAPC_UUID     {0x2603779b, 0xb2a6, 0x4f7e, {0x87, 0x83, 0x62, 0xab, 0x11, 0xb3, 0x83, 0xfd}}
+
+/* Command For DAPC TA */
+#define PTA_CMD_DAPC_TEST             0
+#define PTA_CMD_DAPC_MASTER_TEST      1
+#define PTA_CMD_DAPC_SLAVE_APC_TEST   2
+
+#endif  /* __TEE_PTA_TTDAPC_H__ */
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/pta.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/pta.mk
new file mode 100644
index 0000000..5fb69ba
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/pta.mk
@@ -0,0 +1,5 @@
+libdir := $(call my-dir)
+libname := pta_dapc
+
+include $(BUILD_OPTEE_OS_LIB)
+
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/pta_dapc.c b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/pta_dapc.c
new file mode 100644
index 0000000..a0d6685
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/pta_dapc.c
@@ -0,0 +1,103 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2020. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver's
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#include <pta_dapc.h>
+#include <dapc_public.h>
+//#include <initcall.h>
+#include <io.h>
+#include <kernel/pseudo_ta.h>
+//#include <kernel/interrupt.h>
+//#include <mm/core_memprot.h>
+//#include <mm/core_mmu.h>
+#include <tee_api_defines.h>
+
+/* Static Function */
+static TEE_Result invoke_command(void *pSessionContext __unused,
+				 uint32_t nCommandID, uint32_t nParamTypes,
+				 TEE_Param pParams[TEE_NUM_PARAMS])
+{
+	uint32_t p1, p2, p3;
+	int ret;
+
+	EMSG("DEVAPC nCommandID(%x)\n", nCommandID);
+
+	switch (nCommandID) {
+	case PTA_CMD_DAPC_TEST:
+		EMSG("DEVAPC test command\n");
+
+		if (TEE_PARAM_TYPE_GET(nParamTypes, 0) != TEE_PARAM_TYPE_VALUE_INOUT)
+			return TEE_ERROR_BAD_PARAMETERS;
+
+		p1 = pParams[0].value.a;
+		p2 = pParams[0].value.b;
+		EMSG("input value p1: %u, p2: %u\n", p1, p2);
+
+		return TEE_SUCCESS;
+
+	case PTA_CMD_DAPC_MASTER_TEST:
+		EMSG("DEVAPC try to set master transaction...\n");
+
+		p1 = pParams[0].value.a;
+		p2 = pParams[1].value.a;
+		EMSG("input value p1: %u, p2: %u\n", p1, p2);
+
+        set_master_transaction(p1 ,p2);
+		dump_devapc();
+
+		return TEE_SUCCESS;
+
+	case PTA_CMD_DAPC_SLAVE_APC_TEST:
+		EMSG("DEVAPC try to set module apc...\n");
+
+		p1 = pParams[0].value.a;
+		p2 = pParams[1].value.a;
+		p3 = pParams[2].value.a;
+		EMSG("input value p1: %u, p2: %u, p3: %u\n", p1, p2, p3);
+
+		set_module_apc(p1, p2, p3);
+		dump_devapc();
+
+		return TEE_SUCCESS;
+	default:
+		break;
+	}
+
+	return TEE_ERROR_NOT_IMPLEMENTED;
+}
+
+pseudo_ta_register(.uuid = PTA_DAPC_UUID, .name = "pta_dapc",
+		   .flags = PTA_DEFAULT_FLAGS,
+		   .invoke_command_entry_point = invoke_command);
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/sub.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/sub.mk
new file mode 100644
index 0000000..713c26c
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/mt2712/pta_dapc/sub.mk
@@ -0,0 +1,11 @@
+srcs-y := \
+          pta_dapc.c
+
+incdirs-lib-y = \
+    include/ \
+    ../../../mt2712/dapc/include
+
+libdirs += $(call my-dir)/../../../mt2712/dapc
+libnames += dapc
+
+$(call add-pta-src, pta_dapc.c)
diff --git a/src/bsp/trustzone/optee/source/mt2xxx/pta/pta.mk b/src/bsp/trustzone/optee/source/mt2xxx/pta/pta.mk
new file mode 100644
index 0000000..fe62cda
--- /dev/null
+++ b/src/bsp/trustzone/optee/source/mt2xxx/pta/pta.mk
@@ -0,0 +1,45 @@
+define my-dir
+$(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
+endef
+
+define all-pta-mk-under
+$(wildcard $1/*/pta.mk)
+endef
+
+define _add-prebuilt-libname
+libdirs += $(call my-dir)
+libnames += $1
+endef
+
+define add-prebuilt-libname
+$(eval $(call _add-prebuilt-libname, $1))
+endef
+
+define add-pta-src
+$(eval LDADD := $(LDADD) $(out-dir)/../..$(subst ..,,$(libdir)/$(strip $(subst .c,.o,$1))))
+endef
+
+# $1: libname
+# $2: object file in libname
+define _add-libname-pta-obj
+my-path := $(call my-dir)
+$(out-dir)$$(subst ..,,$$(my-path))/$$(strip $2): $(call my-dir)/lib$$(strip $1).a
+	echo $$@
+	$(q)mkdir -p $$(dir $$@)
+	$(q)cd $$(dir $$@); $(AR$(sm)) x $$(abspath $$<) $2
+
+libdeps += $(out-dir)$$(subst ..,,$$(my-path))/$$(strip $2)
+LDADD := $(LDADD) $(out-dir)$$(subst ..,,$$(my-path))/$$(strip $2)
+endef
+
+define add-libname-pta-obj
+$(eval $(call _add-libname-pta-obj,$1,$2))
+endef
+
+base-prefix = core-lib/
+BUILD_OPTEE_OS_LIB := mk/lib.mk
+
+#include $(call all-pta-mk-under, $(call my-dir))
+include $(call my-dir)/common/pta.mk
+-include $(call my-dir)/$(PLATFORM_FLAVOR)/pta.mk
+