brintos

brintos / linux-shallow public Read only

0
0
Text · 11.3 KiB · ebbbd42 Raw
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, &param);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, &param);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