linux/drivers/tee/optee/supp.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015, 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#include <linux/device.h>
  15#include <linux/slab.h>
  16#include <linux/uaccess.h>
  17#include "optee_private.h"
  18
  19void optee_supp_init(struct optee_supp *supp)
  20{
  21        memset(supp, 0, sizeof(*supp));
  22        mutex_init(&supp->ctx_mutex);
  23        mutex_init(&supp->thrd_mutex);
  24        mutex_init(&supp->supp_mutex);
  25        init_completion(&supp->data_to_supp);
  26        init_completion(&supp->data_from_supp);
  27}
  28
  29void optee_supp_uninit(struct optee_supp *supp)
  30{
  31        mutex_destroy(&supp->ctx_mutex);
  32        mutex_destroy(&supp->thrd_mutex);
  33        mutex_destroy(&supp->supp_mutex);
  34}
  35
  36/**
  37 * optee_supp_thrd_req() - request service from supplicant
  38 * @ctx:        context doing the request
  39 * @func:       function requested
  40 * @num_params: number of elements in @param array
  41 * @param:      parameters for function
  42 *
  43 * Returns result of operation to be passed to secure world
  44 */
  45u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
  46                        struct tee_param *param)
  47{
  48        bool interruptable;
  49        struct optee *optee = tee_get_drvdata(ctx->teedev);
  50        struct optee_supp *supp = &optee->supp;
  51        u32 ret;
  52
  53        /*
  54         * Other threads blocks here until we've copied our answer from
  55         * supplicant.
  56         */
  57        while (mutex_lock_interruptible(&supp->thrd_mutex)) {
  58                /* See comment below on when the RPC can be interrupted. */
  59                mutex_lock(&supp->ctx_mutex);
  60                interruptable = !supp->ctx;
  61                mutex_unlock(&supp->ctx_mutex);
  62                if (interruptable)
  63                        return TEEC_ERROR_COMMUNICATION;
  64        }
  65
  66        /*
  67         * We have exclusive access now since the supplicant at this
  68         * point is either doing a
  69         * wait_for_completion_interruptible(&supp->data_to_supp) or is in
  70         * userspace still about to do the ioctl() to enter
  71         * optee_supp_recv() below.
  72         */
  73
  74        supp->func = func;
  75        supp->num_params = num_params;
  76        supp->param = param;
  77        supp->req_posted = true;
  78
  79        /* Let supplicant get the data */
  80        complete(&supp->data_to_supp);
  81
  82        /*
  83         * Wait for supplicant to process and return result, once we've
  84         * returned from wait_for_completion(data_from_supp) we have
  85         * exclusive access again.
  86         */
  87        while (wait_for_completion_interruptible(&supp->data_from_supp)) {
  88                mutex_lock(&supp->ctx_mutex);
  89                interruptable = !supp->ctx;
  90                if (interruptable) {
  91                        /*
  92                         * There's no supplicant available and since the
  93                         * supp->ctx_mutex currently is held none can
  94                         * become available until the mutex released
  95                         * again.
  96                         *
  97                         * Interrupting an RPC to supplicant is only
  98                         * allowed as a way of slightly improving the user
  99                         * experience in case the supplicant hasn't been
 100                         * started yet. During normal operation the supplicant
 101                         * will serve all requests in a timely manner and
 102                         * interrupting then wouldn't make sense.
 103                         */
 104                        supp->ret = TEEC_ERROR_COMMUNICATION;
 105                        init_completion(&supp->data_to_supp);
 106                }
 107                mutex_unlock(&supp->ctx_mutex);
 108                if (interruptable)
 109                        break;
 110        }
 111
 112        ret = supp->ret;
 113        supp->param = NULL;
 114        supp->req_posted = false;
 115
 116        /* We're done, let someone else talk to the supplicant now. */
 117        mutex_unlock(&supp->thrd_mutex);
 118
 119        return ret;
 120}
 121
 122/**
 123 * optee_supp_recv() - receive request for supplicant
 124 * @ctx:        context receiving the request
 125 * @func:       requested function in supplicant
 126 * @num_params: number of elements allocated in @param, updated with number
 127 *              used elements
 128 * @param:      space for parameters for @func
 129 *
 130 * Returns 0 on success or <0 on failure
 131 */
 132int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
 133                    struct tee_param *param)
 134{
 135        struct tee_device *teedev = ctx->teedev;
 136        struct optee *optee = tee_get_drvdata(teedev);
 137        struct optee_supp *supp = &optee->supp;
 138        int rc;
 139
 140        /*
 141         * In case two threads in one supplicant is calling this function
 142         * simultaneously we need to protect the data with a mutex which
 143         * we'll release before returning.
 144         */
 145        mutex_lock(&supp->supp_mutex);
 146
 147        if (supp->supp_next_send) {
 148                /*
 149                 * optee_supp_recv() has been called again without
 150                 * a optee_supp_send() in between. Supplicant has
 151                 * probably been restarted before it was able to
 152                 * write back last result. Abort last request and
 153                 * wait for a new.
 154                 */
 155                if (supp->req_posted) {
 156                        supp->ret = TEEC_ERROR_COMMUNICATION;
 157                        supp->supp_next_send = false;
 158                        complete(&supp->data_from_supp);
 159                }
 160        }
 161
 162        /*
 163         * This is where supplicant will be hanging most of the
 164         * time, let's make this interruptable so we can easily
 165         * restart supplicant if needed.
 166         */
 167        if (wait_for_completion_interruptible(&supp->data_to_supp)) {
 168                rc = -ERESTARTSYS;
 169                goto out;
 170        }
 171
 172        /* We have exlusive access to the data */
 173
 174        if (*num_params < supp->num_params) {
 175                /*
 176                 * Not enough room for parameters, tell supplicant
 177                 * it failed and abort last request.
 178                 */
 179                supp->ret = TEEC_ERROR_COMMUNICATION;
 180                rc = -EINVAL;
 181                complete(&supp->data_from_supp);
 182                goto out;
 183        }
 184
 185        *func = supp->func;
 186        *num_params = supp->num_params;
 187        memcpy(param, supp->param,
 188               sizeof(struct tee_param) * supp->num_params);
 189
 190        /* Allow optee_supp_send() below to do its work */
 191        supp->supp_next_send = true;
 192
 193        rc = 0;
 194out:
 195        mutex_unlock(&supp->supp_mutex);
 196        return rc;
 197}
 198
 199/**
 200 * optee_supp_send() - send result of request from supplicant
 201 * @ctx:        context sending result
 202 * @ret:        return value of request
 203 * @num_params: number of parameters returned
 204 * @param:      returned parameters
 205 *
 206 * Returns 0 on success or <0 on failure.
 207 */
 208int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
 209                    struct tee_param *param)
 210{
 211        struct tee_device *teedev = ctx->teedev;
 212        struct optee *optee = tee_get_drvdata(teedev);
 213        struct optee_supp *supp = &optee->supp;
 214        size_t n;
 215        int rc = 0;
 216
 217        /*
 218         * We still have exclusive access to the data since that's how we
 219         * left it when returning from optee_supp_read().
 220         */
 221
 222        /* See comment on mutex in optee_supp_read() above */
 223        mutex_lock(&supp->supp_mutex);
 224
 225        if (!supp->supp_next_send) {
 226                /*
 227                 * Something strange is going on, supplicant shouldn't
 228                 * enter optee_supp_send() in this state
 229                 */
 230                rc = -ENOENT;
 231                goto out;
 232        }
 233
 234        if (num_params != supp->num_params) {
 235                /*
 236                 * Something is wrong, let supplicant restart. Next call to
 237                 * optee_supp_recv() will give an error to the requesting
 238                 * thread and release it.
 239                 */
 240                rc = -EINVAL;
 241                goto out;
 242        }
 243
 244        /* Update out and in/out parameters */
 245        for (n = 0; n < num_params; n++) {
 246                struct tee_param *p = supp->param + n;
 247
 248                switch (p->attr) {
 249                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
 250                case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
 251                        p->u.value.a = param[n].u.value.a;
 252                        p->u.value.b = param[n].u.value.b;
 253                        p->u.value.c = param[n].u.value.c;
 254                        break;
 255                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
 256                case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
 257                        p->u.memref.size = param[n].u.memref.size;
 258                        break;
 259                default:
 260                        break;
 261                }
 262        }
 263        supp->ret = ret;
 264
 265        /* Allow optee_supp_recv() above to do its work */
 266        supp->supp_next_send = false;
 267
 268        /* Let the requesting thread continue */
 269        complete(&supp->data_from_supp);
 270out:
 271        mutex_unlock(&supp->supp_mutex);
 272        return rc;
 273}
 274