mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 06:01:57 +00:00
optee: probe RPMB device using RPMB subsystem
Adds support in the OP-TEE drivers (both SMC and FF-A ABIs) to probe and use an RPMB device via the RPMB subsystem instead of passing the RPMB frames via tee-supplicant in user space. A fallback mechanism is kept to route RPMB frames via tee-supplicant if the RPMB subsystem isn't available. The OP-TEE RPC ABI is extended to support iterating over all RPMB devices until one is found with the expected RPMB key already programmed. Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org> Tested-by: Manuel Traut <manut@mecka.net> Reviewed-by: Sumit Garg <sumit.garg@linaro.org> Link: https://lore.kernel.org/r/20240814153558.708365-5-jens.wiklander@linaro.org Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
c30b855e81
commit
f0c8431568
15
Documentation/ABI/testing/sysfs-class-tee
Normal file
15
Documentation/ABI/testing/sysfs-class-tee
Normal file
@ -0,0 +1,15 @@
|
||||
What: /sys/class/tee/tee{,priv}X/rpmb_routing_model
|
||||
Date: May 2024
|
||||
KernelVersion: 6.10
|
||||
Contact: op-tee@lists.trustedfirmware.org
|
||||
Description:
|
||||
RPMB frames can be routed to the RPMB device via the
|
||||
user-space daemon tee-supplicant or the RPMB subsystem
|
||||
in the kernel. The value "user" means that the driver
|
||||
will route the RPMB frames via user space. Conversely,
|
||||
"kernel" means that the frames are routed via the RPMB
|
||||
subsystem without assistance from tee-supplicant. It
|
||||
should be assumed that RPMB frames are routed via user
|
||||
space if the variable is absent. The primary purpose
|
||||
of this variable is to let systemd know whether
|
||||
tee-supplicant is needed in the early boot with initramfs.
|
@ -22458,6 +22458,7 @@ M: Jens Wiklander <jens.wiklander@linaro.org>
|
||||
R: Sumit Garg <sumit.garg@linaro.org>
|
||||
L: op-tee@lists.trustedfirmware.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-class-tee
|
||||
F: Documentation/driver-api/tee.rst
|
||||
F: Documentation/tee/
|
||||
F: Documentation/userspace-api/tee.rst
|
||||
|
@ -10,17 +10,85 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rpmb.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/tee_core.h>
|
||||
#include <linux/types.h>
|
||||
#include "optee_private.h"
|
||||
|
||||
struct blocking_notifier_head optee_rpmb_intf_added =
|
||||
BLOCKING_NOTIFIER_INIT(optee_rpmb_intf_added);
|
||||
|
||||
static int rpmb_add_dev(struct device *dev)
|
||||
{
|
||||
blocking_notifier_call_chain(&optee_rpmb_intf_added, 0,
|
||||
to_rpmb_dev(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct class_interface rpmb_class_intf = {
|
||||
.add_dev = rpmb_add_dev,
|
||||
};
|
||||
|
||||
void optee_bus_scan_rpmb(struct work_struct *work)
|
||||
{
|
||||
struct optee *optee = container_of(work, struct optee,
|
||||
rpmb_scan_bus_work);
|
||||
int ret;
|
||||
|
||||
if (!optee->rpmb_scan_bus_done) {
|
||||
ret = optee_enumerate_devices(PTA_CMD_GET_DEVICES_RPMB);
|
||||
optee->rpmb_scan_bus_done = !ret;
|
||||
if (ret && ret != -ENODEV)
|
||||
pr_info("Scanning for RPMB device: ret %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
int optee_rpmb_intf_rdev(struct notifier_block *intf, unsigned long action,
|
||||
void *data)
|
||||
{
|
||||
struct optee *optee = container_of(intf, struct optee, rpmb_intf);
|
||||
|
||||
schedule_work(&optee->rpmb_scan_bus_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void optee_bus_scan(struct work_struct *work)
|
||||
{
|
||||
WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
|
||||
}
|
||||
|
||||
static ssize_t rpmb_routing_model_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct optee *optee = dev_get_drvdata(dev);
|
||||
const char *s;
|
||||
|
||||
if (optee->in_kernel_rpmb_routing)
|
||||
s = "kernel";
|
||||
else
|
||||
s = "user";
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", s);
|
||||
}
|
||||
static DEVICE_ATTR_RO(rpmb_routing_model);
|
||||
|
||||
static struct attribute *optee_dev_attrs[] = {
|
||||
&dev_attr_rpmb_routing_model.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(optee_dev);
|
||||
|
||||
void optee_set_dev_group(struct optee *optee)
|
||||
{
|
||||
tee_device_set_dev_groups(optee->teedev, optee_dev_groups);
|
||||
tee_device_set_dev_groups(optee->supp_teedev, optee_dev_groups);
|
||||
}
|
||||
|
||||
int optee_open(struct tee_context *ctx, bool cap_memref_null)
|
||||
{
|
||||
struct optee_context_data *ctxdata;
|
||||
@ -97,6 +165,9 @@ void optee_release_supp(struct tee_context *ctx)
|
||||
|
||||
void optee_remove_common(struct optee *optee)
|
||||
{
|
||||
blocking_notifier_chain_unregister(&optee_rpmb_intf_added,
|
||||
&optee->rpmb_intf);
|
||||
cancel_work_sync(&optee->rpmb_scan_bus_work);
|
||||
/* Unregister OP-TEE specific client devices on TEE bus */
|
||||
optee_unregister_devices();
|
||||
|
||||
@ -113,13 +184,18 @@ void optee_remove_common(struct optee *optee)
|
||||
tee_shm_pool_free(optee->pool);
|
||||
optee_supp_uninit(&optee->supp);
|
||||
mutex_destroy(&optee->call_queue.mutex);
|
||||
rpmb_dev_put(optee->rpmb_dev);
|
||||
mutex_destroy(&optee->rpmb_dev_mutex);
|
||||
}
|
||||
|
||||
static int smc_abi_rc;
|
||||
static int ffa_abi_rc;
|
||||
static bool intf_is_regged;
|
||||
|
||||
static int __init optee_core_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* The kernel may have crashed at the same time that all available
|
||||
* secure world threads were suspended and we cannot reschedule the
|
||||
@ -130,18 +206,36 @@ static int __init optee_core_init(void)
|
||||
if (is_kdump_kernel())
|
||||
return -ENODEV;
|
||||
|
||||
if (IS_REACHABLE(CONFIG_RPMB)) {
|
||||
rc = rpmb_interface_register(&rpmb_class_intf);
|
||||
if (rc)
|
||||
return rc;
|
||||
intf_is_regged = true;
|
||||
}
|
||||
|
||||
smc_abi_rc = optee_smc_abi_register();
|
||||
ffa_abi_rc = optee_ffa_abi_register();
|
||||
|
||||
/* If both failed there's no point with this module */
|
||||
if (smc_abi_rc && ffa_abi_rc)
|
||||
if (smc_abi_rc && ffa_abi_rc) {
|
||||
if (IS_REACHABLE(CONFIG_RPMB)) {
|
||||
rpmb_interface_unregister(&rpmb_class_intf);
|
||||
intf_is_regged = false;
|
||||
}
|
||||
return smc_abi_rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(optee_core_init);
|
||||
|
||||
static void __exit optee_core_exit(void)
|
||||
{
|
||||
if (IS_REACHABLE(CONFIG_RPMB) && intf_is_regged) {
|
||||
rpmb_interface_unregister(&rpmb_class_intf);
|
||||
intf_is_regged = false;
|
||||
}
|
||||
|
||||
if (!smc_abi_rc)
|
||||
optee_smc_abi_unregister();
|
||||
if (!ffa_abi_rc)
|
||||
|
@ -43,6 +43,13 @@ static int get_devices(struct tee_context *ctx, u32 session,
|
||||
ret = tee_client_invoke_func(ctx, &inv_arg, param);
|
||||
if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) &&
|
||||
(inv_arg.ret != TEEC_ERROR_SHORT_BUFFER))) {
|
||||
/*
|
||||
* TEE_ERROR_STORAGE_NOT_AVAILABLE is returned when getting
|
||||
* the list of device TAs that depends on RPMB but a usable
|
||||
* RPMB device isn't found.
|
||||
*/
|
||||
if (inv_arg.ret == TEE_ERROR_STORAGE_NOT_AVAILABLE)
|
||||
return -ENODEV;
|
||||
pr_err("PTA_CMD_GET_DEVICES invoke function err: %x\n",
|
||||
inv_arg.ret);
|
||||
return -EINVAL;
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/arm_ffa.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/rpmb.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
@ -909,6 +910,10 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
|
||||
optee->ffa.bottom_half_value = U32_MAX;
|
||||
optee->rpc_param_count = rpc_param_count;
|
||||
|
||||
if (IS_REACHABLE(CONFIG_RPMB) &&
|
||||
(sec_caps & OPTEE_FFA_SEC_CAP_RPMB_PROBE))
|
||||
optee->in_kernel_rpmb_routing = true;
|
||||
|
||||
teedev = tee_device_alloc(&optee_ffa_clnt_desc, NULL, optee->pool,
|
||||
optee);
|
||||
if (IS_ERR(teedev)) {
|
||||
@ -925,6 +930,8 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
|
||||
}
|
||||
optee->supp_teedev = teedev;
|
||||
|
||||
optee_set_dev_group(optee);
|
||||
|
||||
rc = tee_device_register(optee->teedev);
|
||||
if (rc)
|
||||
goto err_unreg_supp_teedev;
|
||||
@ -940,6 +947,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
|
||||
optee_cq_init(&optee->call_queue, 0);
|
||||
optee_supp_init(&optee->supp);
|
||||
optee_shm_arg_cache_init(optee, arg_cache_flags);
|
||||
mutex_init(&optee->rpmb_dev_mutex);
|
||||
ffa_dev_set_drvdata(ffa_dev, optee);
|
||||
ctx = teedev_open(optee->teedev);
|
||||
if (IS_ERR(ctx)) {
|
||||
@ -961,6 +969,10 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
|
||||
if (rc)
|
||||
goto err_unregister_devices;
|
||||
|
||||
INIT_WORK(&optee->rpmb_scan_bus_work, optee_bus_scan_rpmb);
|
||||
optee->rpmb_intf.notifier_call = optee_rpmb_intf_rdev;
|
||||
blocking_notifier_chain_register(&optee_rpmb_intf_added,
|
||||
&optee->rpmb_intf);
|
||||
pr_info("initialized driver\n");
|
||||
return 0;
|
||||
|
||||
@ -974,6 +986,8 @@ err_close_ctx:
|
||||
teedev_close_context(ctx);
|
||||
err_rhashtable_free:
|
||||
rhashtable_free_and_destroy(&optee->ffa.global_ids, rh_free_fn, NULL);
|
||||
rpmb_dev_put(optee->rpmb_dev);
|
||||
mutex_destroy(&optee->rpmb_dev_mutex);
|
||||
optee_supp_uninit(&optee->supp);
|
||||
mutex_destroy(&optee->call_queue.mutex);
|
||||
mutex_destroy(&optee->ffa.mutex);
|
||||
|
@ -92,6 +92,8 @@
|
||||
#define OPTEE_FFA_SEC_CAP_ARG_OFFSET BIT(0)
|
||||
/* OP-TEE supports asynchronous notification via FF-A */
|
||||
#define OPTEE_FFA_SEC_CAP_ASYNC_NOTIF BIT(1)
|
||||
/* OP-TEE supports probing for RPMB device if needed */
|
||||
#define OPTEE_FFA_SEC_CAP_RPMB_PROBE BIT(2)
|
||||
|
||||
#define OPTEE_FFA_EXCHANGE_CAPABILITIES OPTEE_FFA_BLOCKING_CALL(2)
|
||||
|
||||
|
@ -7,7 +7,9 @@
|
||||
#define OPTEE_PRIVATE_H
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/rhashtable.h>
|
||||
#include <linux/rpmb.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/tee_core.h>
|
||||
#include <linux/types.h>
|
||||
@ -20,6 +22,7 @@
|
||||
/* Some Global Platform error codes used in this driver */
|
||||
#define TEEC_SUCCESS 0x00000000
|
||||
#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
|
||||
#define TEEC_ERROR_ITEM_NOT_FOUND 0xFFFF0008
|
||||
#define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A
|
||||
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
|
||||
#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
|
||||
@ -28,6 +31,7 @@
|
||||
|
||||
/* API Return Codes are from the GP TEE Internal Core API Specification */
|
||||
#define TEE_ERROR_TIMEOUT 0xFFFF3001
|
||||
#define TEE_ERROR_STORAGE_NOT_AVAILABLE 0xF0100003
|
||||
|
||||
#define TEEC_ORIGIN_COMMS 0x00000002
|
||||
|
||||
@ -200,6 +204,12 @@ struct optee_ops {
|
||||
* @notif: notification synchronization struct
|
||||
* @supp: supplicant synchronization struct for RPC to supplicant
|
||||
* @pool: shared memory pool
|
||||
* @mutex: mutex protecting @rpmb_dev
|
||||
* @rpmb_dev: current RPMB device or NULL
|
||||
* @rpmb_scan_bus_done flag if device registation of RPMB dependent devices
|
||||
* was already done
|
||||
* @rpmb_scan_bus_work workq to for an RPMB device and to scan optee bus
|
||||
* and register RPMB dependent optee drivers
|
||||
* @rpc_param_count: If > 0 number of RPC parameters to make room for
|
||||
* @scan_bus_done flag if device registation was already done.
|
||||
* @scan_bus_work workq to scan optee bus and register optee drivers
|
||||
@ -218,9 +228,16 @@ struct optee {
|
||||
struct optee_notif notif;
|
||||
struct optee_supp supp;
|
||||
struct tee_shm_pool *pool;
|
||||
/* Protects rpmb_dev pointer */
|
||||
struct mutex rpmb_dev_mutex;
|
||||
struct rpmb_dev *rpmb_dev;
|
||||
struct notifier_block rpmb_intf;
|
||||
unsigned int rpc_param_count;
|
||||
bool scan_bus_done;
|
||||
bool scan_bus_done;
|
||||
bool rpmb_scan_bus_done;
|
||||
bool in_kernel_rpmb_routing;
|
||||
struct work_struct scan_bus_work;
|
||||
struct work_struct rpmb_scan_bus_work;
|
||||
};
|
||||
|
||||
struct optee_session {
|
||||
@ -253,6 +270,8 @@ struct optee_call_ctx {
|
||||
size_t num_entries;
|
||||
};
|
||||
|
||||
extern struct blocking_notifier_head optee_rpmb_intf_added;
|
||||
|
||||
int optee_notif_init(struct optee *optee, u_int max_key);
|
||||
void optee_notif_uninit(struct optee *optee);
|
||||
int optee_notif_wait(struct optee *optee, u_int key, u32 timeout);
|
||||
@ -283,9 +302,14 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
|
||||
|
||||
#define PTA_CMD_GET_DEVICES 0x0
|
||||
#define PTA_CMD_GET_DEVICES_SUPP 0x1
|
||||
#define PTA_CMD_GET_DEVICES_RPMB 0x2
|
||||
int optee_enumerate_devices(u32 func);
|
||||
void optee_unregister_devices(void);
|
||||
void optee_bus_scan_rpmb(struct work_struct *work);
|
||||
int optee_rpmb_intf_rdev(struct notifier_block *intf, unsigned long action,
|
||||
void *data);
|
||||
|
||||
void optee_set_dev_group(struct optee *optee);
|
||||
void optee_remove_common(struct optee *optee);
|
||||
int optee_open(struct tee_context *ctx, bool cap_memref_null);
|
||||
void optee_release(struct tee_context *ctx);
|
||||
|
@ -104,4 +104,39 @@
|
||||
/* I2C master control flags */
|
||||
#define OPTEE_RPC_I2C_FLAGS_TEN_BIT BIT(0)
|
||||
|
||||
/*
|
||||
* Reset RPMB probing
|
||||
*
|
||||
* Releases an eventually already used RPMB devices and starts over searching
|
||||
* for RPMB devices. Returns the kind of shared memory to use in subsequent
|
||||
* OPTEE_RPC_CMD_RPMB_PROBE_NEXT and OPTEE_RPC_CMD_RPMB calls.
|
||||
*
|
||||
* [out] value[0].a OPTEE_RPC_SHM_TYPE_*, the parameter for
|
||||
* OPTEE_RPC_CMD_SHM_ALLOC
|
||||
*/
|
||||
#define OPTEE_RPC_CMD_RPMB_PROBE_RESET 22
|
||||
|
||||
/*
|
||||
* Probe next RPMB device
|
||||
*
|
||||
* [out] value[0].a Type of RPMB device, OPTEE_RPC_RPMB_*
|
||||
* [out] value[0].b EXT CSD-slice 168 "RPMB Size"
|
||||
* [out] value[0].c EXT CSD-slice 222 "Reliable Write Sector Count"
|
||||
* [out] memref[1] Buffer with the raw CID
|
||||
*/
|
||||
#define OPTEE_RPC_CMD_RPMB_PROBE_NEXT 23
|
||||
|
||||
/* Type of RPMB device */
|
||||
#define OPTEE_RPC_RPMB_EMMC 0
|
||||
#define OPTEE_RPC_RPMB_UFS 1
|
||||
#define OPTEE_RPC_RPMB_NVME 2
|
||||
|
||||
/*
|
||||
* Replay Protected Memory Block access
|
||||
*
|
||||
* [in] memref[0] Frames to device
|
||||
* [out] memref[1] Frames from device
|
||||
*/
|
||||
#define OPTEE_RPC_CMD_RPMB_FRAMES 24
|
||||
|
||||
#endif /*__OPTEE_RPC_CMD_H*/
|
||||
|
@ -278,6 +278,8 @@ struct optee_smc_get_shm_config_result {
|
||||
#define OPTEE_SMC_SEC_CAP_ASYNC_NOTIF BIT(5)
|
||||
/* Secure world supports pre-allocating RPC arg struct */
|
||||
#define OPTEE_SMC_SEC_CAP_RPC_ARG BIT(6)
|
||||
/* Secure world supports probing for RPMB device if needed */
|
||||
#define OPTEE_SMC_SEC_CAP_RPMB_PROBE BIT(7)
|
||||
|
||||
#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
|
||||
#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/rpmb.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tee_core.h>
|
||||
#include "optee_private.h"
|
||||
@ -261,6 +262,154 @@ void optee_rpc_cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
|
||||
optee_supp_thrd_req(ctx, OPTEE_RPC_CMD_SHM_FREE, 1, ¶m);
|
||||
}
|
||||
|
||||
static void handle_rpc_func_rpmb_probe_reset(struct tee_context *ctx,
|
||||
struct optee *optee,
|
||||
struct optee_msg_arg *arg)
|
||||
{
|
||||
struct tee_param params[1];
|
||||
|
||||
if (arg->num_params != ARRAY_SIZE(params) ||
|
||||
optee->ops->from_msg_param(optee, params, arg->num_params,
|
||||
arg->params) ||
|
||||
params[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
return;
|
||||
}
|
||||
|
||||
params[0].u.value.a = OPTEE_RPC_SHM_TYPE_KERNEL;
|
||||
params[0].u.value.b = 0;
|
||||
params[0].u.value.c = 0;
|
||||
if (optee->ops->to_msg_param(optee, arg->params,
|
||||
arg->num_params, params)) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&optee->rpmb_dev_mutex);
|
||||
rpmb_dev_put(optee->rpmb_dev);
|
||||
optee->rpmb_dev = NULL;
|
||||
mutex_unlock(&optee->rpmb_dev_mutex);
|
||||
|
||||
arg->ret = TEEC_SUCCESS;
|
||||
}
|
||||
|
||||
static int rpmb_type_to_rpc_type(enum rpmb_type rtype)
|
||||
{
|
||||
switch (rtype) {
|
||||
case RPMB_TYPE_EMMC:
|
||||
return OPTEE_RPC_RPMB_EMMC;
|
||||
case RPMB_TYPE_UFS:
|
||||
return OPTEE_RPC_RPMB_UFS;
|
||||
case RPMB_TYPE_NVME:
|
||||
return OPTEE_RPC_RPMB_NVME;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int rpc_rpmb_match(struct device *dev, const void *data)
|
||||
{
|
||||
struct rpmb_dev *rdev = to_rpmb_dev(dev);
|
||||
|
||||
return rpmb_type_to_rpc_type(rdev->descr.type) >= 0;
|
||||
}
|
||||
|
||||
static void handle_rpc_func_rpmb_probe_next(struct tee_context *ctx,
|
||||
struct optee *optee,
|
||||
struct optee_msg_arg *arg)
|
||||
{
|
||||
struct rpmb_dev *rdev;
|
||||
struct tee_param params[2];
|
||||
void *buf;
|
||||
|
||||
if (arg->num_params != ARRAY_SIZE(params) ||
|
||||
optee->ops->from_msg_param(optee, params, arg->num_params,
|
||||
arg->params) ||
|
||||
params[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT ||
|
||||
params[1].attr != TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
return;
|
||||
}
|
||||
buf = tee_shm_get_va(params[1].u.memref.shm,
|
||||
params[1].u.memref.shm_offs);
|
||||
if (!buf) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&optee->rpmb_dev_mutex);
|
||||
rdev = rpmb_dev_find_device(NULL, optee->rpmb_dev, rpc_rpmb_match);
|
||||
rpmb_dev_put(optee->rpmb_dev);
|
||||
optee->rpmb_dev = rdev;
|
||||
mutex_unlock(&optee->rpmb_dev_mutex);
|
||||
|
||||
if (!rdev) {
|
||||
arg->ret = TEEC_ERROR_ITEM_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
|
||||
if (params[1].u.memref.size < rdev->descr.dev_id_len) {
|
||||
arg->ret = TEEC_ERROR_SHORT_BUFFER;
|
||||
return;
|
||||
}
|
||||
memcpy(buf, rdev->descr.dev_id, rdev->descr.dev_id_len);
|
||||
params[1].u.memref.size = rdev->descr.dev_id_len;
|
||||
params[0].u.value.a = rpmb_type_to_rpc_type(rdev->descr.type);
|
||||
params[0].u.value.b = rdev->descr.capacity;
|
||||
params[0].u.value.c = rdev->descr.reliable_wr_count;
|
||||
if (optee->ops->to_msg_param(optee, arg->params,
|
||||
arg->num_params, params)) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
return;
|
||||
}
|
||||
|
||||
arg->ret = TEEC_SUCCESS;
|
||||
}
|
||||
|
||||
static void handle_rpc_func_rpmb_frames(struct tee_context *ctx,
|
||||
struct optee *optee,
|
||||
struct optee_msg_arg *arg)
|
||||
{
|
||||
struct tee_param params[2];
|
||||
struct rpmb_dev *rdev;
|
||||
void *p0, *p1;
|
||||
|
||||
mutex_lock(&optee->rpmb_dev_mutex);
|
||||
rdev = rpmb_dev_get(optee->rpmb_dev);
|
||||
mutex_unlock(&optee->rpmb_dev_mutex);
|
||||
if (!rdev) {
|
||||
arg->ret = TEEC_ERROR_ITEM_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg->num_params != ARRAY_SIZE(params) ||
|
||||
optee->ops->from_msg_param(optee, params, arg->num_params,
|
||||
arg->params) ||
|
||||
params[0].attr != TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT ||
|
||||
params[1].attr != TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p0 = tee_shm_get_va(params[0].u.memref.shm,
|
||||
params[0].u.memref.shm_offs);
|
||||
p1 = tee_shm_get_va(params[1].u.memref.shm,
|
||||
params[1].u.memref.shm_offs);
|
||||
if (rpmb_route_frames(rdev, p0, params[0].u.memref.size, p1,
|
||||
params[1].u.memref.size)) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
goto out;
|
||||
}
|
||||
if (optee->ops->to_msg_param(optee, arg->params,
|
||||
arg->num_params, params)) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
goto out;
|
||||
}
|
||||
arg->ret = TEEC_SUCCESS;
|
||||
out:
|
||||
rpmb_dev_put(rdev);
|
||||
}
|
||||
|
||||
void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee,
|
||||
struct optee_msg_arg *arg)
|
||||
{
|
||||
@ -277,6 +426,34 @@ void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee,
|
||||
case OPTEE_RPC_CMD_I2C_TRANSFER:
|
||||
handle_rpc_func_cmd_i2c_transfer(ctx, arg);
|
||||
break;
|
||||
/*
|
||||
* optee->in_kernel_rpmb_routing true means that OP-TEE supports
|
||||
* in-kernel RPMB routing _and_ that the RPMB subsystem is
|
||||
* reachable. This is reported to user space with
|
||||
* rpmb_routing_model=kernel in sysfs.
|
||||
*
|
||||
* rpmb_routing_model=kernel is also a promise to user space that
|
||||
* RPMB access will not require supplicant support, hence the
|
||||
* checks below.
|
||||
*/
|
||||
case OPTEE_RPC_CMD_RPMB_PROBE_RESET:
|
||||
if (optee->in_kernel_rpmb_routing)
|
||||
handle_rpc_func_rpmb_probe_reset(ctx, optee, arg);
|
||||
else
|
||||
handle_rpc_supp_cmd(ctx, optee, arg);
|
||||
break;
|
||||
case OPTEE_RPC_CMD_RPMB_PROBE_NEXT:
|
||||
if (optee->in_kernel_rpmb_routing)
|
||||
handle_rpc_func_rpmb_probe_next(ctx, optee, arg);
|
||||
else
|
||||
handle_rpc_supp_cmd(ctx, optee, arg);
|
||||
break;
|
||||
case OPTEE_RPC_CMD_RPMB_FRAMES:
|
||||
if (optee->in_kernel_rpmb_routing)
|
||||
handle_rpc_func_rpmb_frames(ctx, optee, arg);
|
||||
else
|
||||
handle_rpc_supp_cmd(ctx, optee, arg);
|
||||
break;
|
||||
default:
|
||||
handle_rpc_supp_cmd(ctx, optee, arg);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rpmb.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
@ -1685,6 +1686,10 @@ static int optee_probe(struct platform_device *pdev)
|
||||
optee->smc.sec_caps = sec_caps;
|
||||
optee->rpc_param_count = rpc_param_count;
|
||||
|
||||
if (IS_REACHABLE(CONFIG_RPMB) &&
|
||||
(sec_caps & OPTEE_SMC_SEC_CAP_RPMB_PROBE))
|
||||
optee->in_kernel_rpmb_routing = true;
|
||||
|
||||
teedev = tee_device_alloc(&optee_clnt_desc, NULL, pool, optee);
|
||||
if (IS_ERR(teedev)) {
|
||||
rc = PTR_ERR(teedev);
|
||||
@ -1699,6 +1704,8 @@ static int optee_probe(struct platform_device *pdev)
|
||||
}
|
||||
optee->supp_teedev = teedev;
|
||||
|
||||
optee_set_dev_group(optee);
|
||||
|
||||
rc = tee_device_register(optee->teedev);
|
||||
if (rc)
|
||||
goto err_unreg_supp_teedev;
|
||||
@ -1712,6 +1719,7 @@ static int optee_probe(struct platform_device *pdev)
|
||||
optee->smc.memremaped_shm = memremaped_shm;
|
||||
optee->pool = pool;
|
||||
optee_shm_arg_cache_init(optee, arg_cache_flags);
|
||||
mutex_init(&optee->rpmb_dev_mutex);
|
||||
|
||||
platform_set_drvdata(pdev, optee);
|
||||
ctx = teedev_open(optee->teedev);
|
||||
@ -1766,6 +1774,10 @@ static int optee_probe(struct platform_device *pdev)
|
||||
if (rc)
|
||||
goto err_disable_shm_cache;
|
||||
|
||||
INIT_WORK(&optee->rpmb_scan_bus_work, optee_bus_scan_rpmb);
|
||||
optee->rpmb_intf.notifier_call = optee_rpmb_intf_rdev;
|
||||
blocking_notifier_chain_register(&optee_rpmb_intf_added,
|
||||
&optee->rpmb_intf);
|
||||
pr_info("initialized driver\n");
|
||||
return 0;
|
||||
|
||||
@ -1779,6 +1791,8 @@ err_notif_uninit:
|
||||
err_close_ctx:
|
||||
teedev_close_context(ctx);
|
||||
err_supp_uninit:
|
||||
rpmb_dev_put(optee->rpmb_dev);
|
||||
mutex_destroy(&optee->rpmb_dev_mutex);
|
||||
optee_shm_arg_cache_uninit(optee);
|
||||
optee_supp_uninit(&optee->supp);
|
||||
mutex_destroy(&optee->call_queue.mutex);
|
||||
|
Loading…
Reference in New Issue
Block a user