diff options
Diffstat (limited to 'drivers/tee/optee/core.c')
| -rw-r--r-- | drivers/tee/optee/core.c | 659 |
1 files changed, 147 insertions, 512 deletions
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 58169e519422..5b62139714ce 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -1,180 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015, Linaro Limited - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * + * Copyright (c) 2015-2021, Linaro Limited + * Copyright (c) 2016, EPAM Systems */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/arm-smccc.h> +#include <linux/crash_dump.h> #include <linux/errno.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> +#include <linux/rpmb.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/types.h> -#include <linux/uaccess.h> #include "optee_private.h" -#include "optee_smc.h" -#define DRIVER_NAME "optee" +struct blocking_notifier_head optee_rpmb_intf_added = + BLOCKING_NOTIFIER_INIT(optee_rpmb_intf_added); -#define OPTEE_SHM_NUM_PRIV_PAGES 1 - -/** - * optee_from_msg_param() - convert from OPTEE_MSG parameters to - * struct tee_param - * @params: subsystem internal parameter representation - * @num_params: number of elements in the parameter arrays - * @msg_params: OPTEE_MSG parameters - * Returns 0 on success or <0 on failure - */ -int optee_from_msg_param(struct tee_param *params, size_t num_params, - const struct optee_msg_param *msg_params) +static int rpmb_add_dev(struct device *dev) { - int rc; - size_t n; - struct tee_shm *shm; - phys_addr_t pa; - - for (n = 0; n < num_params; n++) { - struct tee_param *p = params + n; - const struct optee_msg_param *mp = msg_params + n; - u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK; - - switch (attr) { - case OPTEE_MSG_ATTR_TYPE_NONE: - p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; - memset(&p->u, 0, sizeof(p->u)); - break; - case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT: - case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT: - case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT: - p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT + - attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; - p->u.value.a = mp->u.value.a; - p->u.value.b = mp->u.value.b; - p->u.value.c = mp->u.value.c; - break; - case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT: - case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT: - case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT: - p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT + - attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; - p->u.memref.size = mp->u.tmem.size; - shm = (struct tee_shm *)(unsigned long) - mp->u.tmem.shm_ref; - if (!shm) { - p->u.memref.shm_offs = 0; - p->u.memref.shm = NULL; - break; - } - rc = tee_shm_get_pa(shm, 0, &pa); - if (rc) - return rc; - p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa; - p->u.memref.shm = shm; - - /* Check that the memref is covered by the shm object */ - if (p->u.memref.size) { - size_t o = p->u.memref.shm_offs + - p->u.memref.size - 1; - - rc = tee_shm_get_pa(shm, o, NULL); - if (rc) - return rc; - } - break; - default: - return -EINVAL; - } - } + blocking_notifier_call_chain(&optee_rpmb_intf_added, 0, + to_rpmb_dev(dev)); + return 0; } -/** - * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters - * @msg_params: OPTEE_MSG parameters - * @num_params: number of elements in the parameter arrays - * @params: subsystem itnernal parameter representation - * Returns 0 on success or <0 on failure - */ -int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params, - const struct tee_param *params) +static struct class_interface rpmb_class_intf = { + .add_dev = rpmb_add_dev, +}; + +void optee_bus_scan_rpmb(struct work_struct *work) { - int rc; - size_t n; - phys_addr_t pa; - - for (n = 0; n < num_params; n++) { - const struct tee_param *p = params + n; - struct optee_msg_param *mp = msg_params + n; - - switch (p->attr) { - case TEE_IOCTL_PARAM_ATTR_TYPE_NONE: - mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; - memset(&mp->u, 0, sizeof(mp->u)); - break; - case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT: - case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT: - case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT: - mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr - - TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; - mp->u.value.a = p->u.value.a; - mp->u.value.b = p->u.value.b; - mp->u.value.c = p->u.value.c; - break; - case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: - case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: - case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: - mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + - p->attr - - TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; - mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm; - mp->u.tmem.size = p->u.memref.size; - if (!p->u.memref.shm) { - mp->u.tmem.buf_ptr = 0; - break; - } - rc = tee_shm_get_pa(p->u.memref.shm, - p->u.memref.shm_offs, &pa); - if (rc) - return rc; - mp->u.tmem.buf_ptr = pa; - mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED << - OPTEE_MSG_ATTR_CACHE_SHIFT; - break; - default: - return -EINVAL; - } + struct optee *optee = container_of(work, struct optee, + rpmb_scan_bus_work); + int ret; + + if (!optee->rpmb_scan_bus_done) { + ret = optee_enumerate_devices(PTA_CMD_GET_DEVICES_RPMB); + optee->rpmb_scan_bus_done = !ret; + if (ret && ret != -ENODEV) + pr_info("Scanning for RPMB device: ret %d\n", ret); } +} + +int optee_rpmb_intf_rdev(struct notifier_block *intf, unsigned long action, + void *data) +{ + struct optee *optee = container_of(intf, struct optee, rpmb_intf); + + schedule_work(&optee->rpmb_scan_bus_work); + return 0; } -static void optee_get_version(struct tee_device *teedev, - struct tee_ioctl_version_data *vers) +int optee_set_dma_mask(struct optee *optee, u_int pa_width) { - struct tee_ioctl_version_data v = { - .impl_id = TEE_IMPL_ID_OPTEE, - .impl_caps = TEE_OPTEE_CAP_TZ, - .gen_caps = TEE_GEN_CAP_GP, - }; - *vers = v; + u64 mask = DMA_BIT_MASK(min(64, pa_width)); + + return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask); +} + +static void optee_bus_scan(struct work_struct *work) +{ + WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP)); +} + +static ssize_t rpmb_routing_model_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct optee *optee = dev_get_drvdata(dev); + const char *s; + + if (optee->in_kernel_rpmb_routing) + s = "kernel"; + else + s = "user"; + + return sysfs_emit(buf, "%s\n", s); +} +static DEVICE_ATTR_RO(rpmb_routing_model); + +static struct attribute *optee_dev_attrs[] = { + &dev_attr_rpmb_routing_model.attr, + NULL +}; + +ATTRIBUTE_GROUPS(optee_dev); + +void optee_set_dev_group(struct optee *optee) +{ + tee_device_set_dev_groups(optee->teedev, optee_dev_groups); + tee_device_set_dev_groups(optee->supp_teedev, optee_dev_groups); } -static int optee_open(struct tee_context *ctx) +int optee_open(struct tee_context *ctx, bool cap_memref_null) { struct optee_context_data *ctxdata; struct tee_device *teedev = ctx->teedev; @@ -187,436 +109,149 @@ static int optee_open(struct tee_context *ctx) if (teedev == optee->supp_teedev) { bool busy = true; - mutex_lock(&optee->supp.ctx_mutex); + mutex_lock(&optee->supp.mutex); if (!optee->supp.ctx) { busy = false; optee->supp.ctx = ctx; } - mutex_unlock(&optee->supp.ctx_mutex); + mutex_unlock(&optee->supp.mutex); if (busy) { kfree(ctxdata); return -EBUSY; } - } + if (!optee->scan_bus_done) { + INIT_WORK(&optee->scan_bus_work, optee_bus_scan); + schedule_work(&optee->scan_bus_work); + optee->scan_bus_done = true; + } + } mutex_init(&ctxdata->mutex); INIT_LIST_HEAD(&ctxdata->sess_list); + ctx->cap_memref_null = cap_memref_null; ctx->data = ctxdata; return 0; } -static void optee_release(struct tee_context *ctx) +static void optee_release_helper(struct tee_context *ctx, + int (*close_session)(struct tee_context *ctx, + u32 session, + bool system_thread)) { struct optee_context_data *ctxdata = ctx->data; - struct tee_device *teedev = ctx->teedev; - struct optee *optee = tee_get_drvdata(teedev); - struct tee_shm *shm; - struct optee_msg_arg *arg = NULL; - phys_addr_t parg; struct optee_session *sess; struct optee_session *sess_tmp; if (!ctxdata) return; - shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), TEE_SHM_MAPPED); - if (!IS_ERR(shm)) { - arg = tee_shm_get_va(shm, 0); - /* - * If va2pa fails for some reason, we can't call - * optee_close_session(), only free the memory. Secure OS - * will leak sessions and finally refuse more sessions, but - * we will at least let normal world reclaim its memory. - */ - if (!IS_ERR(arg)) - tee_shm_va2pa(shm, arg, &parg); - } - list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list, list_node) { list_del(&sess->list_node); - if (!IS_ERR_OR_NULL(arg)) { - memset(arg, 0, sizeof(*arg)); - arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION; - arg->session = sess->session_id; - optee_do_call_with_arg(ctx, parg); - } + close_session(ctx, sess->session_id, sess->use_sys_thread); kfree(sess); } kfree(ctxdata); - - if (!IS_ERR(shm)) - tee_shm_free(shm); - ctx->data = NULL; - - if (teedev == optee->supp_teedev) { - mutex_lock(&optee->supp.ctx_mutex); - optee->supp.ctx = NULL; - mutex_unlock(&optee->supp.ctx_mutex); - } -} - -static struct tee_driver_ops optee_ops = { - .get_version = optee_get_version, - .open = optee_open, - .release = optee_release, - .open_session = optee_open_session, - .close_session = optee_close_session, - .invoke_func = optee_invoke_func, - .cancel_req = optee_cancel_req, -}; - -static struct tee_desc optee_desc = { - .name = DRIVER_NAME "-clnt", - .ops = &optee_ops, - .owner = THIS_MODULE, -}; - -static struct tee_driver_ops optee_supp_ops = { - .get_version = optee_get_version, - .open = optee_open, - .release = optee_release, - .supp_recv = optee_supp_recv, - .supp_send = optee_supp_send, -}; - -static struct tee_desc optee_supp_desc = { - .name = DRIVER_NAME "-supp", - .ops = &optee_supp_ops, - .owner = THIS_MODULE, - .flags = TEE_DESC_PRIVILEGED, -}; - -static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn) -{ - struct arm_smccc_res res; - - invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res); - - if (res.a0 == OPTEE_MSG_UID_0 && res.a1 == OPTEE_MSG_UID_1 && - res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3) - return true; - return false; -} - -static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn) -{ - union { - struct arm_smccc_res smccc; - struct optee_smc_calls_revision_result result; - } res; - - invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc); - - if (res.result.major == OPTEE_MSG_REVISION_MAJOR && - (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR) - return true; - return false; -} - -static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn, - u32 *sec_caps) -{ - union { - struct arm_smccc_res smccc; - struct optee_smc_exchange_capabilities_result result; - } res; - u32 a1 = 0; - - /* - * TODO This isn't enough to tell if it's UP system (from kernel - * point of view) or not, is_smp() returns the the information - * needed, but can't be called directly from here. - */ - if (!IS_ENABLED(CONFIG_SMP) || nr_cpu_ids == 1) - a1 |= OPTEE_SMC_NSEC_CAP_UNIPROCESSOR; - - invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0, - &res.smccc); - - if (res.result.status != OPTEE_SMC_RETURN_OK) - return false; - - *sec_caps = res.result.capabilities; - return true; -} - -static struct tee_shm_pool * -optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm) -{ - union { - struct arm_smccc_res smccc; - struct optee_smc_get_shm_config_result result; - } res; - struct tee_shm_pool *pool; - unsigned long vaddr; - phys_addr_t paddr; - size_t size; - phys_addr_t begin; - phys_addr_t end; - void *va; - struct tee_shm_pool_mem_info priv_info; - struct tee_shm_pool_mem_info dmabuf_info; - - invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc); - if (res.result.status != OPTEE_SMC_RETURN_OK) { - pr_info("shm service not available\n"); - return ERR_PTR(-ENOENT); - } - - if (res.result.settings != OPTEE_SMC_SHM_CACHED) { - pr_err("only normal cached shared memory supported\n"); - return ERR_PTR(-EINVAL); - } - - begin = roundup(res.result.start, PAGE_SIZE); - end = rounddown(res.result.start + res.result.size, PAGE_SIZE); - paddr = begin; - size = end - begin; - - if (size < 2 * OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE) { - pr_err("too small shared memory area\n"); - return ERR_PTR(-EINVAL); - } - - va = memremap(paddr, size, MEMREMAP_WB); - if (!va) { - pr_err("shared memory ioremap failed\n"); - return ERR_PTR(-EINVAL); - } - vaddr = (unsigned long)va; - - priv_info.vaddr = vaddr; - priv_info.paddr = paddr; - priv_info.size = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; - dmabuf_info.vaddr = vaddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; - dmabuf_info.paddr = paddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; - dmabuf_info.size = size - OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; - - pool = tee_shm_pool_alloc_res_mem(&priv_info, &dmabuf_info); - if (IS_ERR(pool)) { - memunmap(va); - goto out; - } - - *memremaped_shm = va; -out: - return pool; -} - -/* Simple wrapper functions to be able to use a function pointer */ -static void optee_smccc_smc(unsigned long a0, unsigned long a1, - unsigned long a2, unsigned long a3, - unsigned long a4, unsigned long a5, - unsigned long a6, unsigned long a7, - struct arm_smccc_res *res) -{ - arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res); -} - -static void optee_smccc_hvc(unsigned long a0, unsigned long a1, - unsigned long a2, unsigned long a3, - unsigned long a4, unsigned long a5, - unsigned long a6, unsigned long a7, - struct arm_smccc_res *res) -{ - arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res); } -static optee_invoke_fn *get_invoke_func(struct device_node *np) +void optee_release(struct tee_context *ctx) { - const char *method; - - pr_info("probing for conduit method from DT.\n"); - - if (of_property_read_string(np, "method", &method)) { - pr_warn("missing \"method\" property\n"); - return ERR_PTR(-ENXIO); - } - - if (!strcmp("hvc", method)) - return optee_smccc_hvc; - else if (!strcmp("smc", method)) - return optee_smccc_smc; - - pr_warn("invalid \"method\" property: %s\n", method); - return ERR_PTR(-EINVAL); + optee_release_helper(ctx, optee_close_session_helper); } -static struct optee *optee_probe(struct device_node *np) +void optee_release_supp(struct tee_context *ctx) { - optee_invoke_fn *invoke_fn; - struct tee_shm_pool *pool; - struct optee *optee = NULL; - void *memremaped_shm = NULL; - struct tee_device *teedev; - u32 sec_caps; - int rc; + struct optee *optee = tee_get_drvdata(ctx->teedev); - invoke_fn = get_invoke_func(np); - if (IS_ERR(invoke_fn)) - return (void *)invoke_fn; + optee_release_helper(ctx, optee_close_session_helper); - if (!optee_msg_api_uid_is_optee_api(invoke_fn)) { - pr_warn("api uid mismatch\n"); - return ERR_PTR(-EINVAL); - } - - if (!optee_msg_api_revision_is_compatible(invoke_fn)) { - pr_warn("api revision mismatch\n"); - return ERR_PTR(-EINVAL); - } - - if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) { - pr_warn("capabilities mismatch\n"); - return ERR_PTR(-EINVAL); - } - - /* - * We have no other option for shared memory, if secure world - * doesn't have any reserved memory we can use we can't continue. - */ - if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) - return ERR_PTR(-EINVAL); - - pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm); - if (IS_ERR(pool)) - return (void *)pool; - - optee = kzalloc(sizeof(*optee), GFP_KERNEL); - if (!optee) { - rc = -ENOMEM; - goto err; - } - - optee->invoke_fn = invoke_fn; - - teedev = tee_device_alloc(&optee_desc, NULL, pool, optee); - if (IS_ERR(teedev)) { - rc = PTR_ERR(teedev); - goto err; - } - optee->teedev = teedev; - - teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee); - if (IS_ERR(teedev)) { - rc = PTR_ERR(teedev); - goto err; - } - optee->supp_teedev = teedev; - - rc = tee_device_register(optee->teedev); - if (rc) - goto err; - - rc = tee_device_register(optee->supp_teedev); - if (rc) - goto err; - - mutex_init(&optee->call_queue.mutex); - INIT_LIST_HEAD(&optee->call_queue.waiters); - optee_wait_queue_init(&optee->wait_queue); - optee_supp_init(&optee->supp); - optee->memremaped_shm = memremaped_shm; - optee->pool = pool; - - optee_enable_shm_cache(optee); - - pr_info("initialized driver\n"); - return optee; -err: - if (optee) { - /* - * tee_device_unregister() is safe to call even if the - * devices hasn't been registered with - * tee_device_register() yet. - */ - tee_device_unregister(optee->supp_teedev); - tee_device_unregister(optee->teedev); - kfree(optee); - } - if (pool) - tee_shm_pool_free(pool); - if (memremaped_shm) - memunmap(memremaped_shm); - return ERR_PTR(rc); + optee_supp_release(&optee->supp); } -static void optee_remove(struct optee *optee) +void optee_remove_common(struct optee *optee) { + blocking_notifier_chain_unregister(&optee_rpmb_intf_added, + &optee->rpmb_intf); + cancel_work_sync(&optee->rpmb_scan_bus_work); + /* Unregister OP-TEE specific client devices on TEE bus */ + optee_unregister_devices(); + + optee_notif_uninit(optee); + optee_shm_arg_cache_uninit(optee); + teedev_close_context(optee->ctx); /* - * Ask OP-TEE to free all cached shared memory objects to decrease - * reference counters and also avoid wild pointers in secure world - * into the old shared memory range. - */ - optee_disable_shm_cache(optee); - - /* - * The two devices has to be unregistered before we can free the + * The two devices have to be unregistered before we can free the * other resources. */ tee_device_unregister(optee->supp_teedev); tee_device_unregister(optee->teedev); tee_shm_pool_free(optee->pool); - if (optee->memremaped_shm) - memunmap(optee->memremaped_shm); - optee_wait_queue_exit(&optee->wait_queue); optee_supp_uninit(&optee->supp); mutex_destroy(&optee->call_queue.mutex); - - kfree(optee); + rpmb_dev_put(optee->rpmb_dev); + mutex_destroy(&optee->rpmb_dev_mutex); } -static const struct of_device_id optee_match[] = { - { .compatible = "linaro,optee-tz" }, - {}, -}; - -static struct optee *optee_svc; +static int smc_abi_rc; +static int ffa_abi_rc; +static bool intf_is_regged; -static int __init optee_driver_init(void) +static int __init optee_core_init(void) { - struct device_node *fw_np; - struct device_node *np; - struct optee *optee; - - /* Node is supposed to be below /firmware */ - fw_np = of_find_node_by_name(NULL, "firmware"); - if (!fw_np) - return -ENODEV; + int rc; - np = of_find_matching_node(fw_np, optee_match); - of_node_put(fw_np); - if (!np) + /* + * The kernel may have crashed at the same time that all available + * secure world threads were suspended and we cannot reschedule the + * suspended threads without access to the crashed kernel's wait_queue. + * Therefore, we cannot reliably initialize the OP-TEE driver in the + * kdump kernel. + */ + if (is_kdump_kernel()) return -ENODEV; - optee = optee_probe(np); - of_node_put(np); + if (IS_REACHABLE(CONFIG_RPMB)) { + rc = rpmb_interface_register(&rpmb_class_intf); + if (rc) + return rc; + intf_is_regged = true; + } - if (IS_ERR(optee)) - return PTR_ERR(optee); + smc_abi_rc = optee_smc_abi_register(); + ffa_abi_rc = optee_ffa_abi_register(); - optee_svc = optee; + /* If both failed there's no point with this module */ + if (smc_abi_rc && ffa_abi_rc) { + if (IS_REACHABLE(CONFIG_RPMB)) { + rpmb_interface_unregister(&rpmb_class_intf); + intf_is_regged = false; + } + return smc_abi_rc; + } return 0; } -module_init(optee_driver_init); +module_init(optee_core_init); -static void __exit optee_driver_exit(void) +static void __exit optee_core_exit(void) { - struct optee *optee = optee_svc; + if (IS_REACHABLE(CONFIG_RPMB) && intf_is_regged) { + rpmb_interface_unregister(&rpmb_class_intf); + intf_is_regged = false; + } - optee_svc = NULL; - if (optee) - optee_remove(optee); + if (!smc_abi_rc) + optee_smc_abi_unregister(); + if (!ffa_abi_rc) + optee_ffa_abi_unregister(); } -module_exit(optee_driver_exit); +module_exit(optee_core_exit); MODULE_AUTHOR("Linaro"); MODULE_DESCRIPTION("OP-TEE driver"); -MODULE_SUPPORTED_DEVICE(""); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:optee"); |
