linux/drivers/tee/optee/rpc.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015-2016, Linaro Limited
   3 *
   4 * This software is licensed under the terms of the GNU General Public
   5 * License version 2, as published by the Free Software Foundation, and
   6 * may be copied, distributed, and modified under those terms.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 *
  13 */
  14
  15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  16
  17#include <linux/delay.h>
  18#include <linux/device.h>
  19#include <linux/slab.h>
  20#include <linux/tee_drv.h>
  21#include "optee_private.h"
  22#include "optee_smc.h"
  23
  24struct wq_entry {
  25        struct list_head link;
  26        struct completion c;
  27        u32 key;
  28};
  29
  30void optee_wait_queue_init(struct optee_wait_queue *priv)
  31{
  32        mutex_init(&priv->mu);
  33        INIT_LIST_HEAD(&priv->db);
  34}
  35
  36void optee_wait_queue_exit(struct optee_wait_queue *priv)
  37{
  38        mutex_destroy(&priv->mu);
  39}
  40
  41static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg)
  42{
  43        struct timespec64 ts;
  44
  45        if (arg->num_params != 1)
  46                goto bad;
  47        if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
  48                        OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT)
  49                goto bad;
  50
  51        getnstimeofday64(&ts);
  52        arg->params[0].u.value.a = ts.tv_sec;
  53        arg->params[0].u.value.b = ts.tv_nsec;
  54
  55        arg->ret = TEEC_SUCCESS;
  56        return;
  57bad:
  58        arg->ret = TEEC_ERROR_BAD_PARAMETERS;
  59}
  60
  61static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key)
  62{
  63        struct wq_entry *w;
  64
  65        mutex_lock(&wq->mu);
  66
  67        list_for_each_entry(w, &wq->db, link)
  68                if (w->key == key)
  69                        goto out;
  70
  71        w = kmalloc(sizeof(*w), GFP_KERNEL);
  72        if (w) {
  73                init_completion(&w->c);
  74                w->key = key;
  75                list_add_tail(&w->link, &wq->db);
  76        }
  77out:
  78        mutex_unlock(&wq->mu);
  79        return w;
  80}
  81
  82static void wq_sleep(struct optee_wait_queue *wq, u32 key)
  83{
  84        struct wq_entry *w = wq_entry_get(wq, key);
  85
  86        if (w) {
  87                wait_for_completion(&w->c);
  88                mutex_lock(&wq->mu);
  89                list_del(&w->link);
  90                mutex_unlock(&wq->mu);
  91                kfree(w);
  92        }
  93}
  94
  95static void wq_wakeup(struct optee_wait_queue *wq, u32 key)
  96{
  97        struct wq_entry *w = wq_entry_get(wq, key);
  98
  99        if (w)
 100                complete(&w->c);
 101}
 102
 103static void handle_rpc_func_cmd_wq(struct optee *optee,
 104                                   struct optee_msg_arg *arg)
 105{
 106        if (arg->num_params != 1)
 107                goto bad;
 108
 109        if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
 110                        OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
 111                goto bad;
 112
 113        switch (arg->params[0].u.value.a) {
 114        case OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP:
 115                wq_sleep(&optee->wait_queue, arg->params[0].u.value.b);
 116                break;
 117        case OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP:
 118                wq_wakeup(&optee->wait_queue, arg->params[0].u.value.b);
 119                break;
 120        default:
 121                goto bad;
 122        }
 123
 124        arg->ret = TEEC_SUCCESS;
 125        return;
 126bad:
 127        arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 128}
 129
 130static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg)
 131{
 132        u32 msec_to_wait;
 133
 134        if (arg->num_params != 1)
 135                goto bad;
 136
 137        if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
 138                        OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
 139                goto bad;
 140
 141        msec_to_wait = arg->params[0].u.value.a;
 142
 143        /* set task's state to interruptible sleep */
 144        set_current_state(TASK_INTERRUPTIBLE);
 145
 146        /* take a nap */
 147        msleep(msec_to_wait);
 148
 149        arg->ret = TEEC_SUCCESS;
 150        return;
 151bad:
 152        arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 153}
 154
 155static void handle_rpc_supp_cmd(struct tee_context *ctx,
 156                                struct optee_msg_arg *arg)
 157{
 158        struct tee_param *params;
 159
 160        arg->ret_origin = TEEC_ORIGIN_COMMS;
 161
 162        params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
 163                               GFP_KERNEL);
 164        if (!params) {
 165                arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
 166                return;
 167        }
 168
 169        if (optee_from_msg_param(params, arg->num_params, arg->params)) {
 170                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 171                goto out;
 172        }
 173
 174        arg->ret = optee_supp_thrd_req(ctx, arg->cmd, arg->num_params, params);
 175
 176        if (optee_to_msg_param(arg->params, arg->num_params, params))
 177                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 178out:
 179        kfree(params);
 180}
 181
 182static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
 183{
 184        u32 ret;
 185        struct tee_param param;
 186        struct optee *optee = tee_get_drvdata(ctx->teedev);
 187        struct tee_shm *shm;
 188
 189        param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
 190        param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
 191        param.u.value.b = sz;
 192        param.u.value.c = 0;
 193
 194        ret = optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_ALLOC, 1, &param);
 195        if (ret)
 196                return ERR_PTR(-ENOMEM);
 197
 198        mutex_lock(&optee->supp.ctx_mutex);
 199        /* Increases count as secure world doesn't have a reference */
 200        shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c);
 201        mutex_unlock(&optee->supp.ctx_mutex);
 202        return shm;
 203}
 204
 205static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
 206                                          struct optee_msg_arg *arg)
 207{
 208        phys_addr_t pa;
 209        struct tee_shm *shm;
 210        size_t sz;
 211        size_t n;
 212
 213        arg->ret_origin = TEEC_ORIGIN_COMMS;
 214
 215        if (!arg->num_params ||
 216            arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
 217                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 218                return;
 219        }
 220
 221        for (n = 1; n < arg->num_params; n++) {
 222                if (arg->params[n].attr != OPTEE_MSG_ATTR_TYPE_NONE) {
 223                        arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 224                        return;
 225                }
 226        }
 227
 228        sz = arg->params[0].u.value.b;
 229        switch (arg->params[0].u.value.a) {
 230        case OPTEE_MSG_RPC_SHM_TYPE_APPL:
 231                shm = cmd_alloc_suppl(ctx, sz);
 232                break;
 233        case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
 234                shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED);
 235                break;
 236        default:
 237                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 238                return;
 239        }
 240
 241        if (IS_ERR(shm)) {
 242                arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
 243                return;
 244        }
 245
 246        if (tee_shm_get_pa(shm, 0, &pa)) {
 247                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 248                goto bad;
 249        }
 250
 251        arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
 252        arg->params[0].u.tmem.buf_ptr = pa;
 253        arg->params[0].u.tmem.size = sz;
 254        arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
 255        arg->ret = TEEC_SUCCESS;
 256        return;
 257bad:
 258        tee_shm_free(shm);
 259}
 260
 261static void cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
 262{
 263        struct tee_param param;
 264
 265        param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
 266        param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
 267        param.u.value.b = tee_shm_get_id(shm);
 268        param.u.value.c = 0;
 269
 270        /*
 271         * Match the tee_shm_get_from_id() in cmd_alloc_suppl() as secure
 272         * world has released its reference.
 273         *
 274         * It's better to do this before sending the request to supplicant
 275         * as we'd like to let the process doing the initial allocation to
 276         * do release the last reference too in order to avoid stacking
 277         * many pending fput() on the client process. This could otherwise
 278         * happen if secure world does many allocate and free in a single
 279         * invoke.
 280         */
 281        tee_shm_put(shm);
 282
 283        optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_FREE, 1, &param);
 284}
 285
 286static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
 287                                         struct optee_msg_arg *arg)
 288{
 289        struct tee_shm *shm;
 290
 291        arg->ret_origin = TEEC_ORIGIN_COMMS;
 292
 293        if (arg->num_params != 1 ||
 294            arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
 295                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 296                return;
 297        }
 298
 299        shm = (struct tee_shm *)(unsigned long)arg->params[0].u.value.b;
 300        switch (arg->params[0].u.value.a) {
 301        case OPTEE_MSG_RPC_SHM_TYPE_APPL:
 302                cmd_free_suppl(ctx, shm);
 303                break;
 304        case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
 305                tee_shm_free(shm);
 306                break;
 307        default:
 308                arg->ret = TEEC_ERROR_BAD_PARAMETERS;
 309        }
 310        arg->ret = TEEC_SUCCESS;
 311}
 312
 313static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
 314                                struct tee_shm *shm)
 315{
 316        struct optee_msg_arg *arg;
 317
 318        arg = tee_shm_get_va(shm, 0);
 319        if (IS_ERR(arg)) {
 320                pr_err("%s: tee_shm_get_va %p failed\n", __func__, shm);
 321                return;
 322        }
 323
 324        switch (arg->cmd) {
 325        case OPTEE_MSG_RPC_CMD_GET_TIME:
 326                handle_rpc_func_cmd_get_time(arg);
 327                break;
 328        case OPTEE_MSG_RPC_CMD_WAIT_QUEUE:
 329                handle_rpc_func_cmd_wq(optee, arg);
 330                break;
 331        case OPTEE_MSG_RPC_CMD_SUSPEND:
 332                handle_rpc_func_cmd_wait(arg);
 333                break;
 334        case OPTEE_MSG_RPC_CMD_SHM_ALLOC:
 335                handle_rpc_func_cmd_shm_alloc(ctx, arg);
 336                break;
 337        case OPTEE_MSG_RPC_CMD_SHM_FREE:
 338                handle_rpc_func_cmd_shm_free(ctx, arg);
 339                break;
 340        default:
 341                handle_rpc_supp_cmd(ctx, arg);
 342        }
 343}
 344
 345/**
 346 * optee_handle_rpc() - handle RPC from secure world
 347 * @ctx:        context doing the RPC
 348 * @param:      value of registers for the RPC
 349 *
 350 * Result of RPC is written back into @param.
 351 */
 352void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param)
 353{
 354        struct tee_device *teedev = ctx->teedev;
 355        struct optee *optee = tee_get_drvdata(teedev);
 356        struct tee_shm *shm;
 357        phys_addr_t pa;
 358
 359        switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
 360        case OPTEE_SMC_RPC_FUNC_ALLOC:
 361                shm = tee_shm_alloc(ctx, param->a1, TEE_SHM_MAPPED);
 362                if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
 363                        reg_pair_from_64(&param->a1, &param->a2, pa);
 364                        reg_pair_from_64(&param->a4, &param->a5,
 365                                         (unsigned long)shm);
 366                } else {
 367                        param->a1 = 0;
 368                        param->a2 = 0;
 369                        param->a4 = 0;
 370                        param->a5 = 0;
 371                }
 372                break;
 373        case OPTEE_SMC_RPC_FUNC_FREE:
 374                shm = reg_pair_to_ptr(param->a1, param->a2);
 375                tee_shm_free(shm);
 376                break;
 377        case OPTEE_SMC_RPC_FUNC_IRQ:
 378                /*
 379                 * An IRQ was raised while secure world was executing,
 380                 * since all IRQs are handled in Linux a dummy RPC is
 381                 * performed to let Linux take the IRQ through the normal
 382                 * vector.
 383                 */
 384                break;
 385        case OPTEE_SMC_RPC_FUNC_CMD:
 386                shm = reg_pair_to_ptr(param->a1, param->a2);
 387                handle_rpc_func_cmd(ctx, optee, shm);
 388                break;
 389        default:
 390                pr_warn("Unknown RPC func 0x%x\n",
 391                        (u32)OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0));
 392                break;
 393        }
 394
 395        param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
 396}
 397