linux/drivers/tee/optee/device.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2019 Linaro Ltd.
   4 */
   5
   6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   7
   8#include <linux/kernel.h>
   9#include <linux/slab.h>
  10#include <linux/tee_drv.h>
  11#include <linux/uuid.h>
  12#include "optee_private.h"
  13
  14/*
  15 * Get device UUIDs
  16 *
  17 * [out]     memref[0]        Array of device UUIDs
  18 *
  19 * Return codes:
  20 * TEE_SUCCESS - Invoke command success
  21 * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
  22 * TEE_ERROR_SHORT_BUFFER - Output buffer size less than required
  23 */
  24#define PTA_CMD_GET_DEVICES             0x0
  25
  26static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
  27{
  28        if (ver->impl_id == TEE_IMPL_ID_OPTEE)
  29                return 1;
  30        else
  31                return 0;
  32}
  33
  34static int get_devices(struct tee_context *ctx, u32 session,
  35                       struct tee_shm *device_shm, u32 *shm_size)
  36{
  37        int ret = 0;
  38        struct tee_ioctl_invoke_arg inv_arg;
  39        struct tee_param param[4];
  40
  41        memset(&inv_arg, 0, sizeof(inv_arg));
  42        memset(&param, 0, sizeof(param));
  43
  44        /* Invoke PTA_CMD_GET_DEVICES function */
  45        inv_arg.func = PTA_CMD_GET_DEVICES;
  46        inv_arg.session = session;
  47        inv_arg.num_params = 4;
  48
  49        /* Fill invoke cmd params */
  50        param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
  51        param[0].u.memref.shm = device_shm;
  52        param[0].u.memref.size = *shm_size;
  53        param[0].u.memref.shm_offs = 0;
  54
  55        ret = tee_client_invoke_func(ctx, &inv_arg, param);
  56        if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) &&
  57                          (inv_arg.ret != TEEC_ERROR_SHORT_BUFFER))) {
  58                pr_err("PTA_CMD_GET_DEVICES invoke function err: %x\n",
  59                       inv_arg.ret);
  60                return -EINVAL;
  61        }
  62
  63        *shm_size = param[0].u.memref.size;
  64
  65        return 0;
  66}
  67
  68static int optee_register_device(const uuid_t *device_uuid, u32 device_id)
  69{
  70        struct tee_client_device *optee_device = NULL;
  71        int rc;
  72
  73        optee_device = kzalloc(sizeof(*optee_device), GFP_KERNEL);
  74        if (!optee_device)
  75                return -ENOMEM;
  76
  77        optee_device->dev.bus = &tee_bus_type;
  78        dev_set_name(&optee_device->dev, "optee-clnt%u", device_id);
  79        uuid_copy(&optee_device->id.uuid, device_uuid);
  80
  81        rc = device_register(&optee_device->dev);
  82        if (rc) {
  83                pr_err("device registration failed, err: %d\n", rc);
  84                kfree(optee_device);
  85        }
  86
  87        return rc;
  88}
  89
  90int optee_enumerate_devices(void)
  91{
  92        const uuid_t pta_uuid =
  93                UUID_INIT(0x7011a688, 0xddde, 0x4053,
  94                          0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8);
  95        struct tee_ioctl_open_session_arg sess_arg;
  96        struct tee_shm *device_shm = NULL;
  97        const uuid_t *device_uuid = NULL;
  98        struct tee_context *ctx = NULL;
  99        u32 shm_size = 0, idx, num_devices = 0;
 100        int rc;
 101
 102        memset(&sess_arg, 0, sizeof(sess_arg));
 103
 104        /* Open context with OP-TEE driver */
 105        ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
 106        if (IS_ERR(ctx))
 107                return -ENODEV;
 108
 109        /* Open session with device enumeration pseudo TA */
 110        memcpy(sess_arg.uuid, pta_uuid.b, TEE_IOCTL_UUID_LEN);
 111        sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
 112        sess_arg.num_params = 0;
 113
 114        rc = tee_client_open_session(ctx, &sess_arg, NULL);
 115        if ((rc < 0) || (sess_arg.ret != TEEC_SUCCESS)) {
 116                /* Device enumeration pseudo TA not found */
 117                rc = 0;
 118                goto out_ctx;
 119        }
 120
 121        rc = get_devices(ctx, sess_arg.session, NULL, &shm_size);
 122        if (rc < 0 || !shm_size)
 123                goto out_sess;
 124
 125        device_shm = tee_shm_alloc(ctx, shm_size,
 126                                   TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
 127        if (IS_ERR(device_shm)) {
 128                pr_err("tee_shm_alloc failed\n");
 129                rc = PTR_ERR(device_shm);
 130                goto out_sess;
 131        }
 132
 133        rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
 134        if (rc < 0)
 135                goto out_shm;
 136
 137        device_uuid = tee_shm_get_va(device_shm, 0);
 138        if (IS_ERR(device_uuid)) {
 139                pr_err("tee_shm_get_va failed\n");
 140                rc = PTR_ERR(device_uuid);
 141                goto out_shm;
 142        }
 143
 144        num_devices = shm_size / sizeof(uuid_t);
 145
 146        for (idx = 0; idx < num_devices; idx++) {
 147                rc = optee_register_device(&device_uuid[idx], idx);
 148                if (rc)
 149                        goto out_shm;
 150        }
 151
 152out_shm:
 153        tee_shm_free(device_shm);
 154out_sess:
 155        tee_client_close_session(ctx, sess_arg.session);
 156out_ctx:
 157        tee_client_close_context(ctx);
 158
 159        return rc;
 160}
 161