drivers: tee: optee: discover OP-TEE services
This change defines resources for OP-TEE service drivers to register themselves for being bound to when OP-TEE firmware reports the related service is supported. OP-TEE services are discovered during optee driver probe sequence which mandates optee driver is always probe once bound. Discovery of optee services and binding to related U-Boot drivers is embedded upon configuration switch CONFIG_OPTEE_SERVICE_DISCOVERY. Cc: Jens Wiklander <jens.wiklander@linaro.org> Cc: Patrick Delaunay <patrick.delaunay@foss.st.com> Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org> Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
This commit is contained in:
parent
fd0d7a6c88
commit
94ccfb78a4
@ -37,6 +37,14 @@ config OPTEE_TA_SCP03
|
||||
help
|
||||
Enables support for controlling (enabling, provisioning) the
|
||||
Secure Channel Protocol 03 operation in the OP-TEE SCP03 TA.
|
||||
|
||||
config OPTEE_SERVICE_DISCOVERY
|
||||
bool "OP-TEE service discovery"
|
||||
default y
|
||||
help
|
||||
This implements automated driver binding of OP-TEE service drivers by
|
||||
requesting OP-TEE firmware to enumerate its hosted services.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <tee/optee_service.h>
|
||||
|
||||
#include "optee_smc.h"
|
||||
#include "optee_msg.h"
|
||||
@ -22,6 +23,25 @@
|
||||
#define PAGELIST_ENTRIES_PER_PAGE \
|
||||
((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1)
|
||||
|
||||
/*
|
||||
* PTA_DEVICE_ENUM interface exposed by OP-TEE to discover enumerated services
|
||||
*/
|
||||
#define PTA_DEVICE_ENUM { 0x7011a688, 0xddde, 0x4053, \
|
||||
{ 0xa5, 0xa9, 0x7b, 0x3c, 0x4d, 0xdf, 0x13, 0xb8 } }
|
||||
/*
|
||||
* PTA_CMD_GET_DEVICES - List services without supplicant dependencies
|
||||
*
|
||||
* [out] memref[0]: List of the UUIDs of service enumerated by OP-TEE
|
||||
*/
|
||||
#define PTA_CMD_GET_DEVICES 0x0
|
||||
|
||||
/*
|
||||
* PTA_CMD_GET_DEVICES_SUPP - List services depending on tee supplicant
|
||||
*
|
||||
* [out] memref[0]: List of the UUIDs of service enumerated by OP-TEE
|
||||
*/
|
||||
#define PTA_CMD_GET_DEVICES_SUPP 0x1
|
||||
|
||||
typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long,
|
||||
unsigned long, unsigned long, unsigned long,
|
||||
unsigned long, unsigned long,
|
||||
@ -42,6 +62,134 @@ struct rpc_param {
|
||||
u32 a7;
|
||||
};
|
||||
|
||||
static struct optee_service *find_service_driver(const struct tee_optee_ta_uuid *uuid)
|
||||
{
|
||||
struct optee_service *service;
|
||||
u8 loc_uuid[TEE_UUID_LEN];
|
||||
size_t service_cnt, idx;
|
||||
|
||||
service_cnt = ll_entry_count(struct optee_service, optee_service);
|
||||
service = ll_entry_start(struct optee_service, optee_service);
|
||||
|
||||
for (idx = 0; idx < service_cnt; idx++, service++) {
|
||||
tee_optee_ta_uuid_to_octets(loc_uuid, &service->uuid);
|
||||
if (!memcmp(uuid, loc_uuid, sizeof(uuid)))
|
||||
return service;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int bind_service_list(struct udevice *dev, struct tee_shm *service_list, size_t count)
|
||||
{
|
||||
const struct tee_optee_ta_uuid *service_uuid = (const void *)service_list->addr;
|
||||
struct optee_service *service;
|
||||
size_t idx;
|
||||
int ret;
|
||||
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
service = find_service_driver(service_uuid + idx);
|
||||
if (!service)
|
||||
continue;
|
||||
|
||||
ret = device_bind_driver(dev, service->driver_name, service->driver_name, NULL);
|
||||
if (ret) {
|
||||
dev_warn(dev, "%s was not bound: %d, ignored\n", service->driver_name, ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __enum_services(struct udevice *dev, struct tee_shm *shm, size_t *shm_size, u32 tee_sess)
|
||||
{
|
||||
struct tee_invoke_arg arg = { };
|
||||
struct tee_param param = { };
|
||||
int ret = 0;
|
||||
|
||||
arg.func = PTA_CMD_GET_DEVICES;
|
||||
arg.session = tee_sess;
|
||||
|
||||
/* Fill invoke cmd params */
|
||||
param.attr = TEE_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
|
||||
param.u.memref.shm = shm;
|
||||
param.u.memref.size = *shm_size;
|
||||
|
||||
ret = tee_invoke_func(dev, &arg, 1, ¶m);
|
||||
if (ret || (arg.ret && arg.ret != TEE_ERROR_SHORT_BUFFER)) {
|
||||
dev_err(dev, "PTA_CMD_GET_DEVICES invoke function err: 0x%x\n", arg.ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*shm_size = param.u.memref.size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enum_services(struct udevice *dev, struct tee_shm **shm, size_t *count, u32 tee_sess)
|
||||
{
|
||||
size_t shm_size = 0;
|
||||
int ret;
|
||||
|
||||
ret = __enum_services(dev, NULL, &shm_size, tee_sess);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tee_shm_alloc(dev, shm_size, 0, shm);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to allocated shared memory: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = __enum_services(dev, *shm, &shm_size, tee_sess);
|
||||
if (!ret)
|
||||
*count = shm_size / sizeof(struct tee_optee_ta_uuid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int open_enum_session(struct udevice *dev, u32 *tee_sess)
|
||||
{
|
||||
const struct tee_optee_ta_uuid pta_uuid = PTA_DEVICE_ENUM;
|
||||
struct tee_open_session_arg arg = { };
|
||||
int ret;
|
||||
|
||||
tee_optee_ta_uuid_to_octets(arg.uuid, &pta_uuid);
|
||||
|
||||
ret = tee_open_session(dev, &arg, 0, NULL);
|
||||
if (ret || arg.ret) {
|
||||
if (!ret)
|
||||
ret = -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
*tee_sess = arg.session;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bind_service_drivers(struct udevice *dev)
|
||||
{
|
||||
struct tee_shm *service_list = NULL;
|
||||
size_t service_count;
|
||||
u32 tee_sess;
|
||||
int ret;
|
||||
|
||||
ret = open_enum_session(dev, &tee_sess);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = enum_services(dev, &service_list, &service_count, tee_sess);
|
||||
if (!ret)
|
||||
ret = bind_service_list(dev, service_list, service_count);
|
||||
|
||||
tee_shm_free(service_list);
|
||||
tee_close_session(dev, tee_sess);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* reg_pair_to_ptr() - Make a pointer of 2 32-bit values
|
||||
* @reg0: High bits of the pointer
|
||||
@ -638,6 +786,14 @@ static int optee_of_to_plat(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int optee_bind(struct udevice *dev)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_OPTEE_SERVICE_DISCOVERY))
|
||||
dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int optee_probe(struct udevice *dev)
|
||||
{
|
||||
struct optee_pdata *pdata = dev_get_plat(dev);
|
||||
@ -667,11 +823,15 @@ static int optee_probe(struct udevice *dev)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* in U-Boot, the discovery of TA on the TEE bus is not supported:
|
||||
* only bind the drivers associated to the supported OP-TEE TA
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_RNG_OPTEE)) {
|
||||
if (IS_ENABLED(CONFIG_OPTEE_SERVICE_DISCOVERY)) {
|
||||
ret = bind_service_drivers(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (IS_ENABLED(CONFIG_RNG_OPTEE)) {
|
||||
/*
|
||||
* Discovery of TAs on the TEE bus is not supported in U-Boot:
|
||||
* only bind the drivers associated to the supported OP-TEE TA
|
||||
*/
|
||||
ret = device_bind_driver(dev, "optee-rng", "optee-rng", NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -691,6 +851,7 @@ U_BOOT_DRIVER(optee) = {
|
||||
.of_match = optee_match,
|
||||
.of_to_plat = optee_of_to_plat,
|
||||
.probe = optee_probe,
|
||||
.bind = optee_bind,
|
||||
.ops = &optee_ops,
|
||||
.plat_auto = sizeof(struct optee_pdata),
|
||||
.priv_auto = sizeof(struct optee_private),
|
||||
|
34
include/tee/optee_service.h
Normal file
34
include/tee/optee_service.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* (C) Copyright 2022 Linaro Limited
|
||||
*/
|
||||
|
||||
#ifndef _OPTEE_SERVICE_H
|
||||
#define _OPTEE_SERVICE_H
|
||||
|
||||
/*
|
||||
* struct optee_service - Discoverable OP-TEE service
|
||||
*
|
||||
* @driver_name - Name of the related driver
|
||||
* @uuid - UUID of the OP-TEE service related to the driver
|
||||
*
|
||||
* Use macro OPTEE_SERVICE_DRIVER() to register a driver related to an
|
||||
* OP-TEE service discovered when driver asks OP-TEE services enumaration.
|
||||
*/
|
||||
struct optee_service {
|
||||
const char *driver_name;
|
||||
const struct tee_optee_ta_uuid uuid;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OPTEE_SERVICE_DISCOVERY
|
||||
#define OPTEE_SERVICE_DRIVER(__name, __uuid, __drv_name) \
|
||||
ll_entry_declare(struct optee_service, __name, optee_service) = { \
|
||||
.uuid = __uuid, \
|
||||
.driver_name = __drv_name, \
|
||||
}
|
||||
#else
|
||||
#define OPTEE_SERVICE_DRIVER(__name, __uuid, __drv_name) \
|
||||
static int __name##__COUNTER__ __always_unused
|
||||
#endif
|
||||
|
||||
#endif /* _OPTEE_SERVICE_H */
|
Loading…
Reference in New Issue
Block a user