summaryrefslogtreecommitdiff
path: root/drivers/tee/optee/rpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tee/optee/rpc.c')
-rw-r--r--drivers/tee/optee/rpc.c540
1 files changed, 275 insertions, 265 deletions
diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c
index b45c73dd37a5..ebbbd42b0e3e 100644
--- a/drivers/tee/optee/rpc.c
+++ b/drivers/tee/optee/rpc.c
@@ -1,42 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2015-2016, 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
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
-#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/rpmb.h>
#include <linux/slab.h>
-#include <linux/tee_drv.h>
+#include <linux/tee_core.h>
#include "optee_private.h"
-#include "optee_smc.h"
-
-struct wq_entry {
- struct list_head link;
- struct completion c;
- u32 key;
-};
-
-void optee_wait_queue_init(struct optee_wait_queue *priv)
-{
- mutex_init(&priv->mu);
- INIT_LIST_HEAD(&priv->db);
-}
-
-void optee_wait_queue_exit(struct optee_wait_queue *priv)
-{
- mutex_destroy(&priv->mu);
-}
+#include "optee_rpc_cmd.h"
static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg)
{
@@ -58,51 +33,106 @@ bad:
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
}
-static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key)
+#if IS_REACHABLE(CONFIG_I2C)
+static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
{
- struct wq_entry *w;
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct tee_param *params;
+ struct i2c_adapter *adapter;
+ struct i2c_msg msg = { };
+ size_t i;
+ int ret = -EOPNOTSUPP;
+ u8 attr[] = {
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT,
+ };
+
+ if (arg->num_params != ARRAY_SIZE(attr)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
- mutex_lock(&wq->mu);
+ params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params) {
+ arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+ return;
+ }
- list_for_each_entry(w, &wq->db, link)
- if (w->key == key)
- goto out;
+ if (optee->ops->from_msg_param(optee, params, arg->num_params,
+ arg->params))
+ goto bad;
- w = kmalloc(sizeof(*w), GFP_KERNEL);
- if (w) {
- init_completion(&w->c);
- w->key = key;
- list_add_tail(&w->link, &wq->db);
+ for (i = 0; i < arg->num_params; i++) {
+ if (params[i].attr != attr[i])
+ goto bad;
}
-out:
- mutex_unlock(&wq->mu);
- return w;
-}
-static void wq_sleep(struct optee_wait_queue *wq, u32 key)
-{
- struct wq_entry *w = wq_entry_get(wq, key);
-
- if (w) {
- wait_for_completion(&w->c);
- mutex_lock(&wq->mu);
- list_del(&w->link);
- mutex_unlock(&wq->mu);
- kfree(w);
+ adapter = i2c_get_adapter(params[0].u.value.b);
+ if (!adapter)
+ goto bad;
+
+ if (params[1].u.value.a & OPTEE_RPC_I2C_FLAGS_TEN_BIT) {
+ if (!i2c_check_functionality(adapter,
+ I2C_FUNC_10BIT_ADDR)) {
+ i2c_put_adapter(adapter);
+ goto bad;
+ }
+
+ msg.flags = I2C_M_TEN;
}
-}
-static void wq_wakeup(struct optee_wait_queue *wq, u32 key)
-{
- struct wq_entry *w = wq_entry_get(wq, key);
+ msg.addr = params[0].u.value.c;
+ msg.buf = params[2].u.memref.shm->kaddr;
+ msg.len = params[2].u.memref.size;
+
+ switch (params[0].u.value.a) {
+ case OPTEE_RPC_I2C_TRANSFER_RD:
+ msg.flags |= I2C_M_RD;
+ break;
+ case OPTEE_RPC_I2C_TRANSFER_WR:
+ break;
+ default:
+ i2c_put_adapter(adapter);
+ goto bad;
+ }
+
+ ret = i2c_transfer(adapter, &msg, 1);
+
+ if (ret < 0) {
+ arg->ret = TEEC_ERROR_COMMUNICATION;
+ } else {
+ params[3].u.value.a = msg.len;
+ if (optee->ops->to_msg_param(optee, arg->params,
+ arg->num_params, params))
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ else
+ arg->ret = TEEC_SUCCESS;
+ }
- if (w)
- complete(&w->c);
+ i2c_put_adapter(adapter);
+ kfree(params);
+ return;
+bad:
+ kfree(params);
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
}
+#else
+static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ arg->ret = TEEC_ERROR_NOT_SUPPORTED;
+}
+#endif
static void handle_rpc_func_cmd_wq(struct optee *optee,
struct optee_msg_arg *arg)
{
+ int rc = 0;
+
if (arg->num_params != 1)
goto bad;
@@ -111,11 +141,14 @@ static void handle_rpc_func_cmd_wq(struct optee *optee,
goto bad;
switch (arg->params[0].u.value.a) {
- case OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP:
- wq_sleep(&optee->wait_queue, arg->params[0].u.value.b);
+ case OPTEE_RPC_NOTIFICATION_WAIT:
+ rc = optee_notif_wait(optee, arg->params[0].u.value.b, arg->params[0].u.value.c);
+ if (rc)
+ goto bad;
break;
- case OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP:
- wq_wakeup(&optee->wait_queue, arg->params[0].u.value.b);
+ case OPTEE_RPC_NOTIFICATION_SEND:
+ if (optee_notif_send(optee, arg->params[0].u.value.b))
+ goto bad;
break;
default:
goto bad;
@@ -124,7 +157,10 @@ static void handle_rpc_func_cmd_wq(struct optee *optee,
arg->ret = TEEC_SUCCESS;
return;
bad:
- arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ if (rc == -ETIMEDOUT)
+ arg->ret = TEE_ERROR_TIMEOUT;
+ else
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
}
static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg)
@@ -149,7 +185,7 @@ bad:
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
}
-static void handle_rpc_supp_cmd(struct tee_context *ctx,
+static void handle_rpc_supp_cmd(struct tee_context *ctx, struct optee *optee,
struct optee_msg_arg *arg)
{
struct tee_param *params;
@@ -163,20 +199,22 @@ static void handle_rpc_supp_cmd(struct tee_context *ctx,
return;
}
- if (optee_from_msg_param(params, arg->num_params, arg->params)) {
+ if (optee->ops->from_msg_param(optee, params, arg->num_params,
+ arg->params)) {
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
goto out;
}
arg->ret = optee_supp_thrd_req(ctx, arg->cmd, arg->num_params, params);
- if (optee_to_msg_param(arg->params, arg->num_params, params))
+ if (optee->ops->to_msg_param(optee, arg->params, arg->num_params,
+ params))
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
out:
kfree(params);
}
-static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
+struct tee_shm *optee_rpc_cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
{
u32 ret;
struct tee_param param;
@@ -184,11 +222,11 @@ static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
struct tee_shm *shm;
param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
- param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
+ param.u.value.a = OPTEE_RPC_SHM_TYPE_APPL;
param.u.value.b = sz;
param.u.value.c = 0;
- ret = optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_ALLOC, 1, &param);
+ ret = optee_supp_thrd_req(ctx, OPTEE_RPC_CMD_SHM_ALLOC, 1, &param);
if (ret)
return ERR_PTR(-ENOMEM);
@@ -199,108 +237,12 @@ static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
return shm;
}
-static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
- struct optee_msg_arg *arg,
- struct optee_call_ctx *call_ctx)
-{
- phys_addr_t pa;
- struct tee_shm *shm;
- size_t sz;
- size_t n;
-
- arg->ret_origin = TEEC_ORIGIN_COMMS;
-
- if (!arg->num_params ||
- arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
- arg->ret = TEEC_ERROR_BAD_PARAMETERS;
- return;
- }
-
- for (n = 1; n < arg->num_params; n++) {
- if (arg->params[n].attr != OPTEE_MSG_ATTR_TYPE_NONE) {
- arg->ret = TEEC_ERROR_BAD_PARAMETERS;
- return;
- }
- }
-
- sz = arg->params[0].u.value.b;
- switch (arg->params[0].u.value.a) {
- case OPTEE_MSG_RPC_SHM_TYPE_APPL:
- shm = cmd_alloc_suppl(ctx, sz);
- break;
- case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
- shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED);
- break;
- default:
- arg->ret = TEEC_ERROR_BAD_PARAMETERS;
- return;
- }
-
- if (IS_ERR(shm)) {
- arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
- return;
- }
-
- if (tee_shm_get_pa(shm, 0, &pa)) {
- arg->ret = TEEC_ERROR_BAD_PARAMETERS;
- goto bad;
- }
-
- sz = tee_shm_get_size(shm);
-
- if (tee_shm_is_registered(shm)) {
- struct page **pages;
- u64 *pages_list;
- size_t page_num;
-
- pages = tee_shm_get_pages(shm, &page_num);
- if (!pages || !page_num) {
- arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
- goto bad;
- }
-
- pages_list = optee_allocate_pages_list(page_num);
- if (!pages_list) {
- arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
- goto bad;
- }
-
- call_ctx->pages_list = pages_list;
- call_ctx->num_entries = page_num;
-
- arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
- OPTEE_MSG_ATTR_NONCONTIG;
- /*
- * In the least bits of u.tmem.buf_ptr we store buffer offset
- * from 4k page, as described in OP-TEE ABI.
- */
- arg->params[0].u.tmem.buf_ptr = virt_to_phys(pages_list) |
- (tee_shm_get_page_offset(shm) &
- (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
- arg->params[0].u.tmem.size = tee_shm_get_size(shm);
- arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
-
- optee_fill_pages_list(pages_list, pages, page_num,
- tee_shm_get_page_offset(shm));
- } else {
- arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
- arg->params[0].u.tmem.buf_ptr = pa;
- arg->params[0].u.tmem.size = sz;
- arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
- }
-
- arg->ret = TEEC_SUCCESS;
- return;
-bad:
- tee_shm_free(shm);
-}
-
-static void cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
+void optee_rpc_cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
{
struct tee_param param;
param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
- param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
+ param.u.value.a = OPTEE_RPC_SHM_TYPE_APPL;
param.u.value.b = tee_shm_get_id(shm);
param.u.value.c = 0;
@@ -317,136 +259,204 @@ static void cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
*/
tee_shm_put(shm);
- optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_FREE, 1, &param);
+ optee_supp_thrd_req(ctx, OPTEE_RPC_CMD_SHM_FREE, 1, &param);
}
-static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
- struct optee_msg_arg *arg)
+static void handle_rpc_func_rpmb_probe_reset(struct tee_context *ctx,
+ struct optee *optee,
+ struct optee_msg_arg *arg)
{
- struct tee_shm *shm;
+ struct tee_param params[1];
- arg->ret_origin = TEEC_ORIGIN_COMMS;
-
- if (arg->num_params != 1 ||
- arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
+ if (arg->num_params != ARRAY_SIZE(params) ||
+ optee->ops->from_msg_param(optee, params, arg->num_params,
+ arg->params) ||
+ params[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT) {
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
return;
}
- shm = (struct tee_shm *)(unsigned long)arg->params[0].u.value.b;
- switch (arg->params[0].u.value.a) {
- case OPTEE_MSG_RPC_SHM_TYPE_APPL:
- cmd_free_suppl(ctx, shm);
- break;
- case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
- tee_shm_free(shm);
- break;
- default:
+ params[0].u.value.a = OPTEE_RPC_SHM_TYPE_KERNEL;
+ params[0].u.value.b = 0;
+ params[0].u.value.c = 0;
+ if (optee->ops->to_msg_param(optee, arg->params,
+ arg->num_params, params)) {
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
}
+
+ mutex_lock(&optee->rpmb_dev_mutex);
+ rpmb_dev_put(optee->rpmb_dev);
+ optee->rpmb_dev = NULL;
+ mutex_unlock(&optee->rpmb_dev_mutex);
+
arg->ret = TEEC_SUCCESS;
}
-static void free_pages_list(struct optee_call_ctx *call_ctx)
+static int rpmb_type_to_rpc_type(enum rpmb_type rtype)
{
- if (call_ctx->pages_list) {
- optee_free_pages_list(call_ctx->pages_list,
- call_ctx->num_entries);
- call_ctx->pages_list = NULL;
- call_ctx->num_entries = 0;
+ switch (rtype) {
+ case RPMB_TYPE_EMMC:
+ return OPTEE_RPC_RPMB_EMMC;
+ case RPMB_TYPE_UFS:
+ return OPTEE_RPC_RPMB_UFS;
+ case RPMB_TYPE_NVME:
+ return OPTEE_RPC_RPMB_NVME;
+ default:
+ return -1;
}
}
-void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx)
+static int rpc_rpmb_match(struct device *dev, const void *data)
{
- free_pages_list(call_ctx);
+ struct rpmb_dev *rdev = to_rpmb_dev(dev);
+
+ return rpmb_type_to_rpc_type(rdev->descr.type) >= 0;
}
-static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
- struct tee_shm *shm,
- struct optee_call_ctx *call_ctx)
+static void handle_rpc_func_rpmb_probe_next(struct tee_context *ctx,
+ struct optee *optee,
+ struct optee_msg_arg *arg)
{
- struct optee_msg_arg *arg;
+ struct rpmb_dev *rdev;
+ struct tee_param params[2];
+ void *buf;
+
+ if (arg->num_params != ARRAY_SIZE(params) ||
+ optee->ops->from_msg_param(optee, params, arg->num_params,
+ arg->params) ||
+ params[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT ||
+ params[1].attr != TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+ buf = tee_shm_get_va(params[1].u.memref.shm,
+ params[1].u.memref.shm_offs);
+ if (IS_ERR(buf)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ mutex_lock(&optee->rpmb_dev_mutex);
+ rdev = rpmb_dev_find_device(NULL, optee->rpmb_dev, rpc_rpmb_match);
+ rpmb_dev_put(optee->rpmb_dev);
+ optee->rpmb_dev = rdev;
+ mutex_unlock(&optee->rpmb_dev_mutex);
- arg = tee_shm_get_va(shm, 0);
- if (IS_ERR(arg)) {
- pr_err("%s: tee_shm_get_va %p failed\n", __func__, shm);
+ if (!rdev) {
+ arg->ret = TEEC_ERROR_ITEM_NOT_FOUND;
return;
}
+ if (params[1].u.memref.size < rdev->descr.dev_id_len) {
+ arg->ret = TEEC_ERROR_SHORT_BUFFER;
+ return;
+ }
+ memcpy(buf, rdev->descr.dev_id, rdev->descr.dev_id_len);
+ params[1].u.memref.size = rdev->descr.dev_id_len;
+ params[0].u.value.a = rpmb_type_to_rpc_type(rdev->descr.type);
+ params[0].u.value.b = rdev->descr.capacity;
+ params[0].u.value.c = rdev->descr.reliable_wr_count;
+ if (optee->ops->to_msg_param(optee, arg->params,
+ arg->num_params, params)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ arg->ret = TEEC_SUCCESS;
+}
+
+static void handle_rpc_func_rpmb_frames(struct tee_context *ctx,
+ struct optee *optee,
+ struct optee_msg_arg *arg)
+{
+ struct tee_param params[2];
+ struct rpmb_dev *rdev;
+ void *p0, *p1;
+
+ mutex_lock(&optee->rpmb_dev_mutex);
+ rdev = rpmb_dev_get(optee->rpmb_dev);
+ mutex_unlock(&optee->rpmb_dev_mutex);
+ if (!rdev) {
+ arg->ret = TEEC_ERROR_ITEM_NOT_FOUND;
+ return;
+ }
+
+ if (arg->num_params != ARRAY_SIZE(params) ||
+ optee->ops->from_msg_param(optee, params, arg->num_params,
+ arg->params) ||
+ params[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
+ params[1].attr != TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+
+ p0 = tee_shm_get_va(params[0].u.memref.shm,
+ params[0].u.memref.shm_offs);
+ p1 = tee_shm_get_va(params[1].u.memref.shm,
+ params[1].u.memref.shm_offs);
+ if (rpmb_route_frames(rdev, p0, params[0].u.memref.size, p1,
+ params[1].u.memref.size)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+ if (optee->ops->to_msg_param(optee, arg->params,
+ arg->num_params, params)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+ arg->ret = TEEC_SUCCESS;
+out:
+ rpmb_dev_put(rdev);
+}
+
+void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee,
+ struct optee_msg_arg *arg)
+{
switch (arg->cmd) {
- case OPTEE_MSG_RPC_CMD_GET_TIME:
+ case OPTEE_RPC_CMD_GET_TIME:
handle_rpc_func_cmd_get_time(arg);
break;
- case OPTEE_MSG_RPC_CMD_WAIT_QUEUE:
+ case OPTEE_RPC_CMD_NOTIFICATION:
handle_rpc_func_cmd_wq(optee, arg);
break;
- case OPTEE_MSG_RPC_CMD_SUSPEND:
+ case OPTEE_RPC_CMD_SUSPEND:
handle_rpc_func_cmd_wait(arg);
break;
- case OPTEE_MSG_RPC_CMD_SHM_ALLOC:
- free_pages_list(call_ctx);
- handle_rpc_func_cmd_shm_alloc(ctx, arg, call_ctx);
- break;
- case OPTEE_MSG_RPC_CMD_SHM_FREE:
- handle_rpc_func_cmd_shm_free(ctx, arg);
- break;
- default:
- handle_rpc_supp_cmd(ctx, arg);
- }
-}
-
-/**
- * optee_handle_rpc() - handle RPC from secure world
- * @ctx: context doing the RPC
- * @param: value of registers for the RPC
- * @call_ctx: call context. Preserved during one OP-TEE invocation
- *
- * Result of RPC is written back into @param.
- */
-void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param,
- struct optee_call_ctx *call_ctx)
-{
- struct tee_device *teedev = ctx->teedev;
- struct optee *optee = tee_get_drvdata(teedev);
- struct tee_shm *shm;
- phys_addr_t pa;
-
- switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
- case OPTEE_SMC_RPC_FUNC_ALLOC:
- shm = tee_shm_alloc(ctx, param->a1, TEE_SHM_MAPPED);
- if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
- reg_pair_from_64(&param->a1, &param->a2, pa);
- reg_pair_from_64(&param->a4, &param->a5,
- (unsigned long)shm);
- } else {
- param->a1 = 0;
- param->a2 = 0;
- param->a4 = 0;
- param->a5 = 0;
- }
+ case OPTEE_RPC_CMD_I2C_TRANSFER:
+ handle_rpc_func_cmd_i2c_transfer(ctx, arg);
break;
- case OPTEE_SMC_RPC_FUNC_FREE:
- shm = reg_pair_to_ptr(param->a1, param->a2);
- tee_shm_free(shm);
+ /*
+ * optee->in_kernel_rpmb_routing true means that OP-TEE supports
+ * in-kernel RPMB routing _and_ that the RPMB subsystem is
+ * reachable. This is reported to user space with
+ * rpmb_routing_model=kernel in sysfs.
+ *
+ * rpmb_routing_model=kernel is also a promise to user space that
+ * RPMB access will not require supplicant support, hence the
+ * checks below.
+ */
+ case OPTEE_RPC_CMD_RPMB_PROBE_RESET:
+ if (optee->in_kernel_rpmb_routing)
+ handle_rpc_func_rpmb_probe_reset(ctx, optee, arg);
+ else
+ handle_rpc_supp_cmd(ctx, optee, arg);
break;
- case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
- /*
- * A foreign interrupt was raised while secure world was
- * executing, since they are handled in Linux a dummy RPC is
- * performed to let Linux take the interrupt through the normal
- * vector.
- */
+ case OPTEE_RPC_CMD_RPMB_PROBE_NEXT:
+ if (optee->in_kernel_rpmb_routing)
+ handle_rpc_func_rpmb_probe_next(ctx, optee, arg);
+ else
+ handle_rpc_supp_cmd(ctx, optee, arg);
break;
- case OPTEE_SMC_RPC_FUNC_CMD:
- shm = reg_pair_to_ptr(param->a1, param->a2);
- handle_rpc_func_cmd(ctx, optee, shm, call_ctx);
+ case OPTEE_RPC_CMD_RPMB_FRAMES:
+ if (optee->in_kernel_rpmb_routing)
+ handle_rpc_func_rpmb_frames(ctx, optee, arg);
+ else
+ handle_rpc_supp_cmd(ctx, optee, arg);
break;
default:
- pr_warn("Unknown RPC func 0x%x\n",
- (u32)OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0));
- break;
+ handle_rpc_supp_cmd(ctx, optee, arg);
}
-
- param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
}
+
+