463 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2015-2021, Linaro Limited4 */5 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt7 8#include <linux/delay.h>9#include <linux/i2c.h>10#include <linux/rpmb.h>11#include <linux/slab.h>12#include <linux/tee_core.h>13#include "optee_private.h"14#include "optee_rpc_cmd.h"15 16static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg)17{18 struct timespec64 ts;19 20 if (arg->num_params != 1)21 goto bad;22 if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=23 OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT)24 goto bad;25 26 ktime_get_real_ts64(&ts);27 arg->params[0].u.value.a = ts.tv_sec;28 arg->params[0].u.value.b = ts.tv_nsec;29 30 arg->ret = TEEC_SUCCESS;31 return;32bad:33 arg->ret = TEEC_ERROR_BAD_PARAMETERS;34}35 36#if IS_REACHABLE(CONFIG_I2C)37static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,38 struct optee_msg_arg *arg)39{40 struct optee *optee = tee_get_drvdata(ctx->teedev);41 struct tee_param *params;42 struct i2c_adapter *adapter;43 struct i2c_msg msg = { };44 size_t i;45 int ret = -EOPNOTSUPP;46 u8 attr[] = {47 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,48 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,49 TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,50 TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT,51 };52 53 if (arg->num_params != ARRAY_SIZE(attr)) {54 arg->ret = TEEC_ERROR_BAD_PARAMETERS;55 return;56 }57 58 params = kmalloc_array(arg->num_params, sizeof(struct tee_param),59 GFP_KERNEL);60 if (!params) {61 arg->ret = TEEC_ERROR_OUT_OF_MEMORY;62 return;63 }64 65 if (optee->ops->from_msg_param(optee, params, arg->num_params,66 arg->params))67 goto bad;68 69 for (i = 0; i < arg->num_params; i++) {70 if (params[i].attr != attr[i])71 goto bad;72 }73 74 adapter = i2c_get_adapter(params[0].u.value.b);75 if (!adapter)76 goto bad;77 78 if (params[1].u.value.a & OPTEE_RPC_I2C_FLAGS_TEN_BIT) {79 if (!i2c_check_functionality(adapter,80 I2C_FUNC_10BIT_ADDR)) {81 i2c_put_adapter(adapter);82 goto bad;83 }84 85 msg.flags = I2C_M_TEN;86 }87 88 msg.addr = params[0].u.value.c;89 msg.buf = params[2].u.memref.shm->kaddr;90 msg.len = params[2].u.memref.size;91 92 switch (params[0].u.value.a) {93 case OPTEE_RPC_I2C_TRANSFER_RD:94 msg.flags |= I2C_M_RD;95 break;96 case OPTEE_RPC_I2C_TRANSFER_WR:97 break;98 default:99 i2c_put_adapter(adapter);100 goto bad;101 }102 103 ret = i2c_transfer(adapter, &msg, 1);104 105 if (ret < 0) {106 arg->ret = TEEC_ERROR_COMMUNICATION;107 } else {108 params[3].u.value.a = msg.len;109 if (optee->ops->to_msg_param(optee, arg->params,110 arg->num_params, params))111 arg->ret = TEEC_ERROR_BAD_PARAMETERS;112 else113 arg->ret = TEEC_SUCCESS;114 }115 116 i2c_put_adapter(adapter);117 kfree(params);118 return;119bad:120 kfree(params);121 arg->ret = TEEC_ERROR_BAD_PARAMETERS;122}123#else124static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx,125 struct optee_msg_arg *arg)126{127 arg->ret = TEEC_ERROR_NOT_SUPPORTED;128}129#endif130 131static void handle_rpc_func_cmd_wq(struct optee *optee,132 struct optee_msg_arg *arg)133{134 int rc = 0;135 136 if (arg->num_params != 1)137 goto bad;138 139 if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=140 OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)141 goto bad;142 143 switch (arg->params[0].u.value.a) {144 case OPTEE_RPC_NOTIFICATION_WAIT:145 rc = optee_notif_wait(optee, arg->params[0].u.value.b, arg->params[0].u.value.c);146 if (rc)147 goto bad;148 break;149 case OPTEE_RPC_NOTIFICATION_SEND:150 if (optee_notif_send(optee, arg->params[0].u.value.b))151 goto bad;152 break;153 default:154 goto bad;155 }156 157 arg->ret = TEEC_SUCCESS;158 return;159bad:160 if (rc == -ETIMEDOUT)161 arg->ret = TEE_ERROR_TIMEOUT;162 else163 arg->ret = TEEC_ERROR_BAD_PARAMETERS;164}165 166static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg)167{168 u32 msec_to_wait;169 170 if (arg->num_params != 1)171 goto bad;172 173 if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=174 OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)175 goto bad;176 177 msec_to_wait = arg->params[0].u.value.a;178 179 /* Go to interruptible sleep */180 msleep_interruptible(msec_to_wait);181 182 arg->ret = TEEC_SUCCESS;183 return;184bad:185 arg->ret = TEEC_ERROR_BAD_PARAMETERS;186}187 188static void handle_rpc_supp_cmd(struct tee_context *ctx, struct optee *optee,189 struct optee_msg_arg *arg)190{191 struct tee_param *params;192 193 arg->ret_origin = TEEC_ORIGIN_COMMS;194 195 params = kmalloc_array(arg->num_params, sizeof(struct tee_param),196 GFP_KERNEL);197 if (!params) {198 arg->ret = TEEC_ERROR_OUT_OF_MEMORY;199 return;200 }201 202 if (optee->ops->from_msg_param(optee, params, arg->num_params,203 arg->params)) {204 arg->ret = TEEC_ERROR_BAD_PARAMETERS;205 goto out;206 }207 208 arg->ret = optee_supp_thrd_req(ctx, arg->cmd, arg->num_params, params);209 210 if (optee->ops->to_msg_param(optee, arg->params, arg->num_params,211 params))212 arg->ret = TEEC_ERROR_BAD_PARAMETERS;213out:214 kfree(params);215}216 217struct tee_shm *optee_rpc_cmd_alloc_suppl(struct tee_context *ctx, size_t sz)218{219 u32 ret;220 struct tee_param param;221 struct optee *optee = tee_get_drvdata(ctx->teedev);222 struct tee_shm *shm;223 224 param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;225 param.u.value.a = OPTEE_RPC_SHM_TYPE_APPL;226 param.u.value.b = sz;227 param.u.value.c = 0;228 229 ret = optee_supp_thrd_req(ctx, OPTEE_RPC_CMD_SHM_ALLOC, 1, ¶m);230 if (ret)231 return ERR_PTR(-ENOMEM);232 233 mutex_lock(&optee->supp.mutex);234 /* Increases count as secure world doesn't have a reference */235 shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c);236 mutex_unlock(&optee->supp.mutex);237 return shm;238}239 240void optee_rpc_cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)241{242 struct tee_param param;243 244 param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;245 param.u.value.a = OPTEE_RPC_SHM_TYPE_APPL;246 param.u.value.b = tee_shm_get_id(shm);247 param.u.value.c = 0;248 249 /*250 * Match the tee_shm_get_from_id() in cmd_alloc_suppl() as secure251 * world has released its reference.252 *253 * It's better to do this before sending the request to supplicant254 * as we'd like to let the process doing the initial allocation to255 * do release the last reference too in order to avoid stacking256 * many pending fput() on the client process. This could otherwise257 * happen if secure world does many allocate and free in a single258 * invoke.259 */260 tee_shm_put(shm);261 262 optee_supp_thrd_req(ctx, OPTEE_RPC_CMD_SHM_FREE, 1, ¶m);263}264 265static void handle_rpc_func_rpmb_probe_reset(struct tee_context *ctx,266 struct optee *optee,267 struct optee_msg_arg *arg)268{269 struct tee_param params[1];270 271 if (arg->num_params != ARRAY_SIZE(params) ||272 optee->ops->from_msg_param(optee, params, arg->num_params,273 arg->params) ||274 params[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT) {275 arg->ret = TEEC_ERROR_BAD_PARAMETERS;276 return;277 }278 279 params[0].u.value.a = OPTEE_RPC_SHM_TYPE_KERNEL;280 params[0].u.value.b = 0;281 params[0].u.value.c = 0;282 if (optee->ops->to_msg_param(optee, arg->params,283 arg->num_params, params)) {284 arg->ret = TEEC_ERROR_BAD_PARAMETERS;285 return;286 }287 288 mutex_lock(&optee->rpmb_dev_mutex);289 rpmb_dev_put(optee->rpmb_dev);290 optee->rpmb_dev = NULL;291 mutex_unlock(&optee->rpmb_dev_mutex);292 293 arg->ret = TEEC_SUCCESS;294}295 296static int rpmb_type_to_rpc_type(enum rpmb_type rtype)297{298 switch (rtype) {299 case RPMB_TYPE_EMMC:300 return OPTEE_RPC_RPMB_EMMC;301 case RPMB_TYPE_UFS:302 return OPTEE_RPC_RPMB_UFS;303 case RPMB_TYPE_NVME:304 return OPTEE_RPC_RPMB_NVME;305 default:306 return -1;307 }308}309 310static int rpc_rpmb_match(struct device *dev, const void *data)311{312 struct rpmb_dev *rdev = to_rpmb_dev(dev);313 314 return rpmb_type_to_rpc_type(rdev->descr.type) >= 0;315}316 317static void handle_rpc_func_rpmb_probe_next(struct tee_context *ctx,318 struct optee *optee,319 struct optee_msg_arg *arg)320{321 struct rpmb_dev *rdev;322 struct tee_param params[2];323 void *buf;324 325 if (arg->num_params != ARRAY_SIZE(params) ||326 optee->ops->from_msg_param(optee, params, arg->num_params,327 arg->params) ||328 params[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT ||329 params[1].attr != TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT) {330 arg->ret = TEEC_ERROR_BAD_PARAMETERS;331 return;332 }333 buf = tee_shm_get_va(params[1].u.memref.shm,334 params[1].u.memref.shm_offs);335 if (IS_ERR(buf)) {336 arg->ret = TEEC_ERROR_BAD_PARAMETERS;337 return;338 }339 340 mutex_lock(&optee->rpmb_dev_mutex);341 rdev = rpmb_dev_find_device(NULL, optee->rpmb_dev, rpc_rpmb_match);342 rpmb_dev_put(optee->rpmb_dev);343 optee->rpmb_dev = rdev;344 mutex_unlock(&optee->rpmb_dev_mutex);345 346 if (!rdev) {347 arg->ret = TEEC_ERROR_ITEM_NOT_FOUND;348 return;349 }350 351 if (params[1].u.memref.size < rdev->descr.dev_id_len) {352 arg->ret = TEEC_ERROR_SHORT_BUFFER;353 return;354 }355 memcpy(buf, rdev->descr.dev_id, rdev->descr.dev_id_len);356 params[1].u.memref.size = rdev->descr.dev_id_len;357 params[0].u.value.a = rpmb_type_to_rpc_type(rdev->descr.type);358 params[0].u.value.b = rdev->descr.capacity;359 params[0].u.value.c = rdev->descr.reliable_wr_count;360 if (optee->ops->to_msg_param(optee, arg->params,361 arg->num_params, params)) {362 arg->ret = TEEC_ERROR_BAD_PARAMETERS;363 return;364 }365 366 arg->ret = TEEC_SUCCESS;367}368 369static void handle_rpc_func_rpmb_frames(struct tee_context *ctx,370 struct optee *optee,371 struct optee_msg_arg *arg)372{373 struct tee_param params[2];374 struct rpmb_dev *rdev;375 void *p0, *p1;376 377 mutex_lock(&optee->rpmb_dev_mutex);378 rdev = rpmb_dev_get(optee->rpmb_dev);379 mutex_unlock(&optee->rpmb_dev_mutex);380 if (!rdev) {381 arg->ret = TEEC_ERROR_ITEM_NOT_FOUND;382 return;383 }384 385 if (arg->num_params != ARRAY_SIZE(params) ||386 optee->ops->from_msg_param(optee, params, arg->num_params,387 arg->params) ||388 params[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||389 params[1].attr != TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT) {390 arg->ret = TEEC_ERROR_BAD_PARAMETERS;391 goto out;392 }393 394 p0 = tee_shm_get_va(params[0].u.memref.shm,395 params[0].u.memref.shm_offs);396 p1 = tee_shm_get_va(params[1].u.memref.shm,397 params[1].u.memref.shm_offs);398 if (rpmb_route_frames(rdev, p0, params[0].u.memref.size, p1,399 params[1].u.memref.size)) {400 arg->ret = TEEC_ERROR_BAD_PARAMETERS;401 goto out;402 }403 if (optee->ops->to_msg_param(optee, arg->params,404 arg->num_params, params)) {405 arg->ret = TEEC_ERROR_BAD_PARAMETERS;406 goto out;407 }408 arg->ret = TEEC_SUCCESS;409out:410 rpmb_dev_put(rdev);411}412 413void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee,414 struct optee_msg_arg *arg)415{416 switch (arg->cmd) {417 case OPTEE_RPC_CMD_GET_TIME:418 handle_rpc_func_cmd_get_time(arg);419 break;420 case OPTEE_RPC_CMD_NOTIFICATION:421 handle_rpc_func_cmd_wq(optee, arg);422 break;423 case OPTEE_RPC_CMD_SUSPEND:424 handle_rpc_func_cmd_wait(arg);425 break;426 case OPTEE_RPC_CMD_I2C_TRANSFER:427 handle_rpc_func_cmd_i2c_transfer(ctx, arg);428 break;429 /*430 * optee->in_kernel_rpmb_routing true means that OP-TEE supports431 * in-kernel RPMB routing _and_ that the RPMB subsystem is432 * reachable. This is reported to user space with433 * rpmb_routing_model=kernel in sysfs.434 *435 * rpmb_routing_model=kernel is also a promise to user space that436 * RPMB access will not require supplicant support, hence the437 * checks below.438 */439 case OPTEE_RPC_CMD_RPMB_PROBE_RESET:440 if (optee->in_kernel_rpmb_routing)441 handle_rpc_func_rpmb_probe_reset(ctx, optee, arg);442 else443 handle_rpc_supp_cmd(ctx, optee, arg);444 break;445 case OPTEE_RPC_CMD_RPMB_PROBE_NEXT:446 if (optee->in_kernel_rpmb_routing)447 handle_rpc_func_rpmb_probe_next(ctx, optee, arg);448 else449 handle_rpc_supp_cmd(ctx, optee, arg);450 break;451 case OPTEE_RPC_CMD_RPMB_FRAMES:452 if (optee->in_kernel_rpmb_routing)453 handle_rpc_func_rpmb_frames(ctx, optee, arg);454 else455 handle_rpc_supp_cmd(ctx, optee, arg);456 break;457 default:458 handle_rpc_supp_cmd(ctx, optee, arg);459 }460}461 462 463