mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02: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
					
				
					 11 changed files with 387 additions and 2 deletions
				
			
		
							
								
								
									
										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>
 | 
					R:	Sumit Garg <sumit.garg@linaro.org>
 | 
				
			||||||
L:	op-tee@lists.trustedfirmware.org
 | 
					L:	op-tee@lists.trustedfirmware.org
 | 
				
			||||||
S:	Maintained
 | 
					S:	Maintained
 | 
				
			||||||
 | 
					F:	Documentation/ABI/testing/sysfs-class-tee
 | 
				
			||||||
F:	Documentation/driver-api/tee.rst
 | 
					F:	Documentation/driver-api/tee.rst
 | 
				
			||||||
F:	Documentation/tee/
 | 
					F:	Documentation/tee/
 | 
				
			||||||
F:	Documentation/userspace-api/tee.rst
 | 
					F:	Documentation/userspace-api/tee.rst
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,17 +10,85 @@
 | 
				
			||||||
#include <linux/errno.h>
 | 
					#include <linux/errno.h>
 | 
				
			||||||
#include <linux/io.h>
 | 
					#include <linux/io.h>
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/rpmb.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/string.h>
 | 
					#include <linux/string.h>
 | 
				
			||||||
#include <linux/tee_core.h>
 | 
					#include <linux/tee_core.h>
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
#include "optee_private.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)
 | 
					static void optee_bus_scan(struct work_struct *work)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
 | 
						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)
 | 
					int optee_open(struct tee_context *ctx, bool cap_memref_null)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct optee_context_data *ctxdata;
 | 
						struct optee_context_data *ctxdata;
 | 
				
			||||||
| 
						 | 
					@ -97,6 +165,9 @@ void optee_release_supp(struct tee_context *ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void optee_remove_common(struct optee *optee)
 | 
					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 */
 | 
						/* Unregister OP-TEE specific client devices on TEE bus */
 | 
				
			||||||
	optee_unregister_devices();
 | 
						optee_unregister_devices();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,13 +184,18 @@ void optee_remove_common(struct optee *optee)
 | 
				
			||||||
	tee_shm_pool_free(optee->pool);
 | 
						tee_shm_pool_free(optee->pool);
 | 
				
			||||||
	optee_supp_uninit(&optee->supp);
 | 
						optee_supp_uninit(&optee->supp);
 | 
				
			||||||
	mutex_destroy(&optee->call_queue.mutex);
 | 
						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 smc_abi_rc;
 | 
				
			||||||
static int ffa_abi_rc;
 | 
					static int ffa_abi_rc;
 | 
				
			||||||
 | 
					static bool intf_is_regged;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init optee_core_init(void)
 | 
					static int __init optee_core_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The kernel may have crashed at the same time that all available
 | 
						 * The kernel may have crashed at the same time that all available
 | 
				
			||||||
	 * secure world threads were suspended and we cannot reschedule the
 | 
						 * 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())
 | 
						if (is_kdump_kernel())
 | 
				
			||||||
		return -ENODEV;
 | 
							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();
 | 
						smc_abi_rc = optee_smc_abi_register();
 | 
				
			||||||
	ffa_abi_rc = optee_ffa_abi_register();
 | 
						ffa_abi_rc = optee_ffa_abi_register();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If both failed there's no point with this module */
 | 
						/* 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 smc_abi_rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
module_init(optee_core_init);
 | 
					module_init(optee_core_init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __exit optee_core_exit(void)
 | 
					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)
 | 
						if (!smc_abi_rc)
 | 
				
			||||||
		optee_smc_abi_unregister();
 | 
							optee_smc_abi_unregister();
 | 
				
			||||||
	if (!ffa_abi_rc)
 | 
						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);
 | 
						ret = tee_client_invoke_func(ctx, &inv_arg, param);
 | 
				
			||||||
	if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) &&
 | 
						if ((ret < 0) || ((inv_arg.ret != TEEC_SUCCESS) &&
 | 
				
			||||||
			  (inv_arg.ret != TEEC_ERROR_SHORT_BUFFER))) {
 | 
								  (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",
 | 
							pr_err("PTA_CMD_GET_DEVICES invoke function err: %x\n",
 | 
				
			||||||
		       inv_arg.ret);
 | 
							       inv_arg.ret);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/arm_ffa.h>
 | 
					#include <linux/arm_ffa.h>
 | 
				
			||||||
#include <linux/errno.h>
 | 
					#include <linux/errno.h>
 | 
				
			||||||
 | 
					#include <linux/rpmb.h>
 | 
				
			||||||
#include <linux/scatterlist.h>
 | 
					#include <linux/scatterlist.h>
 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
#include <linux/slab.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->ffa.bottom_half_value = U32_MAX;
 | 
				
			||||||
	optee->rpc_param_count = rpc_param_count;
 | 
						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,
 | 
						teedev = tee_device_alloc(&optee_ffa_clnt_desc, NULL, optee->pool,
 | 
				
			||||||
				  optee);
 | 
									  optee);
 | 
				
			||||||
	if (IS_ERR(teedev)) {
 | 
						if (IS_ERR(teedev)) {
 | 
				
			||||||
| 
						 | 
					@ -925,6 +930,8 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	optee->supp_teedev = teedev;
 | 
						optee->supp_teedev = teedev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						optee_set_dev_group(optee);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = tee_device_register(optee->teedev);
 | 
						rc = tee_device_register(optee->teedev);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		goto err_unreg_supp_teedev;
 | 
							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_cq_init(&optee->call_queue, 0);
 | 
				
			||||||
	optee_supp_init(&optee->supp);
 | 
						optee_supp_init(&optee->supp);
 | 
				
			||||||
	optee_shm_arg_cache_init(optee, arg_cache_flags);
 | 
						optee_shm_arg_cache_init(optee, arg_cache_flags);
 | 
				
			||||||
 | 
						mutex_init(&optee->rpmb_dev_mutex);
 | 
				
			||||||
	ffa_dev_set_drvdata(ffa_dev, optee);
 | 
						ffa_dev_set_drvdata(ffa_dev, optee);
 | 
				
			||||||
	ctx = teedev_open(optee->teedev);
 | 
						ctx = teedev_open(optee->teedev);
 | 
				
			||||||
	if (IS_ERR(ctx)) {
 | 
						if (IS_ERR(ctx)) {
 | 
				
			||||||
| 
						 | 
					@ -961,6 +969,10 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		goto err_unregister_devices;
 | 
							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");
 | 
						pr_info("initialized driver\n");
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -974,6 +986,8 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
 | 
				
			||||||
	teedev_close_context(ctx);
 | 
						teedev_close_context(ctx);
 | 
				
			||||||
err_rhashtable_free:
 | 
					err_rhashtable_free:
 | 
				
			||||||
	rhashtable_free_and_destroy(&optee->ffa.global_ids, rh_free_fn, NULL);
 | 
						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);
 | 
						optee_supp_uninit(&optee->supp);
 | 
				
			||||||
	mutex_destroy(&optee->call_queue.mutex);
 | 
						mutex_destroy(&optee->call_queue.mutex);
 | 
				
			||||||
	mutex_destroy(&optee->ffa.mutex);
 | 
						mutex_destroy(&optee->ffa.mutex);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -92,6 +92,8 @@
 | 
				
			||||||
#define OPTEE_FFA_SEC_CAP_ARG_OFFSET	BIT(0)
 | 
					#define OPTEE_FFA_SEC_CAP_ARG_OFFSET	BIT(0)
 | 
				
			||||||
/* OP-TEE supports asynchronous notification via FF-A */
 | 
					/* OP-TEE supports asynchronous notification via FF-A */
 | 
				
			||||||
#define OPTEE_FFA_SEC_CAP_ASYNC_NOTIF	BIT(1)
 | 
					#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)
 | 
					#define OPTEE_FFA_EXCHANGE_CAPABILITIES OPTEE_FFA_BLOCKING_CALL(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,9 @@
 | 
				
			||||||
#define OPTEE_PRIVATE_H
 | 
					#define OPTEE_PRIVATE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/arm-smccc.h>
 | 
					#include <linux/arm-smccc.h>
 | 
				
			||||||
 | 
					#include <linux/notifier.h>
 | 
				
			||||||
#include <linux/rhashtable.h>
 | 
					#include <linux/rhashtable.h>
 | 
				
			||||||
 | 
					#include <linux/rpmb.h>
 | 
				
			||||||
#include <linux/semaphore.h>
 | 
					#include <linux/semaphore.h>
 | 
				
			||||||
#include <linux/tee_core.h>
 | 
					#include <linux/tee_core.h>
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
| 
						 | 
					@ -20,6 +22,7 @@
 | 
				
			||||||
/* Some Global Platform error codes used in this driver */
 | 
					/* Some Global Platform error codes used in this driver */
 | 
				
			||||||
#define TEEC_SUCCESS			0x00000000
 | 
					#define TEEC_SUCCESS			0x00000000
 | 
				
			||||||
#define TEEC_ERROR_BAD_PARAMETERS	0xFFFF0006
 | 
					#define TEEC_ERROR_BAD_PARAMETERS	0xFFFF0006
 | 
				
			||||||
 | 
					#define TEEC_ERROR_ITEM_NOT_FOUND	0xFFFF0008
 | 
				
			||||||
#define TEEC_ERROR_NOT_SUPPORTED	0xFFFF000A
 | 
					#define TEEC_ERROR_NOT_SUPPORTED	0xFFFF000A
 | 
				
			||||||
#define TEEC_ERROR_COMMUNICATION	0xFFFF000E
 | 
					#define TEEC_ERROR_COMMUNICATION	0xFFFF000E
 | 
				
			||||||
#define TEEC_ERROR_OUT_OF_MEMORY	0xFFFF000C
 | 
					#define TEEC_ERROR_OUT_OF_MEMORY	0xFFFF000C
 | 
				
			||||||
| 
						 | 
					@ -28,6 +31,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* API Return Codes are from the GP TEE Internal Core API Specification */
 | 
					/* API Return Codes are from the GP TEE Internal Core API Specification */
 | 
				
			||||||
#define TEE_ERROR_TIMEOUT		0xFFFF3001
 | 
					#define TEE_ERROR_TIMEOUT		0xFFFF3001
 | 
				
			||||||
 | 
					#define TEE_ERROR_STORAGE_NOT_AVAILABLE	0xF0100003
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TEEC_ORIGIN_COMMS		0x00000002
 | 
					#define TEEC_ORIGIN_COMMS		0x00000002
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,6 +204,12 @@ struct optee_ops {
 | 
				
			||||||
 * @notif:		notification synchronization struct
 | 
					 * @notif:		notification synchronization struct
 | 
				
			||||||
 * @supp:		supplicant synchronization struct for RPC to supplicant
 | 
					 * @supp:		supplicant synchronization struct for RPC to supplicant
 | 
				
			||||||
 * @pool:		shared memory pool
 | 
					 * @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
 | 
					 * @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_done	flag if device registation was already done.
 | 
				
			||||||
 * @scan_bus_work	workq to scan optee bus and register optee drivers
 | 
					 * @scan_bus_work	workq to scan optee bus and register optee drivers
 | 
				
			||||||
| 
						 | 
					@ -218,9 +228,16 @@ struct optee {
 | 
				
			||||||
	struct optee_notif notif;
 | 
						struct optee_notif notif;
 | 
				
			||||||
	struct optee_supp supp;
 | 
						struct optee_supp supp;
 | 
				
			||||||
	struct tee_shm_pool *pool;
 | 
						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;
 | 
						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 scan_bus_work;
 | 
				
			||||||
 | 
						struct work_struct rpmb_scan_bus_work;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct optee_session {
 | 
					struct optee_session {
 | 
				
			||||||
| 
						 | 
					@ -253,6 +270,8 @@ struct optee_call_ctx {
 | 
				
			||||||
	size_t num_entries;
 | 
						size_t num_entries;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct blocking_notifier_head optee_rpmb_intf_added;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int optee_notif_init(struct optee *optee, u_int max_key);
 | 
					int optee_notif_init(struct optee *optee, u_int max_key);
 | 
				
			||||||
void optee_notif_uninit(struct optee *optee);
 | 
					void optee_notif_uninit(struct optee *optee);
 | 
				
			||||||
int optee_notif_wait(struct optee *optee, u_int key, u32 timeout);
 | 
					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		0x0
 | 
				
			||||||
#define PTA_CMD_GET_DEVICES_SUPP	0x1
 | 
					#define PTA_CMD_GET_DEVICES_SUPP	0x1
 | 
				
			||||||
 | 
					#define PTA_CMD_GET_DEVICES_RPMB	0x2
 | 
				
			||||||
int optee_enumerate_devices(u32 func);
 | 
					int optee_enumerate_devices(u32 func);
 | 
				
			||||||
void optee_unregister_devices(void);
 | 
					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);
 | 
					void optee_remove_common(struct optee *optee);
 | 
				
			||||||
int optee_open(struct tee_context *ctx, bool cap_memref_null);
 | 
					int optee_open(struct tee_context *ctx, bool cap_memref_null);
 | 
				
			||||||
void optee_release(struct tee_context *ctx);
 | 
					void optee_release(struct tee_context *ctx);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,4 +104,39 @@
 | 
				
			||||||
/* I2C master control flags */
 | 
					/* I2C master control flags */
 | 
				
			||||||
#define OPTEE_RPC_I2C_FLAGS_TEN_BIT	BIT(0)
 | 
					#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*/
 | 
					#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)
 | 
					#define OPTEE_SMC_SEC_CAP_ASYNC_NOTIF		BIT(5)
 | 
				
			||||||
/* Secure world supports pre-allocating RPC arg struct */
 | 
					/* Secure world supports pre-allocating RPC arg struct */
 | 
				
			||||||
#define OPTEE_SMC_SEC_CAP_RPC_ARG		BIT(6)
 | 
					#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_FUNCID_EXCHANGE_CAPABILITIES	9
 | 
				
			||||||
#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
 | 
					#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/delay.h>
 | 
					#include <linux/delay.h>
 | 
				
			||||||
#include <linux/i2c.h>
 | 
					#include <linux/i2c.h>
 | 
				
			||||||
 | 
					#include <linux/rpmb.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/tee_core.h>
 | 
					#include <linux/tee_core.h>
 | 
				
			||||||
#include "optee_private.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);
 | 
						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,
 | 
					void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee,
 | 
				
			||||||
		   struct optee_msg_arg *arg)
 | 
							   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:
 | 
						case OPTEE_RPC_CMD_I2C_TRANSFER:
 | 
				
			||||||
		handle_rpc_func_cmd_i2c_transfer(ctx, arg);
 | 
							handle_rpc_func_cmd_i2c_transfer(ctx, arg);
 | 
				
			||||||
		break;
 | 
							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:
 | 
						default:
 | 
				
			||||||
		handle_rpc_supp_cmd(ctx, optee, arg);
 | 
							handle_rpc_supp_cmd(ctx, optee, arg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@
 | 
				
			||||||
#include <linux/of_irq.h>
 | 
					#include <linux/of_irq.h>
 | 
				
			||||||
#include <linux/of_platform.h>
 | 
					#include <linux/of_platform.h>
 | 
				
			||||||
#include <linux/platform_device.h>
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
 | 
					#include <linux/rpmb.h>
 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/string.h>
 | 
					#include <linux/string.h>
 | 
				
			||||||
| 
						 | 
					@ -1685,6 +1686,10 @@ static int optee_probe(struct platform_device *pdev)
 | 
				
			||||||
	optee->smc.sec_caps = sec_caps;
 | 
						optee->smc.sec_caps = sec_caps;
 | 
				
			||||||
	optee->rpc_param_count = rpc_param_count;
 | 
						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);
 | 
						teedev = tee_device_alloc(&optee_clnt_desc, NULL, pool, optee);
 | 
				
			||||||
	if (IS_ERR(teedev)) {
 | 
						if (IS_ERR(teedev)) {
 | 
				
			||||||
		rc = PTR_ERR(teedev);
 | 
							rc = PTR_ERR(teedev);
 | 
				
			||||||
| 
						 | 
					@ -1699,6 +1704,8 @@ static int optee_probe(struct platform_device *pdev)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	optee->supp_teedev = teedev;
 | 
						optee->supp_teedev = teedev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						optee_set_dev_group(optee);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = tee_device_register(optee->teedev);
 | 
						rc = tee_device_register(optee->teedev);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		goto err_unreg_supp_teedev;
 | 
							goto err_unreg_supp_teedev;
 | 
				
			||||||
| 
						 | 
					@ -1712,6 +1719,7 @@ static int optee_probe(struct platform_device *pdev)
 | 
				
			||||||
	optee->smc.memremaped_shm = memremaped_shm;
 | 
						optee->smc.memremaped_shm = memremaped_shm;
 | 
				
			||||||
	optee->pool = pool;
 | 
						optee->pool = pool;
 | 
				
			||||||
	optee_shm_arg_cache_init(optee, arg_cache_flags);
 | 
						optee_shm_arg_cache_init(optee, arg_cache_flags);
 | 
				
			||||||
 | 
						mutex_init(&optee->rpmb_dev_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	platform_set_drvdata(pdev, optee);
 | 
						platform_set_drvdata(pdev, optee);
 | 
				
			||||||
	ctx = teedev_open(optee->teedev);
 | 
						ctx = teedev_open(optee->teedev);
 | 
				
			||||||
| 
						 | 
					@ -1766,6 +1774,10 @@ static int optee_probe(struct platform_device *pdev)
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
		goto err_disable_shm_cache;
 | 
							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");
 | 
						pr_info("initialized driver\n");
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1779,6 +1791,8 @@ static int optee_probe(struct platform_device *pdev)
 | 
				
			||||||
err_close_ctx:
 | 
					err_close_ctx:
 | 
				
			||||||
	teedev_close_context(ctx);
 | 
						teedev_close_context(ctx);
 | 
				
			||||||
err_supp_uninit:
 | 
					err_supp_uninit:
 | 
				
			||||||
 | 
						rpmb_dev_put(optee->rpmb_dev);
 | 
				
			||||||
 | 
						mutex_destroy(&optee->rpmb_dev_mutex);
 | 
				
			||||||
	optee_shm_arg_cache_uninit(optee);
 | 
						optee_shm_arg_cache_uninit(optee);
 | 
				
			||||||
	optee_supp_uninit(&optee->supp);
 | 
						optee_supp_uninit(&optee->supp);
 | 
				
			||||||
	mutex_destroy(&optee->call_queue.mutex);
 | 
						mutex_destroy(&optee->call_queue.mutex);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue