Introduce TEE bus driver framework
- supp_nowait flag for non-blocking tee requests - The tee bus driver framework - OP-TEE TEE bus device enumeration support - An OP-TEE based rng driver -----BEGIN PGP SIGNATURE----- iQJOBAABCgA4FiEEcK3MsDvGvFp6zV9ztbC4QZeP7NMFAlxUwVoaHGplbnMud2lr bGFuZGVyQGxpbmFyby5vcmcACgkQtbC4QZeP7NMzCA//S0fLom4hKSz8hgfpXBxR 0RsOiEBE+LGIfShBx+tj+yzG0DPvRBsa4lbvX/uKdPJk/1giazi0lJn3GPQf0XOU Lfdb03hyoKknK5AoPm3N8AceyP9FMkT/813Moxrc35FgQV6OvSGGmjtXs+NQ5SbZ m7YV/zJIkGbNzfRiyN389AtbV95UpNDs7FjTw/d/CZ/U9mRSHAvR1zAUXMgcPpwI XcdhIfgWe0bPjYsX3EmxCRPM0MKrG1LQDB95dkH6+uKM9Fh2MYb+6P5bXlETM5DI ruMupkT+iXXLye2pDPZC1G8Czhqy55qYSTCz3fKZt/onhCUghT9W9yUoxZyvvsEP 6Yf7vDjcBVGfUyvdUEpkmjpjejgbzEkZVxvC+9S8PzPzdWqLD6fHAj+IHkq1mjc7 joqRcpfkTqldvcDpBVoN4QchTs/1ERNPvs+XG7auBSkB9tPAIQP72UBxVxnzq4QM RSJETWND3eylCw08wXrPngbBAejyGDnl2oBnuR0PqVtEWDMiJvkoRl/1F8CxnDM6 aKk2XlslgAQdwnEpN4h1Z+Nnn/KtYoQ3cDHZoGMQ6ktVdUeNvicL1FcbioWCGnI6 mu6pw2i0UKNxFSTLUn8+32Ao9pe4dLsJcOYMZyGQHdnG4M53pCJRRgqh1Bil1s63 4NvqHsa62AUqyRPeQSCj1IU= =So4a -----END PGP SIGNATURE----- Merge tag 'tee-bus-for-5.1' of https://git.linaro.org/people/jens.wiklander/linux-tee into arm/drivers Introduce TEE bus driver framework - supp_nowait flag for non-blocking tee requests - The tee bus driver framework - OP-TEE TEE bus device enumeration support - An OP-TEE based rng driver * tag 'tee-bus-for-5.1' of https://git.linaro.org/people/jens.wiklander/linux-tee: hwrng: add OP-TEE based rng driver tee: optee: add TEE bus device enumeration support tee: add bus driver framework for TEE based devices tee: add supp_nowait flag in tee_context struct
This commit is contained in:
commit
dea73a34e0
|
@ -11264,6 +11264,11 @@ M: Jens Wiklander <jens.wiklander@linaro.org>
|
|||
S: Maintained
|
||||
F: drivers/tee/optee/
|
||||
|
||||
OP-TEE RANDOM NUMBER GENERATOR (RNG) DRIVER
|
||||
M: Sumit Garg <sumit.garg@linaro.org>
|
||||
S: Maintained
|
||||
F: drivers/char/hw_random/optee-rng.c
|
||||
|
||||
OPA-VNIC DRIVER
|
||||
M: Dennis Dalessandro <dennis.dalessandro@intel.com>
|
||||
M: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
|
||||
|
|
|
@ -424,6 +424,21 @@ config HW_RANDOM_EXYNOS
|
|||
will be called exynos-trng.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config HW_RANDOM_OPTEE
|
||||
tristate "OP-TEE based Random Number Generator support"
|
||||
depends on OPTEE
|
||||
default HW_RANDOM
|
||||
help
|
||||
This driver provides support for OP-TEE based Random Number
|
||||
Generator on ARM SoCs where hardware entropy sources are not
|
||||
accessible to normal world (Linux).
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called optee-rng.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
endif # HW_RANDOM
|
||||
|
||||
config UML_RANDOM
|
||||
|
|
|
@ -38,3 +38,4 @@ obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o
|
|||
obj-$(CONFIG_HW_RANDOM_MTK) += mtk-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_S390) += s390-trng.o
|
||||
obj-$(CONFIG_HW_RANDOM_KEYSTONE) += ks-sa-rng.o
|
||||
obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o
|
||||
|
|
|
@ -0,0 +1,298 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/hw_random.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tee_drv.h>
|
||||
#include <linux/uuid.h>
|
||||
|
||||
#define DRIVER_NAME "optee-rng"
|
||||
|
||||
#define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
|
||||
|
||||
/*
|
||||
* TA_CMD_GET_ENTROPY - Get Entropy from RNG
|
||||
*
|
||||
* param[0] (inout memref) - Entropy buffer memory reference
|
||||
* param[1] unused
|
||||
* param[2] unused
|
||||
* param[3] unused
|
||||
*
|
||||
* Result:
|
||||
* TEE_SUCCESS - Invoke command success
|
||||
* TEE_ERROR_BAD_PARAMETERS - Incorrect input param
|
||||
* TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool
|
||||
* TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed
|
||||
*/
|
||||
#define TA_CMD_GET_ENTROPY 0x0
|
||||
|
||||
/*
|
||||
* TA_CMD_GET_RNG_INFO - Get RNG information
|
||||
*
|
||||
* param[0] (out value) - value.a: RNG data-rate in bytes per second
|
||||
* value.b: Quality/Entropy per 1024 bit of data
|
||||
* param[1] unused
|
||||
* param[2] unused
|
||||
* param[3] unused
|
||||
*
|
||||
* Result:
|
||||
* TEE_SUCCESS - Invoke command success
|
||||
* TEE_ERROR_BAD_PARAMETERS - Incorrect input param
|
||||
*/
|
||||
#define TA_CMD_GET_RNG_INFO 0x1
|
||||
|
||||
#define MAX_ENTROPY_REQ_SZ (4 * 1024)
|
||||
|
||||
/**
|
||||
* struct optee_rng_private - OP-TEE Random Number Generator private data
|
||||
* @dev: OP-TEE based RNG device.
|
||||
* @ctx: OP-TEE context handler.
|
||||
* @session_id: RNG TA session identifier.
|
||||
* @data_rate: RNG data rate.
|
||||
* @entropy_shm_pool: Memory pool shared with RNG device.
|
||||
* @optee_rng: OP-TEE RNG driver structure.
|
||||
*/
|
||||
struct optee_rng_private {
|
||||
struct device *dev;
|
||||
struct tee_context *ctx;
|
||||
u32 session_id;
|
||||
u32 data_rate;
|
||||
struct tee_shm *entropy_shm_pool;
|
||||
struct hwrng optee_rng;
|
||||
};
|
||||
|
||||
#define to_optee_rng_private(r) \
|
||||
container_of(r, struct optee_rng_private, optee_rng)
|
||||
|
||||
static size_t get_optee_rng_data(struct optee_rng_private *pvt_data,
|
||||
void *buf, size_t req_size)
|
||||
{
|
||||
u32 ret = 0;
|
||||
u8 *rng_data = NULL;
|
||||
size_t rng_size = 0;
|
||||
struct tee_ioctl_invoke_arg inv_arg = {0};
|
||||
struct tee_param param[4] = {0};
|
||||
|
||||
/* Invoke TA_CMD_GET_ENTROPY function of Trusted App */
|
||||
inv_arg.func = TA_CMD_GET_ENTROPY;
|
||||
inv_arg.session = pvt_data->session_id;
|
||||
inv_arg.num_params = 4;
|
||||
|
||||
/* Fill invoke cmd params */
|
||||
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
|
||||
param[0].u.memref.shm = pvt_data->entropy_shm_pool;
|
||||
param[0].u.memref.size = req_size;
|
||||
param[0].u.memref.shm_offs = 0;
|
||||
|
||||
ret = tee_client_invoke_func(pvt_data->ctx, &inv_arg, param);
|
||||
if ((ret < 0) || (inv_arg.ret != 0)) {
|
||||
dev_err(pvt_data->dev, "TA_CMD_GET_ENTROPY invoke err: %x\n",
|
||||
inv_arg.ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rng_data = tee_shm_get_va(pvt_data->entropy_shm_pool, 0);
|
||||
if (IS_ERR(rng_data)) {
|
||||
dev_err(pvt_data->dev, "tee_shm_get_va failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rng_size = param[0].u.memref.size;
|
||||
memcpy(buf, rng_data, rng_size);
|
||||
|
||||
return rng_size;
|
||||
}
|
||||
|
||||
static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
|
||||
{
|
||||
struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
|
||||
size_t read = 0, rng_size = 0;
|
||||
int timeout = 1;
|
||||
u8 *data = buf;
|
||||
|
||||
if (max > MAX_ENTROPY_REQ_SZ)
|
||||
max = MAX_ENTROPY_REQ_SZ;
|
||||
|
||||
while (read == 0) {
|
||||
rng_size = get_optee_rng_data(pvt_data, data, (max - read));
|
||||
|
||||
data += rng_size;
|
||||
read += rng_size;
|
||||
|
||||
if (wait) {
|
||||
if (timeout-- == 0)
|
||||
return read;
|
||||
msleep((1000 * (max - read)) / pvt_data->data_rate);
|
||||
} else {
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
static int optee_rng_init(struct hwrng *rng)
|
||||
{
|
||||
struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
|
||||
struct tee_shm *entropy_shm_pool = NULL;
|
||||
|
||||
entropy_shm_pool = tee_shm_alloc(pvt_data->ctx, MAX_ENTROPY_REQ_SZ,
|
||||
TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
|
||||
if (IS_ERR(entropy_shm_pool)) {
|
||||
dev_err(pvt_data->dev, "tee_shm_alloc failed\n");
|
||||
return PTR_ERR(entropy_shm_pool);
|
||||
}
|
||||
|
||||
pvt_data->entropy_shm_pool = entropy_shm_pool;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void optee_rng_cleanup(struct hwrng *rng)
|
||||
{
|
||||
struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
|
||||
|
||||
tee_shm_free(pvt_data->entropy_shm_pool);
|
||||
}
|
||||
|
||||
static struct optee_rng_private pvt_data = {
|
||||
.optee_rng = {
|
||||
.name = DRIVER_NAME,
|
||||
.init = optee_rng_init,
|
||||
.cleanup = optee_rng_cleanup,
|
||||
.read = optee_rng_read,
|
||||
}
|
||||
};
|
||||
|
||||
static int get_optee_rng_info(struct device *dev)
|
||||
{
|
||||
u32 ret = 0;
|
||||
struct tee_ioctl_invoke_arg inv_arg = {0};
|
||||
struct tee_param param[4] = {0};
|
||||
|
||||
/* Invoke TA_CMD_GET_RNG_INFO function of Trusted App */
|
||||
inv_arg.func = TA_CMD_GET_RNG_INFO;
|
||||
inv_arg.session = pvt_data.session_id;
|
||||
inv_arg.num_params = 4;
|
||||
|
||||
/* Fill invoke cmd params */
|
||||
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
|
||||
|
||||
ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param);
|
||||
if ((ret < 0) || (inv_arg.ret != 0)) {
|
||||
dev_err(dev, "TA_CMD_GET_RNG_INFO invoke err: %x\n",
|
||||
inv_arg.ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pvt_data.data_rate = param[0].u.value.a;
|
||||
pvt_data.optee_rng.quality = param[0].u.value.b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
|
||||
{
|
||||
if (ver->impl_id == TEE_IMPL_ID_OPTEE)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int optee_rng_probe(struct device *dev)
|
||||
{
|
||||
struct tee_client_device *rng_device = to_tee_client_device(dev);
|
||||
int ret = 0, err = -ENODEV;
|
||||
struct tee_ioctl_open_session_arg sess_arg = {0};
|
||||
|
||||
/* Open context with TEE driver */
|
||||
pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL,
|
||||
NULL);
|
||||
if (IS_ERR(pvt_data.ctx))
|
||||
return -ENODEV;
|
||||
|
||||
/* Open session with hwrng Trusted App */
|
||||
memcpy(sess_arg.uuid, rng_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
|
||||
sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
|
||||
sess_arg.num_params = 0;
|
||||
|
||||
ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL);
|
||||
if ((ret < 0) || (sess_arg.ret != 0)) {
|
||||
dev_err(dev, "tee_client_open_session failed, err: %x\n",
|
||||
sess_arg.ret);
|
||||
err = -EINVAL;
|
||||
goto out_ctx;
|
||||
}
|
||||
pvt_data.session_id = sess_arg.session;
|
||||
|
||||
err = get_optee_rng_info(dev);
|
||||
if (err)
|
||||
goto out_sess;
|
||||
|
||||
err = hwrng_register(&pvt_data.optee_rng);
|
||||
if (err) {
|
||||
dev_err(dev, "hwrng registration failed (%d)\n", err);
|
||||
goto out_sess;
|
||||
}
|
||||
|
||||
pvt_data.dev = dev;
|
||||
|
||||
return 0;
|
||||
|
||||
out_sess:
|
||||
tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
|
||||
out_ctx:
|
||||
tee_client_close_context(pvt_data.ctx);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int optee_rng_remove(struct device *dev)
|
||||
{
|
||||
hwrng_unregister(&pvt_data.optee_rng);
|
||||
tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
|
||||
tee_client_close_context(pvt_data.ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct tee_client_device_id optee_rng_id_table[] = {
|
||||
{UUID_INIT(0xab7a617c, 0xb8e7, 0x4d8f,
|
||||
0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64)},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(tee, optee_rng_id_table);
|
||||
|
||||
static struct tee_client_driver optee_rng_driver = {
|
||||
.id_table = optee_rng_id_table,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.bus = &tee_bus_type,
|
||||
.probe = optee_rng_probe,
|
||||
.remove = optee_rng_remove,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init optee_rng_mod_init(void)
|
||||
{
|
||||
return driver_register(&optee_rng_driver.driver);
|
||||
}
|
||||
|
||||
static void __exit optee_rng_mod_exit(void)
|
||||
{
|
||||
driver_unregister(&optee_rng_driver.driver);
|
||||
}
|
||||
|
||||
module_init(optee_rng_mod_init);
|
||||
module_exit(optee_rng_mod_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Sumit Garg <sumit.garg@linaro.org>");
|
||||
MODULE_DESCRIPTION("OP-TEE based random number generator driver");
|
|
@ -5,3 +5,4 @@ optee-objs += call.o
|
|||
optee-objs += rpc.o
|
||||
optee-objs += supp.o
|
||||
optee-objs += shm_pool.o
|
||||
optee-objs += device.o
|
||||
|
|
|
@ -634,6 +634,10 @@ static struct optee *optee_probe(struct device_node *np)
|
|||
if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
|
||||
pr_info("dynamic shared memory is enabled\n");
|
||||
|
||||
rc = optee_enumerate_devices();
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
pr_info("initialized driver\n");
|
||||
return optee;
|
||||
err:
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2019 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tee_drv.h>
|
||||
#include <linux/uuid.h>
|
||||
#include "optee_private.h"
|
||||
|
||||
/*
|
||||
* Get device UUIDs
|
||||
*
|
||||
* [out] memref[0] Array of device UUIDs
|
||||
*
|
||||
* Return codes:
|
||||
* TEE_SUCCESS - Invoke command success
|
||||
* TEE_ERROR_BAD_PARAMETERS - Incorrect input param
|
||||
* TEE_ERROR_SHORT_BUFFER - Output buffer size less than required
|
||||
*/
|
||||
#define PTA_CMD_GET_DEVICES 0x0
|
||||
|
||||
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
|
||||
{
|
||||
if (ver->impl_id == TEE_IMPL_ID_OPTEE)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_devices(struct tee_context *ctx, u32 session,
|
||||
struct tee_shm *device_shm, u32 *shm_size)
|
||||
{
|
||||
u32 ret = 0;
|
||||
struct tee_ioctl_invoke_arg inv_arg = {0};
|
||||
struct tee_param param[4] = {0};
|
||||
|
||||
/* Invoke PTA_CMD_GET_DEVICES function */
|
||||
inv_arg.func = PTA_CMD_GET_DEVICES;
|
||||
inv_arg.session = session;
|
||||
inv_arg.num_params = 4;
|
||||
|
||||
/* Fill invoke cmd params */
|
||||
param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
|
||||
param[0].u.memref.shm = device_shm;
|
||||
param[0].u.memref.size = *shm_size;
|
||||
param[0].u.memref.shm_offs = 0;
|
||||
|
||||
ret = tee_client_invoke_func(ctx, &inv_arg, param);
|
||||
if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) &&
|
||||
(inv_arg.ret != TEEC_ERROR_SHORT_BUFFER))) {
|
||||
pr_err("PTA_CMD_GET_DEVICES invoke function err: %x\n",
|
||||
inv_arg.ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*shm_size = param[0].u.memref.size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int optee_register_device(const uuid_t *device_uuid, u32 device_id)
|
||||
{
|
||||
struct tee_client_device *optee_device = NULL;
|
||||
int rc;
|
||||
|
||||
optee_device = kzalloc(sizeof(*optee_device), GFP_KERNEL);
|
||||
if (!optee_device)
|
||||
return -ENOMEM;
|
||||
|
||||
optee_device->dev.bus = &tee_bus_type;
|
||||
dev_set_name(&optee_device->dev, "optee-clnt%u", device_id);
|
||||
uuid_copy(&optee_device->id.uuid, device_uuid);
|
||||
|
||||
rc = device_register(&optee_device->dev);
|
||||
if (rc) {
|
||||
pr_err("device registration failed, err: %d\n", rc);
|
||||
kfree(optee_device);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int optee_enumerate_devices(void)
|
||||
{
|
||||
const uuid_t pta_uuid =
|
||||
UUID_INIT(0x7011a688, 0xddde, 0x4053,
|
||||
0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8);
|
||||
struct tee_ioctl_open_session_arg sess_arg = {0};
|
||||
struct tee_shm *device_shm = NULL;
|
||||
const uuid_t *device_uuid = NULL;
|
||||
struct tee_context *ctx = NULL;
|
||||
u32 shm_size = 0, idx, num_devices = 0;
|
||||
int rc;
|
||||
|
||||
/* Open context with OP-TEE driver */
|
||||
ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
|
||||
if (IS_ERR(ctx))
|
||||
return -ENODEV;
|
||||
|
||||
/* Open session with device enumeration pseudo TA */
|
||||
memcpy(sess_arg.uuid, pta_uuid.b, TEE_IOCTL_UUID_LEN);
|
||||
sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
|
||||
sess_arg.num_params = 0;
|
||||
|
||||
rc = tee_client_open_session(ctx, &sess_arg, NULL);
|
||||
if ((rc < 0) || (sess_arg.ret != TEEC_SUCCESS)) {
|
||||
/* Device enumeration pseudo TA not found */
|
||||
rc = 0;
|
||||
goto out_ctx;
|
||||
}
|
||||
|
||||
rc = get_devices(ctx, sess_arg.session, NULL, &shm_size);
|
||||
if (rc < 0 || !shm_size)
|
||||
goto out_sess;
|
||||
|
||||
device_shm = tee_shm_alloc(ctx, shm_size,
|
||||
TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
|
||||
if (IS_ERR(device_shm)) {
|
||||
pr_err("tee_shm_alloc failed\n");
|
||||
rc = PTR_ERR(device_shm);
|
||||
goto out_sess;
|
||||
}
|
||||
|
||||
rc = get_devices(ctx, sess_arg.session, device_shm, &shm_size);
|
||||
if (rc < 0)
|
||||
goto out_shm;
|
||||
|
||||
device_uuid = tee_shm_get_va(device_shm, 0);
|
||||
if (IS_ERR(device_uuid)) {
|
||||
pr_err("tee_shm_get_va failed\n");
|
||||
rc = PTR_ERR(device_uuid);
|
||||
goto out_shm;
|
||||
}
|
||||
|
||||
num_devices = shm_size / sizeof(uuid_t);
|
||||
|
||||
for (idx = 0; idx < num_devices; idx++) {
|
||||
rc = optee_register_device(&device_uuid[idx], idx);
|
||||
if (rc)
|
||||
goto out_shm;
|
||||
}
|
||||
|
||||
out_shm:
|
||||
tee_shm_free(device_shm);
|
||||
out_sess:
|
||||
tee_client_close_session(ctx, sess_arg.session);
|
||||
out_ctx:
|
||||
tee_client_close_context(ctx);
|
||||
|
||||
return rc;
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
|
||||
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
|
||||
#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
|
||||
#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
|
||||
|
||||
#define TEEC_ORIGIN_COMMS 0x00000002
|
||||
|
||||
|
@ -181,6 +182,8 @@ void optee_free_pages_list(void *array, size_t num_entries);
|
|||
void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
|
||||
size_t page_offset);
|
||||
|
||||
int optee_enumerate_devices(void);
|
||||
|
||||
/*
|
||||
* Small helpers
|
||||
*/
|
||||
|
|
|
@ -88,10 +88,18 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
|
|||
{
|
||||
struct optee *optee = tee_get_drvdata(ctx->teedev);
|
||||
struct optee_supp *supp = &optee->supp;
|
||||
struct optee_supp_req *req = kzalloc(sizeof(*req), GFP_KERNEL);
|
||||
struct optee_supp_req *req;
|
||||
bool interruptable;
|
||||
u32 ret;
|
||||
|
||||
/*
|
||||
* Return in case there is no supplicant available and
|
||||
* non-blocking request.
|
||||
*/
|
||||
if (!supp->ctx && ctx->supp_nowait)
|
||||
return TEEC_ERROR_COMMUNICATION;
|
||||
|
||||
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
||||
if (!req)
|
||||
return TEEC_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -106,6 +105,11 @@ static int tee_open(struct inode *inode, struct file *filp)
|
|||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
||||
/*
|
||||
* Default user-space behaviour is to wait for tee-supplicant
|
||||
* if not present for any requests in this context.
|
||||
*/
|
||||
ctx->supp_nowait = false;
|
||||
filp->private_data = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
@ -982,6 +986,14 @@ tee_client_open_context(struct tee_context *start,
|
|||
} while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM);
|
||||
|
||||
put_device(put_dev);
|
||||
/*
|
||||
* Default behaviour for in kernel client is to not wait for
|
||||
* tee-supplicant if not present for any requests in this context.
|
||||
* Also this flag could be configured again before call to
|
||||
* tee_client_open_session() if any in kernel client requires
|
||||
* different behaviour.
|
||||
*/
|
||||
ctx->supp_nowait = true;
|
||||
return ctx;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tee_client_open_context);
|
||||
|
@ -1027,6 +1039,39 @@ int tee_client_invoke_func(struct tee_context *ctx,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tee_client_invoke_func);
|
||||
|
||||
static int tee_client_device_match(struct device *dev,
|
||||
struct device_driver *drv)
|
||||
{
|
||||
const struct tee_client_device_id *id_table;
|
||||
struct tee_client_device *tee_device;
|
||||
|
||||
id_table = to_tee_client_driver(drv)->id_table;
|
||||
tee_device = to_tee_client_device(dev);
|
||||
|
||||
while (!uuid_is_null(&id_table->uuid)) {
|
||||
if (uuid_equal(&tee_device->id.uuid, &id_table->uuid))
|
||||
return 1;
|
||||
id_table++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tee_client_device_uevent(struct device *dev,
|
||||
struct kobj_uevent_env *env)
|
||||
{
|
||||
uuid_t *dev_id = &to_tee_client_device(dev)->id.uuid;
|
||||
|
||||
return add_uevent_var(env, "MODALIAS=tee:%pUb", dev_id);
|
||||
}
|
||||
|
||||
struct bus_type tee_bus_type = {
|
||||
.name = "tee",
|
||||
.match = tee_client_device_match,
|
||||
.uevent = tee_client_device_uevent,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(tee_bus_type);
|
||||
|
||||
static int __init tee_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
@ -1040,18 +1085,32 @@ static int __init tee_init(void)
|
|||
rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee");
|
||||
if (rc) {
|
||||
pr_err("failed to allocate char dev region\n");
|
||||
goto out_unreg_class;
|
||||
}
|
||||
|
||||
rc = bus_register(&tee_bus_type);
|
||||
if (rc) {
|
||||
pr_err("failed to register tee bus\n");
|
||||
goto out_unreg_chrdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_unreg_chrdev:
|
||||
unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
|
||||
out_unreg_class:
|
||||
class_destroy(tee_class);
|
||||
tee_class = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit tee_exit(void)
|
||||
{
|
||||
bus_unregister(&tee_bus_type);
|
||||
unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
|
||||
class_destroy(tee_class);
|
||||
tee_class = NULL;
|
||||
unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
|
||||
}
|
||||
|
||||
subsys_initcall(tee_init);
|
||||
|
|
|
@ -779,4 +779,13 @@ struct typec_device_id {
|
|||
kernel_ulong_t driver_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_client_device_id - tee based device identifier
|
||||
* @uuid: For TEE based client devices we use the device uuid as
|
||||
* the identifier.
|
||||
*/
|
||||
struct tee_client_device_id {
|
||||
uuid_t uuid;
|
||||
};
|
||||
|
||||
#endif /* LINUX_MOD_DEVICETABLE_H */
|
||||
|
|
|
@ -15,11 +15,14 @@
|
|||
#ifndef __TEE_DRV_H
|
||||
#define __TEE_DRV_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/tee.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uuid.h>
|
||||
|
||||
/*
|
||||
* The file describes the API provided by the generic TEE driver to the
|
||||
|
@ -47,6 +50,11 @@ struct tee_shm_pool;
|
|||
* @releasing: flag that indicates if context is being released right now.
|
||||
* It is needed to break circular dependency on context during
|
||||
* shared memory release.
|
||||
* @supp_nowait: flag that indicates that requests in this context should not
|
||||
* wait for tee-supplicant daemon to be started if not present
|
||||
* and just return with an error code. It is needed for requests
|
||||
* that arises from TEE based kernel drivers that should be
|
||||
* non-blocking in nature.
|
||||
*/
|
||||
struct tee_context {
|
||||
struct tee_device *teedev;
|
||||
|
@ -54,6 +62,7 @@ struct tee_context {
|
|||
void *data;
|
||||
struct kref refcount;
|
||||
bool releasing;
|
||||
bool supp_nowait;
|
||||
};
|
||||
|
||||
struct tee_param_memref {
|
||||
|
@ -538,4 +547,31 @@ static inline bool tee_param_is_memref(struct tee_param *param)
|
|||
}
|
||||
}
|
||||
|
||||
extern struct bus_type tee_bus_type;
|
||||
|
||||
/**
|
||||
* struct tee_client_device - tee based device
|
||||
* @id: device identifier
|
||||
* @dev: device structure
|
||||
*/
|
||||
struct tee_client_device {
|
||||
struct tee_client_device_id id;
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
#define to_tee_client_device(d) container_of(d, struct tee_client_device, dev)
|
||||
|
||||
/**
|
||||
* struct tee_client_driver - tee client driver
|
||||
* @id_table: device id table supported by this driver
|
||||
* @driver: driver structure
|
||||
*/
|
||||
struct tee_client_driver {
|
||||
const struct tee_client_device_id *id_table;
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
#define to_tee_client_driver(d) \
|
||||
container_of(d, struct tee_client_driver, driver)
|
||||
|
||||
#endif /*__TEE_DRV_H*/
|
||||
|
|
|
@ -225,5 +225,8 @@ int main(void)
|
|||
DEVID_FIELD(typec_device_id, svid);
|
||||
DEVID_FIELD(typec_device_id, mode);
|
||||
|
||||
DEVID(tee_client_device_id);
|
||||
DEVID_FIELD(tee_client_device_id, uuid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,9 @@ typedef unsigned char __u8;
|
|||
typedef struct {
|
||||
__u8 b[16];
|
||||
} uuid_le;
|
||||
typedef struct {
|
||||
__u8 b[16];
|
||||
} uuid_t;
|
||||
|
||||
/* Big exception to the "don't include kernel headers into userspace, which
|
||||
* even potentially has different endianness and word sizes, since
|
||||
|
@ -1287,6 +1290,21 @@ static int do_typec_entry(const char *filename, void *symval, char *alias)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Looks like: tee:uuid */
|
||||
static int do_tee_entry(const char *filename, void *symval, char *alias)
|
||||
{
|
||||
DEF_FIELD(symval, tee_client_device_id, uuid);
|
||||
|
||||
sprintf(alias, "tee:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
uuid.b[0], uuid.b[1], uuid.b[2], uuid.b[3], uuid.b[4],
|
||||
uuid.b[5], uuid.b[6], uuid.b[7], uuid.b[8], uuid.b[9],
|
||||
uuid.b[10], uuid.b[11], uuid.b[12], uuid.b[13], uuid.b[14],
|
||||
uuid.b[15]);
|
||||
|
||||
add_wildcard(alias);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Does namelen bytes of name exactly match the symbol? */
|
||||
static bool sym_is(const char *name, unsigned namelen, const char *symbol)
|
||||
{
|
||||
|
@ -1357,6 +1375,7 @@ static const struct devtable devtable[] = {
|
|||
{"fslmc", SIZE_fsl_mc_device_id, do_fsl_mc_entry},
|
||||
{"tbsvc", SIZE_tb_service_id, do_tbsvc_entry},
|
||||
{"typec", SIZE_typec_device_id, do_typec_entry},
|
||||
{"tee", SIZE_tee_client_device_id, do_tee_entry},
|
||||
};
|
||||
|
||||
/* Create MODULE_ALIAS() statements.
|
||||
|
|
Loading…
Reference in New Issue