| 1 | |
| 2 | |
| 3 | * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
| 4 |
|
| 5 |
|
| 6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
| 7 |
|
| 8 | #include <linux/firmware/qcom/qcom_scm.h>
|
| 9 | #include <linux/init.h>
|
| 10 | #include <linux/module.h>
|
| 11 | #include <linux/slab.h>
|
| 12 | #include <linux/uaccess.h>
|
| 13 | #include <linux/xarray.h>
|
| 14 |
|
| 15 | #include "qcomtee.h"
|
| 16 |
|
| 17 |
|
| 18 | struct qcomtee_object qcomtee_object_root = {
|
| 19 | .name = "root",
|
| 20 | .object_type = QCOMTEE_OBJECT_TYPE_ROOT,
|
| 21 | .info.qtee_id = QCOMTEE_MSG_OBJECT_ROOT,
|
| 22 | };
|
| 23 |
|
| 24 |
|
| 25 | int qcomtee_next_arg_type(struct qcomtee_arg *u, int i,
|
| 26 | enum qcomtee_arg_type type)
|
| 27 | {
|
| 28 | while (u[i].type != QCOMTEE_ARG_TYPE_INV && u[i].type != type)
|
| 29 | i++;
|
| 30 | return i;
|
| 31 | }
|
| 32 |
|
| 33 | |
| 34 | * QTEE expects IDs with QCOMTEE_MSG_OBJECT_NS_BIT set for objects of
|
| 35 | * QCOMTEE_OBJECT_TYPE_CB type. The first ID with QCOMTEE_MSG_OBJECT_NS_BIT
|
| 36 | * set is reserved for the primordial object.
|
| 37 |
|
| 38 | #define QCOMTEE_OBJECT_PRIMORDIAL (QCOMTEE_MSG_OBJECT_NS_BIT)
|
| 39 | #define QCOMTEE_OBJECT_ID_START (QCOMTEE_OBJECT_PRIMORDIAL + 1)
|
| 40 | #define QCOMTEE_OBJECT_ID_END (U32_MAX)
|
| 41 |
|
| 42 | #define QCOMTEE_OBJECT_SET(p, type, ...) \
|
| 43 | __QCOMTEE_OBJECT_SET(p, type, ##__VA_ARGS__, 0UL)
|
| 44 | #define __QCOMTEE_OBJECT_SET(p, type, optr, ...) \
|
| 45 | do { \
|
| 46 | (p)->object_type = (type); \
|
| 47 | (p)->info.qtee_id = (unsigned long)(optr); \
|
| 48 | } while (0)
|
| 49 |
|
| 50 | static struct qcomtee_object *
|
| 51 | qcomtee_qtee_object_alloc(struct qcomtee_object_invoke_ctx *oic,
|
| 52 | unsigned int object_id)
|
| 53 | {
|
| 54 | struct qcomtee *qcomtee = tee_get_drvdata(oic->ctx->teedev);
|
| 55 | struct qcomtee_object *object;
|
| 56 |
|
| 57 | object = kzalloc_obj(*object);
|
| 58 | if (!object)
|
| 59 | return NULL_QCOMTEE_OBJECT;
|
| 60 |
|
| 61 |
|
| 62 | object->name = kasprintf(GFP_KERNEL, "qcomtee-%u", object_id);
|
| 63 | QCOMTEE_OBJECT_SET(object, QCOMTEE_OBJECT_TYPE_TEE, object_id);
|
| 64 | kref_init(&object->refcount);
|
| 65 |
|
| 66 | object->info.qcomtee_async_ctx = qcomtee->ctx;
|
| 67 | teedev_ctx_get(object->info.qcomtee_async_ctx);
|
| 68 |
|
| 69 | return object;
|
| 70 | }
|
| 71 |
|
| 72 | static void qcomtee_qtee_object_free(struct qcomtee_object *object)
|
| 73 | {
|
| 74 |
|
| 75 | teedev_ctx_put(object->info.qcomtee_async_ctx);
|
| 76 |
|
| 77 | kfree(object->name);
|
| 78 | kfree(object);
|
| 79 | }
|
| 80 |
|
| 81 | static void qcomtee_do_release_qtee_object(struct work_struct *work)
|
| 82 | {
|
| 83 | struct qcomtee_object *object;
|
| 84 | struct qcomtee *qcomtee;
|
| 85 | int ret, result = 0;
|
| 86 |
|
| 87 |
|
| 88 | struct qcomtee_arg args[] = { { .type = QCOMTEE_ARG_TYPE_INV } };
|
| 89 |
|
| 90 | object = container_of(work, struct qcomtee_object, work);
|
| 91 | qcomtee = tee_get_drvdata(object->info.qcomtee_async_ctx->teedev);
|
| 92 |
|
| 93 | qcomtee->oic.ctx = object->info.qcomtee_async_ctx;
|
| 94 |
|
| 95 | ret = qcomtee_object_do_invoke_internal(&qcomtee->oic, object,
|
| 96 | QCOMTEE_MSG_OBJECT_OP_RELEASE,
|
| 97 | args, &result);
|
| 98 |
|
| 99 |
|
| 100 | if (ret && ret != -ENODEV) {
|
| 101 | queue_work(qcomtee->wq, &object->work);
|
| 102 | } else {
|
| 103 | if (ret || result)
|
| 104 | pr_err("%s release failed, ret = %d (%x)\n",
|
| 105 | qcomtee_object_name(object), ret, result);
|
| 106 | qcomtee_qtee_object_free(object);
|
| 107 | }
|
| 108 | }
|
| 109 |
|
| 110 | static void qcomtee_release_qtee_object(struct qcomtee_object *object)
|
| 111 | {
|
| 112 | struct qcomtee *qcomtee =
|
| 113 | tee_get_drvdata(object->info.qcomtee_async_ctx->teedev);
|
| 114 |
|
| 115 | INIT_WORK(&object->work, qcomtee_do_release_qtee_object);
|
| 116 | queue_work(qcomtee->wq, &object->work);
|
| 117 | }
|
| 118 |
|
| 119 | static void qcomtee_object_release(struct kref *refcount)
|
| 120 | {
|
| 121 | struct qcomtee_object *object;
|
| 122 | const char *name;
|
| 123 |
|
| 124 | object = container_of(refcount, struct qcomtee_object, refcount);
|
| 125 |
|
| 126 | |
| 127 | * qcomtee_object_get() is called in a RCU read lock. synchronize_rcu()
|
| 128 | * to avoid releasing the object while it is being accessed in
|
| 129 | * qcomtee_object_get().
|
| 130 |
|
| 131 | synchronize_rcu();
|
| 132 |
|
| 133 | switch (typeof_qcomtee_object(object)) {
|
| 134 | case QCOMTEE_OBJECT_TYPE_TEE:
|
| 135 | qcomtee_release_qtee_object(object);
|
| 136 |
|
| 137 | break;
|
| 138 | case QCOMTEE_OBJECT_TYPE_CB:
|
| 139 | name = object->name;
|
| 140 |
|
| 141 | if (object->ops->release)
|
| 142 | object->ops->release(object);
|
| 143 |
|
| 144 | kfree_const(name);
|
| 145 |
|
| 146 | break;
|
| 147 | case QCOMTEE_OBJECT_TYPE_ROOT:
|
| 148 | case QCOMTEE_OBJECT_TYPE_NULL:
|
| 149 | default:
|
| 150 | break;
|
| 151 | }
|
| 152 | }
|
| 153 |
|
| 154 | |
| 155 | * qcomtee_object_get() - Increase the object's reference count.
|
| 156 | * @object: object to increase the reference count.
|
| 157 | *
|
| 158 | * Context: The caller should hold RCU read lock.
|
| 159 |
|
| 160 | int qcomtee_object_get(struct qcomtee_object *object)
|
| 161 | {
|
| 162 | if (object != &qcomtee_primordial_object &&
|
| 163 | object != NULL_QCOMTEE_OBJECT &&
|
| 164 | object != ROOT_QCOMTEE_OBJECT)
|
| 165 | return kref_get_unless_zero(&object->refcount);
|
| 166 |
|
| 167 | return 0;
|
| 168 | }
|
| 169 |
|
| 170 | |
| 171 | * qcomtee_object_put() - Decrease the object's reference count.
|
| 172 | * @object: object to decrease the reference count.
|
| 173 |
|
| 174 | void qcomtee_object_put(struct qcomtee_object *object)
|
| 175 | {
|
| 176 | if (object != &qcomtee_primordial_object &&
|
| 177 | object != NULL_QCOMTEE_OBJECT &&
|
| 178 | object != ROOT_QCOMTEE_OBJECT)
|
| 179 | kref_put(&object->refcount, qcomtee_object_release);
|
| 180 | }
|
| 181 |
|
| 182 | static int qcomtee_idx_alloc(struct qcomtee_object_invoke_ctx *oic, u32 *idx,
|
| 183 | struct qcomtee_object *object)
|
| 184 | {
|
| 185 | struct qcomtee *qcomtee = tee_get_drvdata(oic->ctx->teedev);
|
| 186 |
|
| 187 |
|
| 188 | return xa_alloc_cyclic(&qcomtee->xa_local_objects, idx, object,
|
| 189 | XA_LIMIT(QCOMTEE_OBJECT_ID_START,
|
| 190 | QCOMTEE_OBJECT_ID_END),
|
| 191 | &qcomtee->xa_last_id, GFP_KERNEL);
|
| 192 | }
|
| 193 |
|
| 194 | struct qcomtee_object *qcomtee_idx_erase(struct qcomtee_object_invoke_ctx *oic,
|
| 195 | u32 idx)
|
| 196 | {
|
| 197 | struct qcomtee *qcomtee = tee_get_drvdata(oic->ctx->teedev);
|
| 198 |
|
| 199 | if (idx < QCOMTEE_OBJECT_ID_START || idx > QCOMTEE_OBJECT_ID_END)
|
| 200 | return NULL_QCOMTEE_OBJECT;
|
| 201 |
|
| 202 | return xa_erase(&qcomtee->xa_local_objects, idx);
|
| 203 | }
|
| 204 |
|
| 205 | |
| 206 | * qcomtee_object_id_get() - Get an ID for an object to send to QTEE.
|
| 207 | * @oic: context to use for the invocation.
|
| 208 | * @object: object to assign an ID.
|
| 209 | * @object_id: object ID.
|
| 210 | *
|
| 211 | * Called on the path to QTEE to construct the message; see
|
| 212 | * qcomtee_prepare_msg() and qcomtee_update_msg().
|
| 213 | *
|
| 214 | * Return: On success, returns 0; on failure, returns < 0.
|
| 215 |
|
| 216 | static int qcomtee_object_id_get(struct qcomtee_object_invoke_ctx *oic,
|
| 217 | struct qcomtee_object *object,
|
| 218 | unsigned int *object_id)
|
| 219 | {
|
| 220 | u32 idx;
|
| 221 |
|
| 222 | switch (typeof_qcomtee_object(object)) {
|
| 223 | case QCOMTEE_OBJECT_TYPE_CB:
|
| 224 | if (qcomtee_idx_alloc(oic, &idx, object) < 0)
|
| 225 | return -ENOSPC;
|
| 226 |
|
| 227 | *object_id = idx;
|
| 228 |
|
| 229 | break;
|
| 230 | case QCOMTEE_OBJECT_TYPE_ROOT:
|
| 231 | case QCOMTEE_OBJECT_TYPE_TEE:
|
| 232 | *object_id = object->info.qtee_id;
|
| 233 |
|
| 234 | break;
|
| 235 | case QCOMTEE_OBJECT_TYPE_NULL:
|
| 236 | *object_id = QCOMTEE_MSG_OBJECT_NULL;
|
| 237 |
|
| 238 | break;
|
| 239 | }
|
| 240 |
|
| 241 | return 0;
|
| 242 | }
|
| 243 |
|
| 244 |
|
| 245 | static void qcomtee_object_id_put(struct qcomtee_object_invoke_ctx *oic,
|
| 246 | unsigned int object_id)
|
| 247 | {
|
| 248 | qcomtee_idx_erase(oic, object_id);
|
| 249 | }
|
| 250 |
|
| 251 | |
| 252 | * qcomtee_local_object_get() - Get the object referenced by the ID.
|
| 253 | * @oic: context to use for the invocation.
|
| 254 | * @object_id: object ID.
|
| 255 | *
|
| 256 | * It is called on the path from QTEE.
|
| 257 | * It is called on behalf of QTEE to obtain an instance of an object
|
| 258 | * for a given ID. It increases the object's reference count on success.
|
| 259 | *
|
| 260 | * Return: On error, returns %NULL_QCOMTEE_OBJECT.
|
| 261 | * On success, returns the object.
|
| 262 |
|
| 263 | static struct qcomtee_object *
|
| 264 | qcomtee_local_object_get(struct qcomtee_object_invoke_ctx *oic,
|
| 265 | unsigned int object_id)
|
| 266 | {
|
| 267 | struct qcomtee *qcomtee = tee_get_drvdata(oic->ctx->teedev);
|
| 268 | struct qcomtee_object *object;
|
| 269 |
|
| 270 | if (object_id == QCOMTEE_OBJECT_PRIMORDIAL)
|
| 271 | return &qcomtee_primordial_object;
|
| 272 |
|
| 273 | guard(rcu)();
|
| 274 | object = xa_load(&qcomtee->xa_local_objects, object_id);
|
| 275 |
|
| 276 | qcomtee_object_get(object);
|
| 277 |
|
| 278 | return object;
|
| 279 | }
|
| 280 |
|
| 281 | |
| 282 | * qcomtee_object_user_init() - Initialize an object for the user.
|
| 283 | * @object: object to initialize.
|
| 284 | * @ot: type of object as &enum qcomtee_object_type.
|
| 285 | * @ops: instance of callbacks.
|
| 286 | * @fmt: name assigned to the object.
|
| 287 | *
|
| 288 | * Return: On success, returns 0; on failure, returns < 0.
|
| 289 |
|
| 290 | int qcomtee_object_user_init(struct qcomtee_object *object,
|
| 291 | enum qcomtee_object_type ot,
|
| 292 | struct qcomtee_object_operations *ops,
|
| 293 | const char *fmt, ...)
|
| 294 | {
|
| 295 | va_list ap;
|
| 296 | int ret;
|
| 297 |
|
| 298 | kref_init(&object->refcount);
|
| 299 | QCOMTEE_OBJECT_SET(object, QCOMTEE_OBJECT_TYPE_NULL);
|
| 300 |
|
| 301 | va_start(ap, fmt);
|
| 302 | switch (ot) {
|
| 303 | case QCOMTEE_OBJECT_TYPE_NULL:
|
| 304 | ret = 0;
|
| 305 |
|
| 306 | break;
|
| 307 | case QCOMTEE_OBJECT_TYPE_CB:
|
| 308 | object->ops = ops;
|
| 309 | if (!object->ops->dispatch) {
|
| 310 | ret = -EINVAL;
|
| 311 | break;
|
| 312 | }
|
| 313 |
|
| 314 |
|
| 315 | object->name = kvasprintf_const(GFP_KERNEL, fmt, ap);
|
| 316 | QCOMTEE_OBJECT_SET(object, QCOMTEE_OBJECT_TYPE_CB);
|
| 317 |
|
| 318 | ret = 0;
|
| 319 | break;
|
| 320 | case QCOMTEE_OBJECT_TYPE_ROOT:
|
| 321 | case QCOMTEE_OBJECT_TYPE_TEE:
|
| 322 | default:
|
| 323 | ret = -EINVAL;
|
| 324 | }
|
| 325 | va_end(ap);
|
| 326 |
|
| 327 | return ret;
|
| 328 | }
|
| 329 |
|
| 330 | |
| 331 | * qcomtee_object_type() - Returns the type of object represented by an ID.
|
| 332 | * @object_id: object ID for the object.
|
| 333 | *
|
| 334 | * Similar to typeof_qcomtee_object(), but instead of receiving an object as
|
| 335 | * an argument, it receives an object ID. It is used internally on the return
|
| 336 | * path from QTEE.
|
| 337 | *
|
| 338 | * Return: Returns the type of object referenced by @object_id.
|
| 339 |
|
| 340 | static enum qcomtee_object_type qcomtee_object_type(unsigned int object_id)
|
| 341 | {
|
| 342 | if (object_id == QCOMTEE_MSG_OBJECT_NULL)
|
| 343 | return QCOMTEE_OBJECT_TYPE_NULL;
|
| 344 |
|
| 345 | if (object_id & QCOMTEE_MSG_OBJECT_NS_BIT)
|
| 346 | return QCOMTEE_OBJECT_TYPE_CB;
|
| 347 |
|
| 348 | return QCOMTEE_OBJECT_TYPE_TEE;
|
| 349 | }
|
| 350 |
|
| 351 | |
| 352 | * qcomtee_object_qtee_init() - Initialize an object for QTEE.
|
| 353 | * @oic: context to use for the invocation.
|
| 354 | * @object: object returned.
|
| 355 | * @object_id: object ID received from QTEE.
|
| 356 | *
|
| 357 | * Return: On failure, returns < 0 and sets @object to %NULL_QCOMTEE_OBJECT.
|
| 358 | * On success, returns 0
|
| 359 |
|
| 360 | static int qcomtee_object_qtee_init(struct qcomtee_object_invoke_ctx *oic,
|
| 361 | struct qcomtee_object **object,
|
| 362 | unsigned int object_id)
|
| 363 | {
|
| 364 | int ret = 0;
|
| 365 |
|
| 366 | switch (qcomtee_object_type(object_id)) {
|
| 367 | case QCOMTEE_OBJECT_TYPE_NULL:
|
| 368 | *object = NULL_QCOMTEE_OBJECT;
|
| 369 |
|
| 370 | break;
|
| 371 | case QCOMTEE_OBJECT_TYPE_CB:
|
| 372 | *object = qcomtee_local_object_get(oic, object_id);
|
| 373 | if (*object == NULL_QCOMTEE_OBJECT)
|
| 374 | ret = -EINVAL;
|
| 375 |
|
| 376 | break;
|
| 377 |
|
| 378 | default:
|
| 379 | *object = qcomtee_qtee_object_alloc(oic, object_id);
|
| 380 | if (*object == NULL_QCOMTEE_OBJECT)
|
| 381 | ret = -ENOMEM;
|
| 382 |
|
| 383 | break;
|
| 384 | }
|
| 385 |
|
| 386 | return ret;
|
| 387 | }
|
| 388 |
|
| 389 | |
| 390 | * ''Marshaling API''
|
| 391 | * qcomtee_prepare_msg - Prepare the inbound buffer for sending to QTEE
|
| 392 | * qcomtee_update_args - Parse the QTEE response in the inbound buffer
|
| 393 | * qcomtee_prepare_args - Parse the QTEE request from the outbound buffer
|
| 394 | * qcomtee_update_msg - Update the outbound buffer with the response for QTEE
|
| 395 |
|
| 396 |
|
| 397 | static int qcomtee_prepare_msg(struct qcomtee_object_invoke_ctx *oic,
|
| 398 | struct qcomtee_object *object, u32 op,
|
| 399 | struct qcomtee_arg *u)
|
| 400 | {
|
| 401 | struct qcomtee_msg_object_invoke *msg;
|
| 402 | unsigned int object_id;
|
| 403 | int i, ib, ob, io, oo;
|
| 404 | size_t offset;
|
| 405 |
|
| 406 |
|
| 407 | msg = oic->in_msg.addr;
|
| 408 |
|
| 409 |
|
| 410 | offset = qcomtee_msg_buffer_args(struct qcomtee_msg_object_invoke,
|
| 411 | qcomtee_args_len(u));
|
| 412 |
|
| 413 |
|
| 414 | if (qcomtee_object_id_get(oic, object, &object_id))
|
| 415 | return -ENOSPC;
|
| 416 |
|
| 417 | ib = 0;
|
| 418 | qcomtee_arg_for_each_input_buffer(i, u) {
|
| 419 | void *msgptr;
|
| 420 |
|
| 421 | msg->args[ib].b.offset = offset;
|
| 422 | msg->args[ib].b.size = u[i].b.size;
|
| 423 |
|
| 424 | msgptr = qcomtee_msg_offset_to_ptr(msg, offset);
|
| 425 |
|
| 426 | if (!(u[i].flags & QCOMTEE_ARG_FLAGS_UADDR))
|
| 427 | memcpy(msgptr, u[i].b.addr, u[i].b.size);
|
| 428 | else if (copy_from_user(msgptr, u[i].b.uaddr, u[i].b.size))
|
| 429 | return -EFAULT;
|
| 430 |
|
| 431 | offset += qcomtee_msg_offset_align(u[i].b.size);
|
| 432 | ib++;
|
| 433 | }
|
| 434 |
|
| 435 | ob = ib;
|
| 436 | qcomtee_arg_for_each_output_buffer(i, u) {
|
| 437 |
|
| 438 | msg->args[ob].b.offset = offset;
|
| 439 | msg->args[ob].b.size = u[i].b.size;
|
| 440 |
|
| 441 | offset += qcomtee_msg_offset_align(u[i].b.size);
|
| 442 | ob++;
|
| 443 | }
|
| 444 |
|
| 445 | io = ob;
|
| 446 | qcomtee_arg_for_each_input_object(i, u) {
|
| 447 | if (qcomtee_object_id_get(oic, u[i].o, &msg->args[io].o)) {
|
| 448 | qcomtee_object_id_put(oic, object_id);
|
| 449 | for (io--; io >= ob; io--)
|
| 450 | qcomtee_object_id_put(oic, msg->args[io].o);
|
| 451 |
|
| 452 | return -ENOSPC;
|
| 453 | }
|
| 454 |
|
| 455 | io++;
|
| 456 | }
|
| 457 |
|
| 458 | oo = io;
|
| 459 | qcomtee_arg_for_each_output_object(i, u)
|
| 460 | oo++;
|
| 461 |
|
| 462 |
|
| 463 | qcomtee_msg_init(msg, object_id, op, ib, ob, io, oo);
|
| 464 |
|
| 465 | return 0;
|
| 466 | }
|
| 467 |
|
| 468 | |
| 469 | * qcomtee_update_args() - Parse the QTEE response in the inbound buffer.
|
| 470 | * @u: array of arguments for the invocation.
|
| 471 | * @oic: context to use for the invocation.
|
| 472 | *
|
| 473 | * @u must be the same as the one used in qcomtee_prepare_msg() when
|
| 474 | * initializing the inbound buffer.
|
| 475 | *
|
| 476 | * On failure, it continues processing the QTEE message. The caller should
|
| 477 | * do the necessary cleanup, including calling qcomtee_object_put()
|
| 478 | * on the output objects.
|
| 479 | *
|
| 480 | * Return: On success, returns 0; on failure, returns < 0.
|
| 481 |
|
| 482 | static int qcomtee_update_args(struct qcomtee_arg *u,
|
| 483 | struct qcomtee_object_invoke_ctx *oic)
|
| 484 | {
|
| 485 | struct qcomtee_msg_object_invoke *msg;
|
| 486 | int i, ib, ob, io, oo;
|
| 487 | int ret = 0;
|
| 488 |
|
| 489 |
|
| 490 | msg = oic->in_msg.addr;
|
| 491 |
|
| 492 | ib = 0;
|
| 493 | qcomtee_arg_for_each_input_buffer(i, u)
|
| 494 | ib++;
|
| 495 |
|
| 496 | ob = ib;
|
| 497 | qcomtee_arg_for_each_output_buffer(i, u) {
|
| 498 | void *msgptr;
|
| 499 |
|
| 500 | u[i].b.size = msg->args[ob].b.size;
|
| 501 |
|
| 502 | msgptr = qcomtee_msg_offset_to_ptr(msg, msg->args[ob].b.offset);
|
| 503 |
|
| 504 | if (!(u[i].flags & QCOMTEE_ARG_FLAGS_UADDR))
|
| 505 | memcpy(u[i].b.addr, msgptr, u[i].b.size);
|
| 506 | else if (copy_to_user(u[i].b.uaddr, msgptr, u[i].b.size))
|
| 507 | ret = -EINVAL;
|
| 508 |
|
| 509 | ob++;
|
| 510 | }
|
| 511 |
|
| 512 | io = ob;
|
| 513 | qcomtee_arg_for_each_input_object(i, u)
|
| 514 | io++;
|
| 515 |
|
| 516 | oo = io;
|
| 517 | qcomtee_arg_for_each_output_object(i, u) {
|
| 518 | if (qcomtee_object_qtee_init(oic, &u[i].o, msg->args[oo].o))
|
| 519 | ret = -EINVAL;
|
| 520 |
|
| 521 | oo++;
|
| 522 | }
|
| 523 |
|
| 524 | return ret;
|
| 525 | }
|
| 526 |
|
| 527 | |
| 528 | * qcomtee_prepare_args() - Parse the QTEE request from the outbound buffer.
|
| 529 | * @oic: context to use for the invocation.
|
| 530 | *
|
| 531 | * It initializes &qcomtee_object_invoke_ctx->u based on the QTEE request in
|
| 532 | * the outbound buffer. It sets %QCOMTEE_ARG_TYPE_INV at the end of the array.
|
| 533 | *
|
| 534 | * On failure, it continues processing the QTEE message. The caller should
|
| 535 | * do the necessary cleanup, including calling qcomtee_object_put()
|
| 536 | * on the input objects.
|
| 537 | *
|
| 538 | * Return: On success, returns 0; on failure, returns < 0.
|
| 539 |
|
| 540 | static int qcomtee_prepare_args(struct qcomtee_object_invoke_ctx *oic)
|
| 541 | {
|
| 542 | struct qcomtee_msg_callback *msg;
|
| 543 | int i, ret = 0;
|
| 544 |
|
| 545 |
|
| 546 | msg = oic->out_msg.addr;
|
| 547 |
|
| 548 | qcomtee_msg_for_each_input_buffer(i, msg) {
|
| 549 | oic->u[i].b.addr =
|
| 550 | qcomtee_msg_offset_to_ptr(msg, msg->args[i].b.offset);
|
| 551 | oic->u[i].b.size = msg->args[i].b.size;
|
| 552 | oic->u[i].type = QCOMTEE_ARG_TYPE_IB;
|
| 553 | }
|
| 554 |
|
| 555 | qcomtee_msg_for_each_output_buffer(i, msg) {
|
| 556 | oic->u[i].b.addr =
|
| 557 | qcomtee_msg_offset_to_ptr(msg, msg->args[i].b.offset);
|
| 558 | oic->u[i].b.size = msg->args[i].b.size;
|
| 559 | oic->u[i].type = QCOMTEE_ARG_TYPE_OB;
|
| 560 | }
|
| 561 |
|
| 562 | qcomtee_msg_for_each_input_object(i, msg) {
|
| 563 | if (qcomtee_object_qtee_init(oic, &oic->u[i].o, msg->args[i].o))
|
| 564 | ret = -EINVAL;
|
| 565 |
|
| 566 | oic->u[i].type = QCOMTEE_ARG_TYPE_IO;
|
| 567 | }
|
| 568 |
|
| 569 | qcomtee_msg_for_each_output_object(i, msg)
|
| 570 | oic->u[i].type = QCOMTEE_ARG_TYPE_OO;
|
| 571 |
|
| 572 |
|
| 573 | oic->u[i].type = QCOMTEE_ARG_TYPE_INV;
|
| 574 |
|
| 575 | return ret;
|
| 576 | }
|
| 577 |
|
| 578 | static int qcomtee_update_msg(struct qcomtee_object_invoke_ctx *oic)
|
| 579 | {
|
| 580 | struct qcomtee_msg_callback *msg;
|
| 581 | int i, ib, ob, io, oo;
|
| 582 |
|
| 583 |
|
| 584 | msg = oic->out_msg.addr;
|
| 585 |
|
| 586 | ib = 0;
|
| 587 | qcomtee_arg_for_each_input_buffer(i, oic->u)
|
| 588 | ib++;
|
| 589 |
|
| 590 | ob = ib;
|
| 591 | qcomtee_arg_for_each_output_buffer(i, oic->u) {
|
| 592 |
|
| 593 | if (msg->args[ob].b.size < oic->u[i].b.size)
|
| 594 | return -EINVAL;
|
| 595 |
|
| 596 | msg->args[ob].b.size = oic->u[i].b.size;
|
| 597 | ob++;
|
| 598 | }
|
| 599 |
|
| 600 | io = ob;
|
| 601 | qcomtee_arg_for_each_input_object(i, oic->u)
|
| 602 | io++;
|
| 603 |
|
| 604 | oo = io;
|
| 605 | qcomtee_arg_for_each_output_object(i, oic->u) {
|
| 606 | if (qcomtee_object_id_get(oic, oic->u[i].o, &msg->args[oo].o)) {
|
| 607 | for (oo--; oo >= io; oo--)
|
| 608 | qcomtee_object_id_put(oic, msg->args[oo].o);
|
| 609 |
|
| 610 | return -ENOSPC;
|
| 611 | }
|
| 612 |
|
| 613 | oo++;
|
| 614 | }
|
| 615 |
|
| 616 | return 0;
|
| 617 | }
|
| 618 |
|
| 619 |
|
| 620 | static void qcomtee_cb_object_invoke(struct qcomtee_object_invoke_ctx *oic,
|
| 621 | struct qcomtee_msg_callback *msg)
|
| 622 | {
|
| 623 | int i, errno;
|
| 624 | u32 op;
|
| 625 |
|
| 626 |
|
| 627 | unsigned int object_id = msg->cxt;
|
| 628 | struct qcomtee_object *object;
|
| 629 |
|
| 630 |
|
| 631 | if (qcomtee_object_type(object_id) == QCOMTEE_OBJECT_TYPE_NULL ||
|
| 632 | qcomtee_object_type(object_id) == QCOMTEE_OBJECT_TYPE_TEE) {
|
| 633 | errno = -EINVAL;
|
| 634 | goto out;
|
| 635 | }
|
| 636 |
|
| 637 | object = qcomtee_local_object_get(oic, object_id);
|
| 638 | if (object == NULL_QCOMTEE_OBJECT) {
|
| 639 | errno = -EINVAL;
|
| 640 | goto out;
|
| 641 | }
|
| 642 |
|
| 643 | oic->object = object;
|
| 644 |
|
| 645 |
|
| 646 | op = msg->op & QCOMTEE_MSG_OBJECT_OP_MASK;
|
| 647 |
|
| 648 | switch (op) {
|
| 649 | case QCOMTEE_MSG_OBJECT_OP_RELEASE:
|
| 650 | qcomtee_object_id_put(oic, object_id);
|
| 651 | qcomtee_object_put(object);
|
| 652 | errno = 0;
|
| 653 |
|
| 654 | break;
|
| 655 | case QCOMTEE_MSG_OBJECT_OP_RETAIN:
|
| 656 | qcomtee_object_get(object);
|
| 657 | errno = 0;
|
| 658 |
|
| 659 | break;
|
| 660 | default:
|
| 661 | errno = qcomtee_prepare_args(oic);
|
| 662 | if (errno) {
|
| 663 |
|
| 664 | qcomtee_arg_for_each_input_buffer(i, oic->u)
|
| 665 | qcomtee_object_put(oic->u[i].o);
|
| 666 |
|
| 667 | break;
|
| 668 | }
|
| 669 |
|
| 670 | errno = object->ops->dispatch(oic, object, op, oic->u);
|
| 671 | if (!errno) {
|
| 672 |
|
| 673 | oic->flags |= QCOMTEE_OIC_FLAG_NOTIFY;
|
| 674 | }
|
| 675 | }
|
| 676 |
|
| 677 | out:
|
| 678 |
|
| 679 | oic->errno = errno;
|
| 680 | }
|
| 681 |
|
| 682 | static int
|
| 683 | qcomtee_object_invoke_ctx_invoke(struct qcomtee_object_invoke_ctx *oic,
|
| 684 | int *result, u64 *res_type)
|
| 685 | {
|
| 686 | phys_addr_t out_msg_paddr;
|
| 687 | phys_addr_t in_msg_paddr;
|
| 688 | int ret;
|
| 689 | u64 res;
|
| 690 |
|
| 691 | tee_shm_get_pa(oic->out_shm, 0, &out_msg_paddr);
|
| 692 | tee_shm_get_pa(oic->in_shm, 0, &in_msg_paddr);
|
| 693 | if (!(oic->flags & QCOMTEE_OIC_FLAG_BUSY))
|
| 694 | ret = qcom_scm_qtee_invoke_smc(in_msg_paddr, oic->in_msg.size,
|
| 695 | out_msg_paddr, oic->out_msg.size,
|
| 696 | &res, res_type);
|
| 697 | else
|
| 698 | ret = qcom_scm_qtee_callback_response(out_msg_paddr,
|
| 699 | oic->out_msg.size,
|
| 700 | &res, res_type);
|
| 701 |
|
| 702 | if (ret)
|
| 703 | pr_err("QTEE returned with %d.\n", ret);
|
| 704 | else
|
| 705 | *result = (int)res;
|
| 706 |
|
| 707 | return ret;
|
| 708 | }
|
| 709 |
|
| 710 | |
| 711 | * qcomtee_qtee_objects_put() - Put the callback objects in the argument array.
|
| 712 | * @u: array of arguments.
|
| 713 | *
|
| 714 | * When qcomtee_object_do_invoke_internal() is successfully invoked,
|
| 715 | * QTEE takes ownership of the callback objects. If the invocation fails,
|
| 716 | * qcomtee_object_do_invoke_internal() calls qcomtee_qtee_objects_put()
|
| 717 | * to mimic the release of callback objects by QTEE.
|
| 718 |
|
| 719 | static void qcomtee_qtee_objects_put(struct qcomtee_arg *u)
|
| 720 | {
|
| 721 | int i;
|
| 722 |
|
| 723 | qcomtee_arg_for_each_input_object(i, u) {
|
| 724 | if (typeof_qcomtee_object(u[i].o) == QCOMTEE_OBJECT_TYPE_CB)
|
| 725 | qcomtee_object_put(u[i].o);
|
| 726 | }
|
| 727 | }
|
| 728 |
|
| 729 | |
| 730 | * qcomtee_object_do_invoke_internal() - Submit an invocation for an object.
|
| 731 | * @oic: context to use for the current invocation.
|
| 732 | * @object: object being invoked.
|
| 733 | * @op: requested operation on the object.
|
| 734 | * @u: array of arguments for the current invocation.
|
| 735 | * @result: result returned from QTEE.
|
| 736 | *
|
| 737 | * The caller is responsible for keeping track of the refcount for each
|
| 738 | * object, including @object. On return, the caller loses ownership of all
|
| 739 | * input objects of type %QCOMTEE_OBJECT_TYPE_CB.
|
| 740 | *
|
| 741 | * Return: On success, returns 0; on failure, returns < 0.
|
| 742 |
|
| 743 | int qcomtee_object_do_invoke_internal(struct qcomtee_object_invoke_ctx *oic,
|
| 744 | struct qcomtee_object *object, u32 op,
|
| 745 | struct qcomtee_arg *u, int *result)
|
| 746 | {
|
| 747 | struct qcomtee_msg_callback *cb_msg;
|
| 748 | struct qcomtee_object *qto;
|
| 749 | int i, ret, errno;
|
| 750 | u64 res_type;
|
| 751 |
|
| 752 |
|
| 753 | ret = qcomtee_msg_buffers_alloc(oic, u);
|
| 754 | if (ret) {
|
| 755 | qcomtee_qtee_objects_put(u);
|
| 756 |
|
| 757 | return ret;
|
| 758 | }
|
| 759 |
|
| 760 | ret = qcomtee_prepare_msg(oic, object, op, u);
|
| 761 | if (ret) {
|
| 762 | qcomtee_qtee_objects_put(u);
|
| 763 |
|
| 764 | goto out;
|
| 765 | }
|
| 766 |
|
| 767 |
|
| 768 | cb_msg = oic->out_msg.addr;
|
| 769 |
|
| 770 | while (1) {
|
| 771 | if (oic->flags & QCOMTEE_OIC_FLAG_BUSY) {
|
| 772 | errno = oic->errno;
|
| 773 | if (!errno)
|
| 774 | errno = qcomtee_update_msg(oic);
|
| 775 | qcomtee_msg_set_result(cb_msg, errno);
|
| 776 | }
|
| 777 |
|
| 778 |
|
| 779 | ret = qcomtee_object_invoke_ctx_invoke(oic, result, &res_type);
|
| 780 |
|
| 781 | if (oic->flags & QCOMTEE_OIC_FLAG_BUSY) {
|
| 782 | qto = oic->object;
|
| 783 | if (qto) {
|
| 784 | if (oic->flags & QCOMTEE_OIC_FLAG_NOTIFY) {
|
| 785 | if (qto->ops->notify)
|
| 786 | qto->ops->notify(oic, qto,
|
| 787 | errno || ret);
|
| 788 | }
|
| 789 |
|
| 790 |
|
| 791 | qcomtee_object_put(qto);
|
| 792 | }
|
| 793 |
|
| 794 | oic->object = NULL_QCOMTEE_OBJECT;
|
| 795 | oic->flags &= ~(QCOMTEE_OIC_FLAG_BUSY |
|
| 796 | QCOMTEE_OIC_FLAG_NOTIFY);
|
| 797 | }
|
| 798 |
|
| 799 | if (ret) {
|
| 800 | |
| 801 | * Unable to finished the invocation.
|
| 802 | * If QCOMTEE_OIC_FLAG_SHARED is not set, put
|
| 803 | * QCOMTEE_OBJECT_TYPE_CB input objects.
|
| 804 |
|
| 805 | if (!(oic->flags & QCOMTEE_OIC_FLAG_SHARED))
|
| 806 | qcomtee_qtee_objects_put(u);
|
| 807 | else
|
| 808 | ret = -ENODEV;
|
| 809 |
|
| 810 | goto out;
|
| 811 |
|
| 812 | } else {
|
| 813 | |
| 814 | * QTEE obtained ownership of QCOMTEE_OBJECT_TYPE_CB
|
| 815 | * input objects in 'u'. On further failure, QTEE is
|
| 816 | * responsible for releasing them.
|
| 817 |
|
| 818 | oic->flags |= QCOMTEE_OIC_FLAG_SHARED;
|
| 819 | }
|
| 820 |
|
| 821 |
|
| 822 | if (res_type != QCOMTEE_RESULT_INBOUND_REQ_NEEDED) {
|
| 823 | |
| 824 | * Parse results. If failed, assume the service
|
| 825 | * was unavailable (i.e. QCOMTEE_MSG_ERROR_UNAVAIL)
|
| 826 | * and put output objects to initiate cleanup.
|
| 827 |
|
| 828 | if (!*result && qcomtee_update_args(u, oic)) {
|
| 829 | *result = QCOMTEE_MSG_ERROR_UNAVAIL;
|
| 830 | qcomtee_arg_for_each_output_object(i, u)
|
| 831 | qcomtee_object_put(u[i].o);
|
| 832 | }
|
| 833 |
|
| 834 | break;
|
| 835 |
|
| 836 | } else {
|
| 837 | oic->flags |= QCOMTEE_OIC_FLAG_BUSY;
|
| 838 | qcomtee_fetch_async_reqs(oic);
|
| 839 | qcomtee_cb_object_invoke(oic, cb_msg);
|
| 840 | }
|
| 841 | }
|
| 842 |
|
| 843 | qcomtee_fetch_async_reqs(oic);
|
| 844 | out:
|
| 845 | qcomtee_msg_buffers_free(oic);
|
| 846 |
|
| 847 | return ret;
|
| 848 | }
|
| 849 |
|
| 850 | int qcomtee_object_do_invoke(struct qcomtee_object_invoke_ctx *oic,
|
| 851 | struct qcomtee_object *object, u32 op,
|
| 852 | struct qcomtee_arg *u, int *result)
|
| 853 | {
|
| 854 |
|
| 855 | if (op & ~QCOMTEE_MSG_OBJECT_OP_MASK)
|
| 856 | return -EINVAL;
|
| 857 |
|
| 858 |
|
| 859 | if (typeof_qcomtee_object(object) != QCOMTEE_OBJECT_TYPE_TEE &&
|
| 860 | typeof_qcomtee_object(object) != QCOMTEE_OBJECT_TYPE_ROOT)
|
| 861 | return -EINVAL;
|
| 862 |
|
| 863 |
|
| 864 | if (op == QCOMTEE_MSG_OBJECT_OP_RELEASE ||
|
| 865 | op == QCOMTEE_MSG_OBJECT_OP_RETAIN)
|
| 866 | return -EINVAL;
|
| 867 |
|
| 868 | return qcomtee_object_do_invoke_internal(oic, object, op, u, result);
|
| 869 | }
|
| 870 |
|
| 871 | |
| 872 | * qcomtee_object_get_client_env() - Get a privileged client env. object.
|
| 873 | * @oic: context to use for the current invocation.
|
| 874 | *
|
| 875 | * The caller should call qcomtee_object_put() on the returned object
|
| 876 | * to release it.
|
| 877 | *
|
| 878 | * Return: On error, returns %NULL_QCOMTEE_OBJECT.
|
| 879 | * On success, returns the object.
|
| 880 |
|
| 881 | struct qcomtee_object *
|
| 882 | qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic)
|
| 883 | {
|
| 884 | struct qcomtee_arg u[3] = { 0 };
|
| 885 | int ret, result;
|
| 886 |
|
| 887 | u[0].o = NULL_QCOMTEE_OBJECT;
|
| 888 | u[0].type = QCOMTEE_ARG_TYPE_IO;
|
| 889 | u[1].type = QCOMTEE_ARG_TYPE_OO;
|
| 890 | ret = qcomtee_object_do_invoke(oic, ROOT_QCOMTEE_OBJECT,
|
| 891 | QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS, u,
|
| 892 | &result);
|
| 893 | if (ret || result)
|
| 894 | return NULL_QCOMTEE_OBJECT;
|
| 895 |
|
| 896 | return u[1].o;
|
| 897 | }
|
| 898 |
|
| 899 | struct qcomtee_object *
|
| 900 | qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic,
|
| 901 | struct qcomtee_object *client_env, u32 uid)
|
| 902 | {
|
| 903 | struct qcomtee_arg u[3] = { 0 };
|
| 904 | int ret, result;
|
| 905 |
|
| 906 | u[0].b.addr = &uid;
|
| 907 | u[0].b.size = sizeof(uid);
|
| 908 | u[0].type = QCOMTEE_ARG_TYPE_IB;
|
| 909 | u[1].type = QCOMTEE_ARG_TYPE_OO;
|
| 910 | ret = qcomtee_object_do_invoke(oic, client_env, QCOMTEE_CLIENT_ENV_OPEN,
|
| 911 | u, &result);
|
| 912 |
|
| 913 | if (ret || result)
|
| 914 | return NULL_QCOMTEE_OBJECT;
|
| 915 |
|
| 916 | return u[1].o;
|
| 917 | }
|