diff --git a/include/linux/ote_protocol.h b/include/linux/ote_protocol.h new file mode 100644 index 000000000000..ef71ac97810e --- /dev/null +++ b/include/linux/ote_protocol.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013-2018 NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __OTE_PROTOCOL_H__ +#define __OTE_PROTOCOL_H__ + +int tegra_set_vpr_params(void *vpr_base, size_t vpr_size); + +void trusty_restore_keyslots(void); +void tlk_restore_keyslots(void); + +int te_is_secos_dev_enabled(void); + +#endif diff --git a/include/uapi/misc/ote_protocol.h b/include/uapi/misc/ote_protocol.h new file mode 100644 index 000000000000..2a72346441f9 --- /dev/null +++ b/include/uapi/misc/ote_protocol.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013-2019 NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __UAPI_TLK_OTE_PROTOCOL_H__ +#define __UAPI_TLK_OTE_PROTOCOL_H__ + +#include +#include + +#define TE_IOCTL_MAGIC_NUMBER ('t') +#define TE_IOCTL_OPEN_CLIENT_SESSION \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x10, union te_cmd) +#define TE_IOCTL_CLOSE_CLIENT_SESSION \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x11, union te_cmd) +#define TE_IOCTL_LAUNCH_OPERATION \ + _IOWR(TE_IOCTL_MAGIC_NUMBER, 0x14, union te_cmd) + +/* secure storage ioctl */ +#define TE_IOCTL_SS_CMD \ + _IOR(TE_IOCTL_MAGIC_NUMBER, 0x30, int) + +#define TE_IOCTL_SS_CMD_GET_NEW_REQ 1 +#define TE_IOCTL_SS_CMD_REQ_COMPLETE 2 + +#define TE_IOCTL_MIN_NR _IOC_NR(TE_IOCTL_OPEN_CLIENT_SESSION) +#define TE_IOCTL_MAX_NR _IOC_NR(TE_IOCTL_SS_CMD) + +struct te_service_id { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_and_node[8]; +}; + +struct te_operation { + uint32_t command; + uint32_t status; + uint64_t list_head; + uint64_t list_tail; + uint32_t list_count; + uint32_t interface_side; +}; + +/* + * OpenSession + */ +struct te_opensession { + struct te_service_id dest_uuid; + struct te_operation operation; + uint64_t answer; +}; + +/* + * CloseSession + */ +struct te_closesession { + uint32_t session_id; + uint64_t answer; +}; + +/* + * LaunchOperation + */ +struct te_launchop { + uint32_t session_id; + struct te_operation operation; + uint64_t answer; +}; + +union te_cmd { + struct te_opensession opensession; + struct te_closesession closesession; + struct te_launchop launchop; +}; + +#endif \ No newline at end of file diff --git a/security/Kconfig b/security/Kconfig index 28e685f53bd1..5364f13b907d 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -228,6 +228,8 @@ source "security/ipe/Kconfig" source "security/integrity/Kconfig" +source "security/tlk_driver/Kconfig" + choice prompt "First legacy 'major LSM' to be initialized" default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX diff --git a/security/Makefile b/security/Makefile index cc0982214b84..25363ea0fffe 100644 --- a/security/Makefile +++ b/security/Makefile @@ -29,3 +29,5 @@ obj-$(CONFIG_SECURITY_IPE) += ipe/ # Object integrity file lists obj-$(CONFIG_INTEGRITY) += integrity/ + +obj-$(CONFIG_TRUSTED_LITTLE_KERNEL) += tlk_driver/ diff --git a/security/tlk_driver/Kconfig b/security/tlk_driver/Kconfig new file mode 100644 index 000000000000..76a6fb01e231 --- /dev/null +++ b/security/tlk_driver/Kconfig @@ -0,0 +1,7 @@ +config TRUSTED_LITTLE_KERNEL + bool "Enable Open Trusted Execution driver" + + help + This option adds kernel support for communication with the + Trusted LK secure OS monitor/runtime support. + If you are unsure how to answer this question, answer N. diff --git a/security/tlk_driver/Makefile b/security/tlk_driver/Makefile new file mode 100644 index 000000000000..f52f36ab270d --- /dev/null +++ b/security/tlk_driver/Makefile @@ -0,0 +1,27 @@ +# +# Copyright (c) 2013-2016, NVIDIA Corporation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +subdir-ccflags-y += -Werror +tlk_driver-objs += ote_device.o +tlk_driver-objs += ote_comms.o +tlk_driver-objs += ote_fs.o +tlk_driver-objs += ote_asm.o +tlk_driver-objs += ote_log.o +tlk_driver-objs += ote_memory.o + +obj-$(CONFIG_TRUSTED_LITTLE_KERNEL) += tlk_driver.o diff --git a/security/tlk_driver/ote_asm.S b/security/tlk_driver/ote_asm.S new file mode 100644 index 000000000000..2f91209ed9a5 --- /dev/null +++ b/security/tlk_driver/ote_asm.S @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014-2016, NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include + +#ifdef CONFIG_ARM64 + +/* uint32_t tlk_generic_smc(uint32_t arg0, uint32_t arg1, uint32_t arg2) */ +SYM_FUNC_START(_tlk_generic_smc) + smc #0 + ret +SYM_FUNC_END(_tlk_generic_smc) + +SYM_FUNC_START(_tlk_get_mair) + mrs x0, mair_el1 + ret +SYM_FUNC_END(_tlk_get_mair) + +#else + + .arch_extension sec +SYM_FUNC_START(_tlk_generic_smc) + smc #0 + mov pc, lr +SYM_FUNC_END(_tlk_generic_smc) + +SYM_FUNC_START(_tlk_get_mair) + mrc p15, 0, r0, c10, c2, 0 + mrc p15, 0, r1, c10, c2, 1 + mov pc, lr +SYM_FUNC_END(_tlk_get_mair) + +#endif diff --git a/security/tlk_driver/ote_comms.c b/security/tlk_driver/ote_comms.c new file mode 100644 index 000000000000..ab2ff3e4bed5 --- /dev/null +++ b/security/tlk_driver/ote_comms.c @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2012-2019 NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ote_protocol.h" + +bool verbose_smc; +core_param(verbose_smc, verbose_smc, bool, 0644); + +#define SET_RESULT(req, r, ro) { req->result = r; req->result_origin = ro; } + +static struct te_session *te_get_session(struct tlk_context *context, + uint32_t session_id) +{ + struct te_session *session, *tmp_session; + + list_for_each_entry_safe(session, tmp_session, + &context->session_list, list) { + if (session->session_id == session_id) + return session; + } + + return NULL; +} + +struct tlk_smc_work_args { + uint32_t arg0; + uintptr_t arg1; + uint32_t arg2; +}; + +static long tlk_generic_smc_on_cpu0(void *args) +{ + struct tlk_smc_work_args *work; + int callback_status = 0; + uint32_t retval; + + work = (struct tlk_smc_work_args *)args; + retval = _tlk_generic_smc(work->arg0, work->arg1, work->arg2); + + while (retval == TE_ERROR_PREEMPT_BY_IRQ || + retval == TE_ERROR_PREEMPT_BY_FS) { + if (retval == TE_ERROR_PREEMPT_BY_FS) + callback_status = tlk_ss_op(); + retval = _tlk_generic_smc(TE_SMC_RESTART, callback_status, 0); + } + + /* Print TLK logs if any */ + ote_print_logs(); + + return retval; +} + +/* + * This routine is called both from normal threads and worker threads. + * The worker threads have PF_NO_SETAFFINITY set, so any calls to + * sched_setaffinity will fail. + * + * If it's a worker thread, always schedule work on CPU0. + * If it's not a worker thread, try to switch to CPU0. If this fails, + * then schedule work on CPU0. + */ +uint32_t tlk_send_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2) +{ + struct tlk_smc_work_args work_args; + + work_args.arg0 = arg0; + work_args.arg1 = arg1; + work_args.arg2 = arg2; + + return work_on_cpu(0, + tlk_generic_smc_on_cpu0, &work_args); +} + +/* + * Do an SMC call + */ +static void do_smc(struct te_request *request, struct tlk_device *dev) +{ + uint32_t smc_args; + uint32_t smc_params = 0; + uint32_t retval = 0; + + smc_args = (uintptr_t)request - (uintptr_t)dev->req_addr; + if (request->params) { + smc_params = + (uintptr_t)request->params - (uintptr_t)dev->req_addr; + } + + retval = tlk_send_smc(request->type, smc_args, smc_params); + + /** + * Check for return code from TLK kernel and propagate to NS userspace + * + * Under certain situations, TLK kernel may return an error code + * _without_ updating the shared request buffer. + * + * This could give a false impression to the user-app about status of + * the request (if default value of request->result is OTE_SUCCESS). + * + * Propagate the error code to NS user-app in case of such scenario. + */ + if ((retval != OTE_SUCCESS) && (request->result == OTE_SUCCESS)) { + pr_err("%s: overriding result_origin field\n", __func__); + request->result = retval; + request->result_origin = OTE_RESULT_ORIGIN_KERNEL; + } +} + +void tlk_restore_keyslots(void) +{ + uint32_t retval; + + if (!te_is_secos_dev_enabled()) + return; + + /* Share the same lock used when request is send from user side */ + mutex_lock(&smc_lock); + + retval = tlk_send_smc(TE_SMC_TA_EVENT, TA_EVENT_RESTORE_KEYS, 0); + + mutex_unlock(&smc_lock); + + if (retval != OTE_SUCCESS) { + pr_err("%s: smc failed err (0x%x)\n", __func__, retval); + } +} +EXPORT_SYMBOL(tlk_restore_keyslots); + +/* + * Open session SMC (supporting client-based te_open_session() calls) + */ +void te_open_session(struct te_opensession *cmd, + struct te_request *request, + struct tlk_context *context) +{ + struct te_session *session; + int ret; + + session = kzalloc(sizeof(struct te_session), GFP_KERNEL); + if (!session) { + SET_RESULT(request, OTE_ERROR_OUT_OF_MEMORY, + OTE_RESULT_ORIGIN_API); + return; + } + + INIT_LIST_HEAD(&session->list); + INIT_LIST_HEAD(&session->temp_shmem_list); + INIT_LIST_HEAD(&session->inactive_persist_shmem_list); + INIT_LIST_HEAD(&session->persist_shmem_list); + + request->type = TE_SMC_OPEN_SESSION; + + ret = te_prep_mem_buffers(request, session); + if (ret != OTE_SUCCESS) { + pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n", + __func__, ret); + SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API); + kfree(session); + return; + } + + memcpy(&request->dest_uuid, + &cmd->dest_uuid, + sizeof(struct te_service_id)); + + pr_debug("OPEN_CLIENT_SESSION: 0x%x 0x%x 0x%x 0x%x\n", + request->dest_uuid[0], + request->dest_uuid[1], + request->dest_uuid[2], + request->dest_uuid[3]); + + do_smc(request, context->dev); + + if (request->result) + goto error; + + /* release temporary mem buffers */ + te_release_mem_buffers(&session->temp_shmem_list); + + /* move persistent mem buffers to active list */ + te_activate_persist_mem_buffers(session); + + /* save off session_id and add to list */ + session->session_id = request->session_id; + list_add_tail(&session->list, &context->session_list); + + return; +error: + /* release buffers allocated in te_prep_mem_buffers */ + te_release_mem_buffers(&session->temp_shmem_list); + te_release_mem_buffers(&session->inactive_persist_shmem_list); + + kfree(session); +} + +/* + * Close session SMC (supporting client-based te_close_session() calls) + */ +void te_close_session(struct te_closesession *cmd, + struct te_request *request, + struct tlk_context *context) +{ + struct te_session *session; + + request->session_id = cmd->session_id; + request->type = TE_SMC_CLOSE_SESSION; + + do_smc(request, context->dev); + if (request->result) + pr_info("%s: error closing session: 0x%08x\n", + __func__, request->result); + + session = te_get_session(context, cmd->session_id); + if (!session) { + pr_info("%s: session_id not found: 0x%x\n", + __func__, cmd->session_id); + return; + } + + /* free session state */ + te_release_mem_buffers(&session->persist_shmem_list); + list_del(&session->list); + kfree(session); +} + +/* + * Launch operation SMC (supporting client-based te_launch_operation() calls) + */ +void te_launch_operation(struct te_launchop *cmd, + struct te_request *request, + struct tlk_context *context) +{ + struct te_session *session; + int ret; + + session = te_get_session(context, cmd->session_id); + if (!session) { + pr_info("%s: session_id not found: 0x%x\n", + __func__, cmd->session_id); + SET_RESULT(request, OTE_ERROR_BAD_PARAMETERS, + OTE_RESULT_ORIGIN_API); + return; + } + + request->session_id = cmd->session_id; + request->command_id = cmd->operation.command; + request->type = TE_SMC_LAUNCH_OPERATION; + + ret = te_prep_mem_buffers(request, session); + if (ret != OTE_SUCCESS) { + pr_err("%s: te_prep_mem_buffers failed err (0x%x)\n", + __func__, ret); + SET_RESULT(request, ret, OTE_RESULT_ORIGIN_API); + return; + } + + do_smc(request, context->dev); + + if (request->result) + goto error; + + /* move persistent mem buffers to active list */ + te_activate_persist_mem_buffers(session); + + /* release temporary mem buffers */ + te_release_mem_buffers(&session->temp_shmem_list); + + return; + +error: + /* release buffers allocated in te_prep_mem_buffers */ + te_release_mem_buffers(&session->temp_shmem_list); + te_release_mem_buffers(&session->inactive_persist_shmem_list); +} + +/* + * Command to open a session with the trusted app. + * This API should only be called from the kernel space. + * Takes UUID of the TA and size as argument + * Returns Session ID if success or ERR when failure + */ +int te_open_trusted_session_tlk(u32 *ta_uuid, u32 uuid_size, + u32 *session_id) +{ + struct te_request *request; + struct te_cmd_req_desc *cmd_desc = NULL; + + mutex_lock(&smc_lock); + + /* Open & submit the work to SMC */ + cmd_desc = te_get_free_cmd_desc(&tlk_dev); + + if (!cmd_desc) { + pr_err("%s: failed to get cmd_desc\n", __func__); + goto error; + } + + request = cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request)); + request->type = TE_SMC_OPEN_SESSION; + + if (uuid_size != sizeof(request->dest_uuid)) { + pr_err("%s: Invalid size sent!\n", __func__); + goto error; + } + + if (ta_uuid == NULL || session_id == NULL) { + pr_err("%s: Null parameters sent!\n", __func__); + goto error; + } + + memcpy(request->dest_uuid, ta_uuid, sizeof(*ta_uuid)*4); + + do_smc(request, &tlk_dev); + + if (request->result) { + pr_err("%s: error opening session: 0x%08x, 0x%08x\n", + __func__, request->result, request->result_origin); + goto error; + } + + *session_id = request->session_id; + if (cmd_desc) + te_put_used_cmd_desc(&tlk_dev, cmd_desc); + + mutex_unlock(&smc_lock); + return OTE_SUCCESS; + +error: + if (cmd_desc) + te_put_used_cmd_desc(&tlk_dev, cmd_desc); + + mutex_unlock(&smc_lock); + return OTE_ERROR_GENERIC; +} +EXPORT_SYMBOL(te_open_trusted_session_tlk); + +/* + * Command to close session opened with the trusted app. + * This API should only be called from the kernel space. + * Takes session Id and UUID of the TA as arguments + */ +void te_close_trusted_session_tlk(u32 session_id, u32 *ta_uuid, + u32 uuid_size) +{ + struct te_request *request; + struct te_cmd_req_desc *cmd_desc = NULL; + + mutex_lock(&smc_lock); + + /* Open & submit the work to SMC */ + cmd_desc = te_get_free_cmd_desc(&tlk_dev); + + if (!cmd_desc) { + pr_err("%s: failed to get cmd_desc\n", __func__); + goto error; + } + + /* Close the session */ + request = cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request)); + request->type = TE_SMC_CLOSE_SESSION; + request->session_id = session_id; + + if (uuid_size != sizeof(request->dest_uuid)) { + pr_err("%s: Invalid size sent!\n", __func__); + goto error; + } + + memcpy(request->dest_uuid, ta_uuid, sizeof(*ta_uuid)*4); + + do_smc(request, &tlk_dev); + + if (request->result) { + pr_err("%s: error closing session: 0x%08x, 0x%08x\n", + __func__, request->result, request->result_origin); + goto error; + } + +error: + if (cmd_desc) + te_put_used_cmd_desc(&tlk_dev, cmd_desc); + mutex_unlock(&smc_lock); +} +EXPORT_SYMBOL(te_close_trusted_session_tlk); + +/* + * Command to launch operations from the linux kernel to + * the trusted app. + * This API should be called only from the kernel space. + * The pointer to the buffer from the kernel, length of thus buffer, + * session Id, UUID of the TA and the command requested from the + * TA should be passed as arguments + * Returns SUCCESS or FAILURE + */ +int te_launch_trusted_oper_tlk(u8 *buf_ptr, u32 buf_len, u32 session_id, + u32 *ta_uuid, u32 ta_cmd, u32 uuid_size) +{ + u32 i; + struct te_request *request; + struct te_oper_param user_param; + struct te_oper_param *param_array; + struct te_oper_param *params = NULL; + struct te_cmd_req_desc *cmd_desc = NULL; + u32 no_of_params = 1; + + mutex_lock(&smc_lock); + + /* Open & submit the work to SMC */ + cmd_desc = te_get_free_cmd_desc(&tlk_dev); + params = te_get_free_params(&tlk_dev, no_of_params); + + if (!cmd_desc || !params) { + pr_err("%s: failed to get cmd_desc/params\n", __func__); + goto error; + } + + /* launch operation */ + request = cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request)); + request->params = (uintptr_t)params; + request->params_size = no_of_params; + request->session_id = session_id; + request->command_id = ta_cmd; + request->type = TE_SMC_LAUNCH_OPERATION; + user_param.index = 0; + user_param.u.Mem.len = buf_len; + user_param.type = TE_PARAM_TYPE_MEM_RW; + user_param.u.Mem.type = TE_MEM_TYPE_NS_KERNEL; + user_param.u.Mem.base = (uint64_t)(uintptr_t)buf_ptr; + + if (uuid_size != sizeof(request->dest_uuid)) { + pr_err("%s: Invalid size sent\n", __func__); + goto error; + } + + memcpy(request->dest_uuid, ta_uuid, sizeof(*ta_uuid)*4); + + param_array = (struct te_oper_param *)(uintptr_t)request->params; + + for (i = 0; i < no_of_params; i++) + memcpy(param_array + i, &user_param, + sizeof(struct te_oper_param)); + + do_smc(request, &tlk_dev); + + if (request->result) { + pr_err("%s: error launching session: 0x%08x, 0x%08x\n", + __func__, request->result, request->result_origin); + goto error; + } else { + if (cmd_desc) + te_put_used_cmd_desc(&tlk_dev, cmd_desc); + + if (params) + te_put_free_params(&tlk_dev, params, no_of_params); + + mutex_unlock(&smc_lock); + return OTE_SUCCESS; + } +error: + if (cmd_desc) + te_put_used_cmd_desc(&tlk_dev, cmd_desc); + + if (params) + te_put_free_params(&tlk_dev, params, no_of_params); + + mutex_unlock(&smc_lock); + return OTE_ERROR_GENERIC; +} +EXPORT_SYMBOL(te_launch_trusted_oper_tlk); diff --git a/security/tlk_driver/ote_device.c b/security/tlk_driver/ote_device.c new file mode 100644 index 000000000000..d740142e4d8e --- /dev/null +++ b/security/tlk_driver/ote_device.c @@ -0,0 +1,714 @@ +/* + * Copyright (c) 2013-2021 NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ote_protocol.h" + +#define SET_ANSWER(a, r, ro) { a.result = r; a.result_origin = ro; } + +struct tlk_device tlk_dev; +DEFINE_MUTEX(smc_lock); + +static int te_create_free_cmd_list(struct tlk_device *dev) +{ + int cmd_desc_count, ret = 0; + struct te_cmd_req_desc *req_desc = NULL, *tmp_req_desc = NULL; + int bitmap_size; + int req_buf_size; + void *req_buf; + + /* + * TLK can map in the shared req/param buffers and do_smc + * only needs to send the offsets within each (with cache coherency + * being maintained by HW through an NS mapping). + */ + req_buf_size = (TE_TOTAL_PAGE_COUNT * PAGE_SIZE); + req_buf = kmalloc(req_buf_size, GFP_KERNEL); + if (!req_buf) { + pr_err("%s: Failed to allocate param buffer!\n", __func__); + ret = -ENOMEM; + goto error; + } + + /* requests in 1st page, params in 2nd, pagelists in 3rd and 4th pages */ + dev->req_addr = (struct te_request *) + (req_buf + (0 * PAGE_SIZE)); + dev->param_addr = (struct te_oper_param *) + (req_buf + (1 * PAGE_SIZE)); + dev->plist_addr = (uint64_t *) + (req_buf + (2 * PAGE_SIZE)); + + /* alloc param bitmap allocator */ + bitmap_size = BITS_TO_LONGS(TE_PARAM_MAX) * sizeof(long); + dev->param_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!dev->param_bitmap) { + pr_err("%s: Failed to allocate param bitmap\n", __func__); + ret = -ENOMEM; + goto error; + } + + /* alloc plist bitmap allocator */ + bitmap_size = BITS_TO_LONGS(TE_PLIST_MAX) * sizeof(long); + dev->plist_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!dev->plist_bitmap) { + pr_err("%s: Failed to allocate plist bitmap\n", __func__); + ret = -ENOMEM; + goto error; + } + + tlk_send_smc(TE_SMC_REGISTER_REQ_BUF, + (uintptr_t)dev->req_addr, req_buf_size); + + if (!dev->req_addr || !dev->param_addr || !dev->plist_addr) { + pr_err("%s: Bad dev request addr/param addr/plist addr!\n", + __func__); + ret = -ENOMEM; + goto error; + } + + for (cmd_desc_count = 0; + cmd_desc_count < TE_CMD_DESC_MAX; cmd_desc_count++) { + + req_desc = kzalloc(sizeof(struct te_cmd_req_desc), GFP_KERNEL); + if (req_desc == NULL) { + pr_err("%s: Failed to allocate cmd req descriptor\n", + __func__); + ret = -ENOMEM; + goto error; + } + req_desc->req_addr = dev->req_addr + cmd_desc_count; + INIT_LIST_HEAD(&(req_desc->list)); + + /* Add the cmd param descriptor to free list */ + list_add_tail(&req_desc->list, &(dev->free_cmd_list)); + } + return 0; +error: + pr_err("%s: Error, returning %d\n", __func__, ret); + kfree(req_buf); + kfree(dev->param_bitmap); + kfree(dev->plist_bitmap); + list_for_each_entry_safe(req_desc, tmp_req_desc, + &(dev->free_cmd_list), list) + kfree(req_desc); + return ret; +} + +static void te_release_free_cmd_list(struct tlk_device *dev) +{ + kfree(dev->req_addr); + kfree(dev->param_bitmap); + kfree(dev->plist_bitmap); +} + +struct te_oper_param *te_get_free_params(struct tlk_device *dev, + unsigned int nparams) +{ + struct te_oper_param *params = NULL; + int idx, nbits; + + if (nparams) { + nbits = get_count_order(nparams); + idx = bitmap_find_free_region(dev->param_bitmap, + TE_PARAM_MAX, nbits); + if (idx >= 0) + params = dev->param_addr + idx; + } + return params; +} + +void te_put_free_params(struct tlk_device *dev, + struct te_oper_param *params, uint32_t nparams) +{ + int idx, nbits; + + idx = (params - dev->param_addr); + nbits = get_count_order(nparams); + bitmap_release_region(dev->param_bitmap, idx, nbits); +} + +struct te_cmd_req_desc *te_get_free_cmd_desc(struct tlk_device *dev) +{ + struct te_cmd_req_desc *cmd_desc = NULL; + + if (!(list_empty(&(dev->free_cmd_list)))) { + cmd_desc = list_first_entry(&(dev->free_cmd_list), + struct te_cmd_req_desc, list); + list_del(&(cmd_desc->list)); + list_add_tail(&cmd_desc->list, &(dev->used_cmd_list)); + } + return cmd_desc; +} + +void te_put_used_cmd_desc(struct tlk_device *dev, + struct te_cmd_req_desc *cmd_desc) +{ + struct te_cmd_req_desc *param_desc, *tmp_param_desc; + + if (cmd_desc) { + list_for_each_entry_safe(param_desc, tmp_param_desc, + &(dev->used_cmd_list), list) { + if (cmd_desc->req_addr == param_desc->req_addr) { + list_del(¶m_desc->list); + list_add_tail(¶m_desc->list, + &(dev->free_cmd_list)); + } + } + } +} + +static void __attribute__((unused)) te_print_cmd_list( + struct tlk_device *dev, int used_list) +{ + struct te_cmd_req_desc *param_desc; + + if (!used_list) { + pr_info("Printing free cmd list\n"); + if (!(list_empty(&(dev->free_cmd_list)))) { + list_for_each_entry(param_desc, &(dev->free_cmd_list), + list) + pr_info("Phys addr for cmd req desc (%p)\n", + param_desc->req_addr); + } + } else { + pr_info("Printing used cmd list\n"); + if (!(list_empty(&(dev->used_cmd_list)))) { + list_for_each_entry(param_desc, &(dev->used_cmd_list), + list) + pr_info("Phys addr for cmd req desc (%p)\n", + param_desc->req_addr); + } + } +} + + +static void te_close_sessions(struct tlk_context *context) +{ + struct tlk_device *dev = context->dev; + union te_cmd cmd; + struct te_cmd_req_desc *cmd_desc = NULL; + struct te_request *request; + struct te_session *session, *tmp_session; + + if (list_empty(&context->session_list)) + return; + + cmd_desc = te_get_free_cmd_desc(dev); + if (!cmd_desc) { + pr_err("%s: failed to get cmd_desc\n", __func__); + return; + } + + request = cmd_desc->req_addr; + + list_for_each_entry_safe(session, tmp_session, + &context->session_list, list) { + + memset(request, 0, sizeof(struct te_request)); + + cmd.closesession.session_id = session->session_id; + + te_close_session(&cmd.closesession, request, context); + } + + te_put_used_cmd_desc(dev, cmd_desc); +} + +static int tlk_device_open(struct inode *inode, struct file *file) +{ + struct tlk_context *context; + int ret = 0; + + context = kzalloc(sizeof(struct tlk_context), GFP_KERNEL); + if (!context) { + ret = -ENOMEM; + goto error; + } + context->dev = &tlk_dev; + INIT_LIST_HEAD(&context->session_list); + + file->private_data = context; + return 0; +error: + return ret; +} + +static int tlk_device_release(struct inode *inode, struct file *file) +{ + struct tlk_context *context = file->private_data; + + /* close any open sessions */ + mutex_lock(&smc_lock); + te_close_sessions(context); + mutex_unlock(&smc_lock); + + kfree(file->private_data); + file->private_data = NULL; + return 0; +} + +static int copy_params_from_user(struct te_request *req, + struct te_operation *operation, struct te_oper_param *caller_params) +{ + struct te_oper_param *param_array; + struct te_oper_param *user_param; + uint32_t i; + + if (operation->list_count == 0) + return 0; + + param_array = (struct te_oper_param *)(uintptr_t)req->params; + if (param_array == NULL) { + pr_err("param_array empty\n"); + return 1; + } + + user_param = (struct te_oper_param *)(uintptr_t)operation->list_head; + for (i = 0; i < operation->list_count && user_param != NULL; i++) { + if (copy_from_user(param_array + i, user_param, + sizeof(struct te_oper_param))) { + pr_err("Failed to copy operation parameter:%d, %p, " \ + "list_count: %d\n", + i, user_param, operation->list_count); + return 1; + } + user_param = (struct te_oper_param *)(uintptr_t) + param_array[i].next_ptr_user; + } + + memcpy(caller_params, param_array, + sizeof(struct te_oper_param) * operation->list_count); + + return 0; +} + +static int copy_params_to_user(struct te_request *req, + struct te_operation *operation, struct te_oper_param *caller_params) +{ + struct te_oper_param *param_array; + struct te_oper_param *user_param; + uint32_t i; + + if (operation->list_count == 0) + return 0; + + param_array = (struct te_oper_param *)(uintptr_t)req->params; + if (param_array == NULL) { + pr_err("param_array empty\n"); + return 1; + } + + user_param = + (struct te_oper_param *)(uintptr_t)operation->list_head; + for (i = 0; i < req->params_size; i++) { + /* clear flags */ + param_array[i].type &= ~TE_PARAM_TYPE_ALL_FLAGS; + + switch(param_array[i].type) { + /* + * Restore the memory base address as it can be overridden + * while sending it to secure world + */ + case TE_PARAM_TYPE_MEM_RO: + case TE_PARAM_TYPE_MEM_RW: + case TE_PARAM_TYPE_PERSIST_MEM_RO: + case TE_PARAM_TYPE_PERSIST_MEM_RW: + param_array[i].u.Mem.base = caller_params[i].u.Mem.base; + } + + if (copy_to_user(user_param, param_array + i, + sizeof(struct te_oper_param))) { + pr_err("Failed to copy back parameter:%d %p\n", i, + user_param); + return 1; + } + user_param = (struct te_oper_param *)(uintptr_t) + param_array[i].next_ptr_user; + } + return 0; +} + +static long te_handle_trustedapp_ioctl(struct file *file, + unsigned int ioctl_num, unsigned long ioctl_param) +{ + long err = 0; + union te_cmd cmd; + struct te_operation *operation = NULL; + struct te_oper_param *params = NULL; + struct te_oper_param *caller_params = NULL; + struct te_request *request; + void __user *ptr_user_answer = NULL; + struct te_answer answer; + struct te_cmd_req_desc *cmd_desc = NULL; + struct tlk_context *context = file->private_data; + struct tlk_device *dev = context->dev; + + if (copy_from_user(&cmd, (void __user *)ioctl_param, + sizeof(union te_cmd))) { + pr_err("Failed to copy command request\n"); + err = -EFAULT; + goto error; + } + + memset(&answer, 0, sizeof(struct te_answer)); + + switch (ioctl_num) { + case TE_IOCTL_OPEN_CLIENT_SESSION: + operation = &cmd.opensession.operation; + ptr_user_answer = (void *)(uintptr_t)cmd.opensession.answer; + + cmd_desc = te_get_free_cmd_desc(dev); + params = te_get_free_params(dev, operation->list_count); + + if (!cmd_desc || (operation->list_count && !params)) { + SET_ANSWER(answer, + OTE_ERROR_OUT_OF_MEMORY, + OTE_RESULT_ORIGIN_COMMS); + pr_err("failed to get cmd_desc/params\n"); + goto error; + } + + request = cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request)); + + request->params = (uintptr_t)params; + request->params_size = operation->list_count; + + if (operation->list_count > 0) { + caller_params = kmalloc(sizeof(struct te_oper_param) * + operation->list_count, GFP_KERNEL); + if (!caller_params) { + pr_err("%s: failed to allocate caller params\n", __func__); + err = -ENOMEM; + goto error; + } + } + + if (copy_params_from_user(request, operation, caller_params)) { + err = -EFAULT; + pr_err("%s: failed to copy params from user\n", __func__); + goto error; + } + + te_open_session(&cmd.opensession, request, context); + + SET_ANSWER(answer, request->result, request->result_origin); + answer.session_id = request->session_id; + break; + + case TE_IOCTL_CLOSE_CLIENT_SESSION: + ptr_user_answer = (void *)(uintptr_t)cmd.closesession.answer; + cmd_desc = te_get_free_cmd_desc(dev); + if (!cmd_desc) { + SET_ANSWER(answer, + OTE_ERROR_OUT_OF_MEMORY, + OTE_RESULT_ORIGIN_COMMS); + pr_err("failed to get cmd_desc\n"); + goto error; + } + + request = cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request)); + + /* close session cannot fail */ + te_close_session(&cmd.closesession, request, context); + break; + + case TE_IOCTL_LAUNCH_OPERATION: + operation = &cmd.launchop.operation; + ptr_user_answer = (void *)(uintptr_t)cmd.launchop.answer; + + cmd_desc = te_get_free_cmd_desc(dev); + params = te_get_free_params(dev, operation->list_count); + + if (!cmd_desc || (operation->list_count && !params)) { + SET_ANSWER(answer, + OTE_ERROR_OUT_OF_MEMORY, + OTE_RESULT_ORIGIN_COMMS); + pr_err("failed to get cmd_desc/params\n"); + goto error; + } + + request = cmd_desc->req_addr; + memset(request, 0, sizeof(struct te_request)); + + request->params = (uintptr_t)params; + request->params_size = operation->list_count; + + if (operation->list_count > 0) { + caller_params = kmalloc(sizeof(struct te_oper_param) * + operation->list_count, GFP_KERNEL); + if (!caller_params) { + pr_err("%s: failed to allocate caller params\n", __func__); + err = -ENOMEM; + goto error; + } + } + + if (copy_params_from_user(request, operation, caller_params)) { + err = -EFAULT; + pr_info("%s: failed to copy params from user\n", __func__); + goto error; + } + + te_launch_operation(&cmd.launchop, request, context); + + SET_ANSWER(answer, request->result, request->result_origin); + break; + + default: + pr_err("Invalid IOCTL Cmd\n"); + err = -EINVAL; + goto error; + } + if (ptr_user_answer && !err) { + if (copy_to_user(ptr_user_answer, &answer, + sizeof(struct te_answer))) { + pr_err("Failed to copy answer\n"); + err = -EFAULT; + } + } + if (request->params && !err) { + if (copy_params_to_user(request, operation, caller_params)) { + pr_err("Failed to copy return params\n"); + err = -EFAULT; + } + } + +error: + if (cmd_desc) + te_put_used_cmd_desc(dev, cmd_desc); + if (params) + te_put_free_params(dev, params, operation->list_count); + kfree(caller_params); + return err; +} + +static long tlk_device_ioctl(struct file *file, unsigned int ioctl_num, + unsigned long ioctl_param) +{ + int err; + + switch (ioctl_num) { + case TE_IOCTL_OPEN_CLIENT_SESSION: + case TE_IOCTL_CLOSE_CLIENT_SESSION: + case TE_IOCTL_LAUNCH_OPERATION: + mutex_lock(&smc_lock); + err = te_handle_trustedapp_ioctl(file, ioctl_num, ioctl_param); + mutex_unlock(&smc_lock); + break; + + case TE_IOCTL_SS_CMD: + err = te_handle_ss_ioctl(file, ioctl_num, ioctl_param); + break; + + default: + pr_err("%s: Invalid IOCTL (0x%x) id 0x%x max 0x%lx\n", + __func__, ioctl_num, _IOC_NR(ioctl_num), + (unsigned long)TE_IOCTL_MAX_NR); + err = -EINVAL; + break; + } + + return err; +} + +static struct device_node *get_tlk_device_node(void) +{ + struct device_node *node = NULL; + node = of_find_compatible_node(NULL, NULL, "android,tlk-driver"); + if (!node) + pr_debug("TLK node not present in FDT\n"); + return node; +} + +int te_is_secos_dev_enabled(void) +{ + static int tlk_dev_status = 0; + struct device_node *node = NULL; + + if (unlikely(tlk_dev_status == 0)) { + node = get_tlk_device_node(); + tlk_dev_status = (node && of_device_is_available(node)); + } + + return tlk_dev_status; +} + +/* + * tlk_driver function definitions. + */ +static const struct file_operations tlk_device_fops = { + .owner = THIS_MODULE, + .open = tlk_device_open, + .release = tlk_device_release, + .unlocked_ioctl = tlk_device_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = tlk_device_ioctl, +#endif +}; + +struct miscdevice tlk_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "tlk_device", + .fops = &tlk_device_fops, +}; + +static int tlk_driver_probe(struct platform_device *pdev) +{ + struct reset_control *rst; + struct clk *clk; + int ret; + + clk = devm_clk_get(&pdev->dev, "nvdec"); + if (!IS_ERR(clk)) { + ret = clk_prepare_enable(clk); + if (ret) + return ret; + } else if (PTR_ERR(clk) != -ENOENT) { + return PTR_ERR(clk); + } else { + pr_err("%s: nvdec clock not available\n", __func__); + } + + rst = devm_reset_control_get(&pdev->dev, "nvdec"); + if (!IS_ERR(rst)) { + ret = reset_control_deassert(rst); + if (ret) + return ret; + } else if (PTR_ERR(rst) != -ENOENT) { + return PTR_ERR(rst); + } else { + pr_err("%s: nvdec reset not available\n", __func__); + } + + platform_set_drvdata(pdev, clk); + + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (ret) { + pr_err("%s: of_platform_populate failed\n", __func__); + goto disable_clk; + } + + if (!te_is_secos_dev_enabled()) { + ret = -ENODEV; + goto disable_clk; + } + + return 0; + +disable_clk: + if (!IS_ERR(clk)) + clk_disable_unprepare(clk); + + return ret; +} + +static void tlk_driver_remove(struct platform_device *pdev) { + struct clk *clk = platform_get_drvdata(pdev); + + if (!IS_ERR(clk)) + clk_disable_unprepare(clk); +} + +static const struct of_device_id tlk_driver_of_match[] = { + { .compatible = "android,tlk-driver",}, + {}, +}; + +static struct platform_driver tlk_driver = { + .probe = tlk_driver_probe, + .remove = tlk_driver_remove, + .driver = { + .name = "tlk-driver", + .owner = THIS_MODULE, + .of_match_table = tlk_driver_of_match, + } +}; + +static int __init tlk_driver_init(void) +{ + if (get_tlk_device_node()) { + int ret; + + INIT_LIST_HEAD(&(tlk_dev.used_cmd_list)); + INIT_LIST_HEAD(&(tlk_dev.free_cmd_list)); + + ret = te_create_free_cmd_list(&tlk_dev); + if (ret != 0) { + pr_err("%s: failed to create free_list\n", __func__); + return ret; + } + } + + return platform_driver_register(&tlk_driver); +} + +static void __exit tlk_driver_exit(void) +{ + platform_driver_unregister(&tlk_driver); + + if (get_tlk_device_node()) + te_release_free_cmd_list(&tlk_dev); +} + +/* Initialize early so that other device drivers can use it during boot */ +subsys_initcall(tlk_driver_init); +module_exit(tlk_driver_exit); + +static int __init tlk_driver_misc_init(void) +{ + int ret; + + if (!te_is_secos_dev_enabled()) { + pr_info("%s: tlk not enabled on this device\n", __func__); + return -ENODEV; + } + + ret = misc_register(&tlk_misc_device); + if (ret) + pr_err("%s: misc_register failed: %d\n", __func__, ret); + + return ret; +} + +static void __exit tlk_driver_misc_exit(void) +{ + if (te_is_secos_dev_enabled()) + misc_deregister(&tlk_misc_device); +} + +module_init(tlk_driver_misc_init); +module_exit(tlk_driver_misc_exit); diff --git a/security/tlk_driver/ote_fs.c b/security/tlk_driver/ote_fs.c new file mode 100644 index 000000000000..467f9c83d6a1 --- /dev/null +++ b/security/tlk_driver/ote_fs.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013-2016 NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ote_protocol.h" + +/* SS operation timeout in milliseconds */ +#define SS_OP_TIME_OUT 5000 + +static DECLARE_COMPLETION(req_ready); +static DECLARE_COMPLETION(req_complete); + +static void tlk_ss_reset(void) +{ + /* reset completion vars to default state */ + init_completion(&req_ready); + init_completion(&req_complete); +} + +int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num, + unsigned long ioctl_param) +{ + int ss_cmd; + + if (ioctl_num != TE_IOCTL_SS_CMD) + return -EINVAL; + + if (copy_from_user(&ss_cmd, (void __user *)ioctl_param, + sizeof(ss_cmd))) { + pr_err("%s: copy from user space failed\n", __func__); + return -EFAULT; + } + + switch (ss_cmd) { + case TE_IOCTL_SS_CMD_GET_NEW_REQ: + /* wait for a new request */ + if (wait_for_completion_interruptible(&req_ready)) + return -ENODATA; + break; + case TE_IOCTL_SS_CMD_REQ_COMPLETE: + /* signal the producer */ + complete(&req_complete); + break; + default: + pr_err("%s: unknown ss_cmd 0x%x\n", __func__, ss_cmd); + return -EINVAL; + } + + return 0; +} + +int tlk_ss_op(void) +{ + /* signal consumer */ + complete(&req_ready); + + /* wait for the consumer's signal */ + if (!wait_for_completion_timeout(&req_complete, + msecs_to_jiffies(SS_OP_TIME_OUT))) { + /* daemon didn't respond */ + tlk_ss_reset(); + return OTE_ERROR_CANCEL; + } + + return OTE_SUCCESS; +} diff --git a/security/tlk_driver/ote_log.c b/security/tlk_driver/ote_log.c new file mode 100644 index 000000000000..26ff60968cee --- /dev/null +++ b/security/tlk_driver/ote_log.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2013-2018 NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ote_protocol.h" + +#define LOGBUF_SIZE 8192 + +struct circular_buffer { + uint32_t size; /* Indicates the total size of the buffer */ + uint32_t start; /* Starting point of valid data in buffer */ + uint32_t end; /* First character which is empty (can be written to) */ + uint32_t overflow; /* Indicator whether buffer has overwritten itself */ + char *buf; +}; + +static int ote_logging_enabled; +struct circular_buffer *cb; + +/* + * Initialize the shared buffer for TLK logging. + * The shared buffer is allocated in DMA memory to get uncached memory + * since TLK directly writes to the physical address of the shared buffer. + * The structure is declared in DMA memory too since it's members will + * also be updated by the TLK directly to their physical addresses. + */ +static int circ_buf_init(struct circular_buffer **cbptr) +{ + + dma_addr_t tp; + + *cbptr = (struct circular_buffer *) dma_alloc_coherent(NULL, + sizeof(struct circular_buffer), &tp, GFP_KERNEL); + if (!*cbptr) { + pr_err("%s: no memory available for circular buffer struct\n", + __func__); + return -ENOMEM; + } + memset(*cbptr, 0, sizeof(struct circular_buffer)); + + (*cbptr)->start = 0; + (*cbptr)->end = 0; + (*cbptr)->size = LOGBUF_SIZE; + + (*cbptr)->buf = (char *) dma_alloc_coherent(NULL, LOGBUF_SIZE, + &tp, GFP_KERNEL); + if (!(*cbptr)->buf) { + pr_err("%s: no memory available for shared buffer\n", + __func__); + /* Frees the memory allocated using dma_alloc_coherent */ + dma_free_coherent(NULL, + sizeof(struct circular_buffer), cbptr, tp); + return -ENOMEM; + } + memset((*cbptr)->buf, 0, LOGBUF_SIZE); + + (*cbptr)->overflow = 0; + + return 0; +} + +/* + * Copy the contents of the circular buffer into a char buffer in order. + * This helps to treat the buffer like a string and use it to tokenize it + * into lines, tag and display it. + */ +static int circ_buf_copy(struct circular_buffer *cb, char *text) +{ + if (cb->end == cb->start) + return 0; + + if (cb->end > cb->start) { + if (abs(cb->end - cb->start) > LOGBUF_SIZE) { + pr_err("%s: cbuf pointers corrupted\n", __func__); + return -EINVAL; + } + + memcpy(text, cb->buf + cb->start, cb->end - cb->start); + + } else if (cb->start > cb->end) { + if (abs(cb->end - cb->start) > LOGBUF_SIZE) { + pr_err("%s: cbuf pointers corrupted\n", __func__); + return -EINVAL; + } + + memcpy(text, cb->buf + cb->start, cb->size - cb->start); + memcpy(text + cb->size - cb->start, cb->buf, cb->end); + + } + + return 0; +} + +/* + * Function which prints TLK logs. + * Tokenizes the TLK logs into lines, tags each line + * and prints it out to kmsg file. + */ +void ote_print_logs(void) +{ + char *text = NULL; + char *temp = NULL; + char *buffer = NULL; + + if (!ote_logging_enabled) + return; + + buffer = kzalloc(LOGBUF_SIZE, GFP_KERNEL); + if (!buffer) { + pr_err("%s: memory allocation failed\n", __func__); + return; + } + + /* This detects if the buffer proved to be too small to hold the data. + * If buffer is not large enough, it overwrites it's oldest data, + * This warning serves to alert the user to possibly use a bigger buffer + */ + if (cb->overflow == 1) { + pr_warn("[TLK] **WARNING** TLK buffer overwritten.\n"); + cb->overflow = 0; + } + + if (circ_buf_copy(cb, buffer) != 0) { + kfree(buffer); + return; + } + cb->buf[cb->end] = '\0'; + + /* + * In case no delimiter was found, strsep returns the entire string as + * token and the original string is made as NULL + */ + text = buffer; + temp = strsep(&text, "\n"); + while (temp != NULL) { + if (strnlen(temp, LOGBUF_SIZE)) + pr_info("[TLK] %s\n", temp); + temp = strsep(&text, "\n"); + } + + /* Indicate that buffer is empty */ + cb->start = cb->end; + kfree(buffer); +} + +/* + * Call function to initialize circular buffer. + * An SMC is made to send the virtual address of the structure to + * the secure OS. + */ +static int ote_logger_probe(struct platform_device *pdev) +{ + if (circ_buf_init(&cb) != 0) + return -1; + + /* enable logging only if secure firmware supports it */ + if (!tlk_send_smc(TE_SMC_INIT_LOGGER, (uintptr_t)cb, 0)) + ote_logging_enabled = 1; + + ote_print_logs(); + + return 0; +} + +static const struct of_device_id ote_logger_of_match[] = { + { .compatible = "android,ote-logger",}, + {}, +}; + +static struct platform_driver ote_logger_driver = { + .probe = ote_logger_probe, + .driver = { + .name = "ote-logger", + .owner = THIS_MODULE, + .of_match_table = ote_logger_of_match, + } +}; + +static int __init ote_logger_driver_init(void) +{ + return platform_driver_register(&ote_logger_driver); +} + +subsys_initcall(ote_logger_driver_init); diff --git a/security/tlk_driver/ote_memory.c b/security/tlk_driver/ote_memory.c new file mode 100644 index 000000000000..0a19e008d9df --- /dev/null +++ b/security/tlk_driver/ote_memory.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ote_protocol.h" + +#define PHYS_PAGELIST_ALIGNED_PA(ent) ((ent) & 0xFFFFFFFFF000ULL) + +#ifndef CONFIG_ARM64 +#define PTE_RDONLY PTE_AP2 +#endif + +extern uint64_t _tlk_get_mair(void); +static uint64_t te_get_mair_attrs(void) { return _tlk_get_mair(); } +static uint64_t te_get_pte_attrs(uint64_t pte, uint64_t mair) +{ + uint64_t pte_attrs, shareable; + uint32_t idx; + uint8_t attrs; + + /* Bits 2:4 holds attributes index */ + idx = (pte >> 2) & 0x7; + attrs = *((uint8_t *)&mair + idx); + + /* Bits 8:9 holds shareability field */ + shareable = (pte >> 8) & 0x3; + + /* + * TLK expects that attributes are stored in the first byte of PTE. + * MSB holds inner(4 bits), outer(4 bits) and shareable (2 bits) + * attributes respectively. + */ + pte_attrs = attrs; + pte_attrs = pte_attrs << 56; + pte_attrs |= (shareable << 54); + return pte_attrs; +} + +static void te_put_free_plist(struct te_shmem_desc *shmem_desc) +{ + struct tlk_device *dev = &tlk_dev; + int idx, nbits; + + idx = shmem_desc->plist_idx; + nbits = get_count_order(shmem_desc->nr_pages); + + bitmap_release_region(dev->plist_bitmap, idx, nbits); +} + +static void te_release_mem_buffer(struct te_shmem_desc *shmem_desc) +{ + uint32_t i; + + list_del(&shmem_desc->list); + for (i = 0; i < shmem_desc->nr_pages; i++) { + if ((shmem_desc->type == TE_PARAM_TYPE_MEM_RW) || + (shmem_desc->type == TE_PARAM_TYPE_PERSIST_MEM_RW)) + set_page_dirty_lock(shmem_desc->pages[i]); + put_page(shmem_desc->pages[i]); + } + + te_put_free_plist(shmem_desc); + + kfree(shmem_desc->pages); + kfree(shmem_desc); +} + +void te_release_mem_buffers(struct list_head *buflist) +{ + struct te_shmem_desc *shmem_desc, *tmp_shmem_desc; + + list_for_each_entry_safe(shmem_desc, tmp_shmem_desc, buflist, list) { + te_release_mem_buffer(shmem_desc); + } +} + +static int te_load_page_list(unsigned long start, + unsigned int npages, + struct page **pages, + struct vm_area_struct **vmas) +{ + struct tlk_device *dev = &tlk_dev; + uint64_t *ptes; + uint64_t mair; + int i, idx, nbits; + + nbits = get_count_order(npages); + idx = bitmap_find_free_region(dev->plist_bitmap, + TE_PLIST_MAX, nbits); + if (idx < 0) { + pr_err("%s: ERROR: plist bitmap is full, order %d max size %lu\n", + __func__, nbits, TE_PLIST_MAX); + return -ENOMEM; + } + + mair = te_get_mair_attrs(); + ptes = dev->plist_addr + idx; + + for (i = 0; i < npages; i++, start += PAGE_SIZE) { + uint64_t pte; +#ifdef CONFIG_ARM64 + /* + * Not performing this sanity check for 32 bit kernel as + * PTE_ATTRINDX* macros are not available in 32 bit headers + */ + if ((pgprot_val(vmas[i]->vm_page_prot) & PTE_ATTRINDX_MASK) != + PTE_ATTRINDX(MT_NORMAL)) { + pr_err("%s: unsupported memory type: %llx\n", + __func__, + pgprot_val(vmas[i]->vm_page_prot) & PTE_ATTRINDX_MASK); + bitmap_release_region(dev->plist_bitmap, idx, nbits); + return -EINVAL; + } +#endif + + /* + * Recreate the pte of the page - we can't access it + * safely here race-free. + */ + + pte = page_to_phys(pages[i]); + pte |= pgprot_val(vmas[i]->vm_page_prot); + if (vmas[i]->vm_flags & VM_WRITE) + pte &= ~PTE_RDONLY; + + ptes[i] = PHYS_PAGELIST_ALIGNED_PA(pte); + ptes[i] |= (start & (PAGE_SIZE-1)); + ptes[i] |= te_get_pte_attrs(pte, mair); + } + return idx; +} + +static int te_pin_user_pages(struct te_oper_param *param, + struct page ***pages, + struct vm_area_struct **vmas, + uint32_t nr_pages, uint32_t *plist_idx) +{ + struct tlk_device *dev = &tlk_dev; + int idx, ret = 0; + int nr_pinned = 0; + unsigned long start; + uint32_t length; + bool writable; + int i; + + start = (unsigned long)param->u.Mem.base, + length = param->u.Mem.len; + + *pages = kzalloc(nr_pages * sizeof(struct page **), GFP_KERNEL); + if (!*pages) { + pr_err("%s: Error allocating %d pages!\n", + __func__, (int)nr_pages); + return OTE_ERROR_OUT_OF_MEMORY; + } + + writable = (param->type == TE_PARAM_TYPE_MEM_RW || + param->type == TE_PARAM_TYPE_PERSIST_MEM_RW); + + down_read(¤t->mm->mmap_lock); + /* + * vmas are valid only when mmap_lock is held. Hence holding the lock + * across get user pages and process returned vmas. + */ + nr_pinned = get_user_pages(start, nr_pages, + writable ? FOLL_WRITE : 0, *pages); + if (nr_pinned != nr_pages) { + pr_err("%s: Error %d in get_user_pages for buffer 0x%lx\n", + __func__, nr_pinned, start); + ret = OTE_ERROR_GENERIC; + goto error; + } + + idx = te_load_page_list(start, nr_pages, *pages, vmas); + if (idx < 0) { + pr_err("%s: Error loading page list, idx = %d!\n", + __func__, idx); + ret = OTE_ERROR_OUT_OF_MEMORY; + goto error; + } + up_read(¤t->mm->mmap_lock); + + /* stores the index from the beginning of shared buffer */ + param->u.Mem.base = (uintptr_t)(dev->plist_addr + idx) - + (uintptr_t)dev->req_addr; + + param->type |= TE_PARAM_TYPE_FLAGS_PHYS_LIST; + + *plist_idx = idx; + + return OTE_SUCCESS; +error: + up_read(¤t->mm->mmap_lock); + for (i = 0; i < nr_pinned; i++) + put_page((*pages)[i]); + kfree(*pages); + return ret; +} + +static int te_prep_mem_buffer(struct te_oper_param *param, + struct te_session *session) +{ + struct page **pages = NULL; + struct te_shmem_desc *shmem_desc = NULL; + int ret = 0, nr_pages = 0; + uint32_t buf_type; + unsigned long start; + uint32_t length; + struct vm_area_struct **vmas; + uint32_t plist_idx = 0; + + /* allocate new shmem descriptor */ + shmem_desc = kzalloc(sizeof(struct te_shmem_desc), GFP_KERNEL); + if (!shmem_desc) { + pr_err("%s: out of memory for shmem_desc!\n", __func__); + ret = OTE_ERROR_OUT_OF_MEMORY; + goto error; + } + + /* Need this for vma alloc prior to pin_user_pages */ + start = (unsigned long)param->u.Mem.base, + length = param->u.Mem.len; + nr_pages = (((uintptr_t)start & (PAGE_SIZE - 1)) + + (length + PAGE_SIZE - 1)) >> PAGE_SHIFT; + + vmas = kzalloc(sizeof(*vmas) * nr_pages, GFP_KERNEL); + if (!vmas) { + pr_err("%s: out of memory for vmas! (%d pages)\n", + __func__, nr_pages); + ret = OTE_ERROR_OUT_OF_MEMORY; + goto error_alloc_vmas; + } + + /* pin pages */ + ret = te_pin_user_pages(param, &pages, vmas, nr_pages, &plist_idx); + if (ret != OTE_SUCCESS) { + pr_err("%s: te_pin_user_pages failed (%d)\n", __func__, ret); + goto error_pin_pages; + } + kfree(vmas); + + /* initialize shmem descriptor */ + INIT_LIST_HEAD(&(shmem_desc->list)); + shmem_desc->plist_idx = plist_idx; + shmem_desc->size = param->u.Mem.len; + shmem_desc->nr_pages = nr_pages; + shmem_desc->pages = pages; + + /* just type (no flags) */ + buf_type = param->type & ~TE_PARAM_TYPE_ALL_FLAGS; + + /* add shmem descriptor to proper list */ + if ((buf_type == TE_PARAM_TYPE_MEM_RO) || + (buf_type == TE_PARAM_TYPE_MEM_RW)) + list_add_tail(&shmem_desc->list, &session->temp_shmem_list); + else { + list_add_tail(&shmem_desc->list, + &session->inactive_persist_shmem_list); + } + + return OTE_SUCCESS; + +error_pin_pages: + kfree(vmas); +error_alloc_vmas: + kfree(shmem_desc); +error: + return ret; +} + +int te_prep_mem_buffers(struct te_request *request, + struct te_session *session) +{ + uint32_t i; + int ret = OTE_SUCCESS; + struct te_oper_param *params; + + params = (struct te_oper_param *)(uintptr_t)request->params; + for (i = 0; i < request->params_size; i++) { + switch (params[i].type) { + case TE_PARAM_TYPE_NONE: + case TE_PARAM_TYPE_INT_RO: + case TE_PARAM_TYPE_INT_RW: + break; + case TE_PARAM_TYPE_MEM_RO: + case TE_PARAM_TYPE_MEM_RW: + case TE_PARAM_TYPE_PERSIST_MEM_RO: + case TE_PARAM_TYPE_PERSIST_MEM_RW: + ret = te_prep_mem_buffer(params + i, session); + if (ret != OTE_SUCCESS) { + pr_err("%s failed with err (%d)\n", + __func__, ret); + ret = OTE_ERROR_BAD_PARAMETERS; + goto error; + } + break; + default: + pr_err("%s: OTE_ERROR_BAD_PARAMETERS\n", __func__); + ret = OTE_ERROR_BAD_PARAMETERS; + break; + } + } + return OTE_SUCCESS; +error: + /* release mem buffers */ + te_release_mem_buffers(&session->temp_shmem_list); + te_release_mem_buffers(&session->inactive_persist_shmem_list); + return ret; +} + +void te_activate_persist_mem_buffers(struct te_session *session) +{ + struct te_shmem_desc *shmem_desc, *tmp_shmem_desc; + + /* move persist mem buffers from inactive list to active list */ + list_for_each_entry_safe(shmem_desc, tmp_shmem_desc, + &session->inactive_persist_shmem_list, list) { + list_move_tail(&shmem_desc->list, &session->persist_shmem_list); + } +} diff --git a/security/tlk_driver/ote_protocol.h b/security/tlk_driver/ote_protocol.h new file mode 100644 index 000000000000..b7d242c9c367 --- /dev/null +++ b/security/tlk_driver/ote_protocol.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2013-2021 NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __TLK_OTE_PROTOCOL_H__ +#define __TLK_OTE_PROTOCOL_H__ + +#include "ote_types.h" + +#include + +/* + * shared buffer is 6 pages: 1st are requests, 2nd are params and the + * remaining 4 are for params physical pages list + */ +#define TE_REQUEST_PAGE_COUNT 1 +#define TE_PARAM_PAGE_COUNT 1 +#define TE_PHYS_PAGE_LIST_PAGE_COUNT 4 +#define TE_TOTAL_PAGE_COUNT (TE_REQUEST_PAGE_COUNT + \ + TE_PARAM_PAGE_COUNT + \ + TE_PHYS_PAGE_LIST_PAGE_COUNT) + +#define TE_CMD_DESC_MAX ((PAGE_SIZE * TE_REQUEST_PAGE_COUNT) / sizeof(struct te_request)) +#define TE_PARAM_MAX ((PAGE_SIZE * TE_PARAM_PAGE_COUNT) / sizeof(struct te_oper_param)) +#define TE_PLIST_MAX ((PAGE_SIZE * TE_PHYS_PAGE_LIST_PAGE_COUNT) / sizeof(uint64_t)) + +#define MAX_BUFFER_MAP_SIZE (TE_PLIST_MAX * PAGE_SIZE) +#define MAX_EXT_SMC_ARGS 12 + +extern struct mutex smc_lock; +extern struct tlk_device tlk_dev; +extern void tlk_fiq_glue_aarch64(void); + +uint32_t tlk_send_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2); +uint32_t _tlk_generic_smc(uint32_t arg0, uintptr_t arg1, uintptr_t arg2); +void tlk_irq_handler(void); +struct te_oper_param *te_get_free_params(struct tlk_device *dev, + unsigned int nparams); +void te_put_free_params(struct tlk_device *dev, + struct te_oper_param *params, uint32_t nparams); +struct te_cmd_req_desc *te_get_free_cmd_desc(struct tlk_device *dev); +void te_put_used_cmd_desc(struct tlk_device *dev, + struct te_cmd_req_desc *cmd_desc); + +/* errors returned by secure world in reponse to SMC calls */ +enum { + TE_ERROR_PREEMPT_BY_IRQ = 0xFFFFFFFD, + TE_ERROR_PREEMPT_BY_FS = 0xFFFFFFFE, +}; + +struct tlk_device { + struct te_request *req_addr; + dma_addr_t req_addr_phys; + struct te_oper_param *param_addr; + dma_addr_t param_addr_phys; + uint64_t *plist_addr; + dma_addr_t plist_addr_phys; + + unsigned long *param_bitmap; + unsigned long *plist_bitmap; + + struct list_head used_cmd_list; + struct list_head free_cmd_list; +}; + +struct te_cmd_req_desc { + struct te_request *req_addr; + struct list_head list; +}; + +struct te_shmem_desc { + struct list_head list; + uint32_t type; + uint32_t plist_idx; + size_t size; + struct page **pages; + unsigned int nr_pages; +}; + +/* + * Per-session data structure. + * + * Both temp (freed upon completion of the associated op) and persist + * (freed upon session close) memory references are tracked by this + * structure. + * + * Persistent memory references stay on an inactive list until the + * associated op completes. If it completes successfully then the + * references are moved to the active list. + */ +struct te_session { + struct list_head list; + uint32_t session_id; + struct list_head temp_shmem_list; + struct list_head inactive_persist_shmem_list; + struct list_head persist_shmem_list; +}; + +struct tlk_context { + struct tlk_device *dev; + struct list_head session_list; +}; + +enum { + /* Trusted Application Calls */ + TE_SMC_OPEN_SESSION = 0x70000001, + TE_SMC_CLOSE_SESSION = 0x70000002, + TE_SMC_LAUNCH_OPERATION = 0x70000003, + TE_SMC_TA_EVENT = 0x70000004, + + /* Trusted OS (64-bit) calls */ + TE_SMC_REGISTER_REQ_BUF = 0x72000001, + TE_SMC_INIT_LOGGER = 0x72000002, + TE_SMC_RESTART = 0x72000100, + + /* SIP (SOC specific) calls. */ + TE_SMC_PROGRAM_VPR = 0x82000003, + TE_SMC_REGISTER_FIQ_GLUE = 0x82000005, + TE_SMC_VRR_SET_BUF = 0x82000011, + TE_SMC_VRR_SEC = 0x82000012, +}; + +enum { + TE_PARAM_TYPE_NONE = 0x0, + TE_PARAM_TYPE_INT_RO = 0x1, + TE_PARAM_TYPE_INT_RW = 0x2, + TE_PARAM_TYPE_MEM_RO = 0x3, + TE_PARAM_TYPE_MEM_RW = 0x4, + TE_PARAM_TYPE_PERSIST_MEM_RO = 0x100, + TE_PARAM_TYPE_PERSIST_MEM_RW = 0x101, + TE_PARAM_TYPE_FLAGS_PHYS_LIST = 0x1000, + TE_PARAM_TYPE_ALL_FLAGS = TE_PARAM_TYPE_FLAGS_PHYS_LIST +}; + +enum { + TE_MEM_TYPE_NS_USER = 0x0, + TE_MEM_TYPE_NS_KERNEL = 0x1, +}; + +struct te_oper_param { + uint32_t index; + uint32_t type; + union { + struct { + uint32_t val; + } Int; + struct { + uint64_t base; + uint32_t len; + uint32_t type; + } Mem; + } u; + uint64_t next_ptr_user; +}; + +struct te_request { + uint32_t type; + uint32_t session_id; + uint32_t command_id; + uint64_t params; + uint32_t params_size; + uint32_t dest_uuid[4]; + uint32_t result; + uint32_t result_origin; +}; + +struct te_answer { + uint32_t result; + uint32_t session_id; + uint32_t result_origin; +}; + +void te_open_session(struct te_opensession *cmd, + struct te_request *request, + struct tlk_context *context); + +void te_close_session(struct te_closesession *cmd, + struct te_request *request, + struct tlk_context *context); + +void te_launch_operation(struct te_launchop *cmd, + struct te_request *request, + struct tlk_context *context); + +enum ta_event_id { + TA_EVENT_RESTORE_KEYS = 0, + + TA_EVENT_MASK = (1 << TA_EVENT_RESTORE_KEYS), +}; + +int te_handle_ss_ioctl(struct file *file, unsigned int ioctl_num, + unsigned long ioctl_param); +void ote_print_logs(void); +int tlk_ss_op(void); +int ote_property_is_disabled(const char *str); +int te_prep_mem_buffers(struct te_request *request, + struct te_session *session); +void te_release_mem_buffers(struct list_head *buflist); +void te_activate_persist_mem_buffers(struct te_session *session); + +#endif diff --git a/security/tlk_driver/ote_types.h b/security/tlk_driver/ote_types.h new file mode 100644 index 000000000000..593400f7a03a --- /dev/null +++ b/security/tlk_driver/ote_types.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 NVIDIA Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __OTE_TYPES_H__ +#define __OTE_TYPES_H__ + +/* + * Return Codes + */ +enum { + /* Success */ + OTE_SUCCESS = 0x00000000, + OTE_ERROR_NO_ERROR = OTE_SUCCESS, + /* Non-specific cause */ + OTE_ERROR_GENERIC = 0xFFFF0000, + /* Access priviledge not sufficient */ + OTE_ERROR_ACCESS_DENIED = 0xFFFF0001, + /* The operation was cancelled */ + OTE_ERROR_CANCEL = 0xFFFF0002, + /* Concurrent accesses conflict */ + OTE_ERROR_ACCESS_CONFLICT = 0xFFFF0003, + /* Too much data for req was passed */ + OTE_ERROR_EXCESS_DATA = 0xFFFF0004, + /* Input data was of invalid format */ + OTE_ERROR_BAD_FORMAT = 0xFFFF0005, + /* Input parameters were invalid */ + OTE_ERROR_BAD_PARAMETERS = 0xFFFF0006, + /* Oper invalid in current state */ + OTE_ERROR_BAD_STATE = 0xFFFF0007, + /* The req data item not found */ + OTE_ERROR_ITEM_NOT_FOUND = 0xFFFF0008, + /* The req oper not implemented */ + OTE_ERROR_NOT_IMPLEMENTED = 0xFFFF0009, + /* The req oper not supported */ + OTE_ERROR_NOT_SUPPORTED = 0xFFFF000A, + /* Expected data was missing */ + OTE_ERROR_NO_DATA = 0xFFFF000B, + /* System ran out of resources */ + OTE_ERROR_OUT_OF_MEMORY = 0xFFFF000C, + /* The system is busy */ + OTE_ERROR_BUSY = 0xFFFF000D, + /* Communication failed */ + OTE_ERROR_COMMUNICATION = 0xFFFF000E, + /* A security fault was detected */ + OTE_ERROR_SECURITY = 0xFFFF000F, + /* The supplied buffer is too short */ + OTE_ERROR_SHORT_BUFFER = 0xFFFF0010, +}; + +/* + * Return Code origins + */ +enum { + /* Originated from OTE Client API */ + OTE_RESULT_ORIGIN_API = 1, + /* Originated from Underlying Communication Stack */ + OTE_RESULT_ORIGIN_COMMS = 2, + /* Originated from Common OTE Code */ + OTE_RESULT_ORIGIN_KERNEL = 3, + /* Originated from Trusted APP Code */ + OTE_RESULT_ORIGIN_TRUSTED_APP = 4, +}; + +#endif