diff options
-rw-r--r-- | drivers/trusty/Makefile | 2 | ||||
-rw-r--r-- | drivers/trusty/trusty-sched-share-api.h | 19 | ||||
-rw-r--r-- | drivers/trusty/trusty-sched-share.c | 220 | ||||
-rw-r--r-- | drivers/trusty/trusty-sched-share.h | 58 | ||||
-rw-r--r-- | drivers/trusty/trusty.c | 6 | ||||
-rw-r--r-- | include/linux/trusty/smcall.h | 30 |
6 files changed, 334 insertions, 1 deletions
diff --git a/drivers/trusty/Makefile b/drivers/trusty/Makefile index 2cf1cfc..42424ad 100644 --- a/drivers/trusty/Makefile +++ b/drivers/trusty/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_TRUSTY) += trusty-core.o -trusty-core-objs += trusty.o trusty-mem.o +trusty-core-objs += trusty.o trusty-mem.o trusty-sched-share.o trusty-core-$(CONFIG_ARM) += trusty-smc-arm.o trusty-core-$(CONFIG_ARM64) += trusty-smc-arm64.o obj-$(CONFIG_TRUSTY_IRQ) += trusty-irq.o diff --git a/drivers/trusty/trusty-sched-share-api.h b/drivers/trusty/trusty-sched-share-api.h new file mode 100644 index 0000000..e2726e6 --- /dev/null +++ b/drivers/trusty/trusty-sched-share-api.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (c) 2022 Google, Inc. + * + * This header file contains the definitions of APIs, used for the + * registration/unregistration of shared-memory used for the + * exchange of info between the Linux Trusty-Driver and the Trusty-Kernel. + */ +#ifndef _TRUSTY_SCHED_SHARE_API_H_ +#define _TRUSTY_SCHED_SHARE_API_H_ + +#include <linux/device.h> + +struct trusty_sched_share_state; + +struct trusty_sched_share_state *trusty_register_sched_share(struct device *device); +void trusty_unregister_sched_share(struct trusty_sched_share_state *sched_share_state); + +#endif /* _TRUSTY_SCHED_SHARE_API_H_ */ diff --git a/drivers/trusty/trusty-sched-share.c b/drivers/trusty/trusty-sched-share.c new file mode 100644 index 0000000..0072739 --- /dev/null +++ b/drivers/trusty/trusty-sched-share.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 Google, Inc. + * + * This trusty-driver module contains the SMC API for the trusty-driver to + * communicate with the trusty-kernel for shared memory + * registration/unregistration. + */ + +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/scatterlist.h> +#include <linux/trusty/trusty.h> +#include "trusty-sched-share.h" + +/** + * struct trusty_sched_share_state - Trusty share resources state local to Trusty-Driver + * @dev: ptr to the trusty-device instance + * @sg: ptr to the scatter-gather list used for shared-memory buffers + * @sched_shared_mem_id: trusty-priority shared-memory id + * @sched_shared_vm: vm ptr to the shared-memory block + * @mem_size: size of trusty shared-memory block in bytes + * @buf_size: page-aligned size of trusty shared-memory buffer in bytes + * @num_pages: number of pages containing the allocated shared-memory buffer + */ +struct trusty_sched_share_state { + struct device *dev; + struct scatterlist *sg; + trusty_shared_mem_id_t sched_shared_mem_id; + char *sched_shared_vm; + u32 mem_size; + u32 buf_size; + u32 num_pages; +}; + +static int +trusty_sched_share_resources_allocate(struct trusty_sched_share_state *share_state) +{ + struct scatterlist *sg; + struct trusty_sched_shared *shared; + unsigned char *mem; + trusty_shared_mem_id_t mem_id; + int result = 0; + int i; + + share_state->mem_size = sizeof(struct trusty_sched_shared) + + nr_cpu_ids * sizeof(struct trusty_percpu_data); + share_state->num_pages = + round_up(share_state->mem_size, PAGE_SIZE) / PAGE_SIZE; + share_state->buf_size = share_state->num_pages * PAGE_SIZE; + + dev_dbg(share_state->dev, + "%s: mem_size=%d, num_pages=%d, buf_size=%d", __func__, + share_state->mem_size, share_state->num_pages, + share_state->buf_size); + + share_state->sg = kcalloc(share_state->num_pages, + sizeof(*share_state->sg), GFP_KERNEL); + if (!share_state->sg) { + result = ENOMEM; + goto err_rsrc_alloc_sg; + } + + mem = vzalloc(share_state->buf_size); + if (!mem) { + result = -ENOMEM; + goto err_rsrc_alloc_mem; + } + share_state->sched_shared_vm = mem; + dev_dbg(share_state->dev, "%s: sched_shared_vm=%p size=%d\n", + __func__, share_state->sched_shared_vm, share_state->buf_size); + + sg_init_table(share_state->sg, share_state->num_pages); + for_each_sg(share_state->sg, sg, share_state->num_pages, i) { + struct page *pg = vmalloc_to_page(mem + (i * PAGE_SIZE)); + + if (!pg) { + result = -ENOMEM; + goto err_rsrc_sg_lookup; + } + sg_set_page(sg, pg, PAGE_SIZE, 0); + } + + result = trusty_share_memory(share_state->dev, &mem_id, share_state->sg, + share_state->num_pages, PAGE_KERNEL); + if (result != 0) { + dev_err(share_state->dev, "trusty_share_memory failed: %d\n", + result); + goto err_rsrc_share_mem; + } + dev_dbg(share_state->dev, "%s: sched_shared_mem_id=0x%llx", __func__, + mem_id); + share_state->sched_shared_mem_id = mem_id; + + shared = (struct trusty_sched_shared *)share_state->sched_shared_vm; + shared->hdr_size = sizeof(struct trusty_sched_shared); + shared->percpu_data_size = sizeof(struct trusty_percpu_data); + + return result; + +err_rsrc_share_mem: +err_rsrc_sg_lookup: + vfree(share_state->sched_shared_vm); +err_rsrc_alloc_mem: + kfree(share_state->sg); +err_rsrc_alloc_sg: + return result; +} + +struct trusty_sched_share_state *trusty_register_sched_share(struct device *device) +{ + int result = 0; + struct trusty_sched_share_state *sched_share_state = NULL; + struct trusty_sched_shared *shared; + uint sched_share_state_size; + + sched_share_state_size = sizeof(*sched_share_state); + + sched_share_state = kzalloc(sched_share_state_size, GFP_KERNEL); + if (!sched_share_state) + goto err_sched_state_alloc; + sched_share_state->dev = device; + + result = trusty_sched_share_resources_allocate(sched_share_state); + if (result) + goto err_resources_alloc; + + shared = (struct trusty_sched_shared *)sched_share_state->sched_shared_vm; + shared->cpu_count = nr_cpu_ids; + + dev_dbg(device, "%s: calling api SMC_SC_SCHED_SHARE_REGISTER...\n", + __func__); + + result = trusty_std_call32( + sched_share_state->dev, SMC_SC_SCHED_SHARE_REGISTER, + (u32)sched_share_state->sched_shared_mem_id, + (u32)(sched_share_state->sched_shared_mem_id >> 32), + sched_share_state->buf_size); + if (result == SM_ERR_UNDEFINED_SMC) { + dev_warn( + sched_share_state->dev, + "trusty-share not supported on secure side, error=%d\n", + result); + goto err_smc_std_call32; + } else if (result < 0) { + dev_err(device, + "trusty std call32 (SMC_SC_SCHED_SHARE_REGISTER) failed: %d\n", + result); + goto err_smc_std_call32; + } + dev_dbg(device, "%s: sched_share_state=%llx\n", __func__, + (u64)sched_share_state); + + return sched_share_state; + +err_smc_std_call32: + result = trusty_reclaim_memory(sched_share_state->dev, + sched_share_state->sched_shared_mem_id, + sched_share_state->sg, + sched_share_state->num_pages); + if (result != 0) { + dev_err(sched_share_state->dev, + "trusty_reclaim_memory() failed: ret=%d mem_id=0x%llx\n", + result, sched_share_state->sched_shared_mem_id); + /* + * It is not safe to free this memory if trusty_reclaim_memory() + * failed. Leak it in that case. + */ + dev_err(sched_share_state->dev, + "WARNING: leaking some allocated resources!!\n"); + } else { + vfree(sched_share_state->sched_shared_vm); + } + kfree(sched_share_state->sg); +err_resources_alloc: + kfree(sched_share_state); + dev_warn(sched_share_state->dev, + "Trusty-Sched_Share API not available.\n"); +err_sched_state_alloc: + return NULL; +} + +void trusty_unregister_sched_share(struct trusty_sched_share_state *sched_share_state) +{ + int result; + + if (!sched_share_state) + return; + + /* ask Trusty to release the Trusty-side resources */ + result = trusty_std_call32( + sched_share_state->dev, SMC_SC_SCHED_SHARE_UNREGISTER, + (u32)sched_share_state->sched_shared_mem_id, + (u32)(sched_share_state->sched_shared_mem_id >> 32), 0); + if (result) { + dev_err(sched_share_state->dev, + "call SMC_SC_SCHED_SHARE_UNREGISTER failed, error=%d\n", + result); + } + result = trusty_reclaim_memory(sched_share_state->dev, + sched_share_state->sched_shared_mem_id, + sched_share_state->sg, + sched_share_state->num_pages); + if (result) { + dev_err(sched_share_state->dev, + "trusty_reclaim_memory() failed: ret=%d mem_id=0x%llx\n", + result, sched_share_state->sched_shared_mem_id); + /* + * It is not safe to free this memory if trusty_reclaim_memory() + * failed. Leak it in that case. + */ + dev_err(sched_share_state->dev, + "WARNING: leaking some allocated resources!!\n"); + } else { + vfree(sched_share_state->sched_shared_vm); + } + + kfree(sched_share_state->sg); + kfree(sched_share_state); +} diff --git a/drivers/trusty/trusty-sched-share.h b/drivers/trusty/trusty-sched-share.h new file mode 100644 index 0000000..7e59eec --- /dev/null +++ b/drivers/trusty/trusty-sched-share.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright (c) 2022 Google, Inc. + * + * This header file defines the SMC API and the shared data info between + * Linux and Trusty. + * + * Important: Copy of this header file is used in Trusty. + * Trusty header file: + * trusty/trusty/kernel/lib/trusty/include/lib/trusty/trusty_share.h + * Please keep the copies in sync. + */ +#ifndef _TRUSTY_SCHED_SHARE_H_ +#define _TRUSTY_SCHED_SHARE_H_ + +#include <linux/trusty/smcall.h> + +/* + * trusty-shadow-priority valid values + */ +#define TRUSTY_SHADOW_PRIORITY_LOW 1 +#define TRUSTY_SHADOW_PRIORITY_NORMAL 2 +#define TRUSTY_SHADOW_PRIORITY_HIGH 3 + +/** + * struct trusty_percpu_data - per-cpu trusty shared data + * @cur_shadow_priority: set by Trusty-Driver/Linux + * @ask_shadow_priority: set by Trusty Kernel + */ +struct trusty_percpu_data { + u32 cur_shadow_priority; + u32 ask_shadow_priority; +}; + +/** + * struct trusty_sched_shared - information in the shared memory. + * @hdr_size: size of the trusty_shared data-structure. + * An instance of this data-structure is embedded at + * the very beginning of the shared-memory block. + * @cpu_count: max number of available CPUs in the system. + * @percpu_data_size: size of the per-cpu data structure. + * The shared-memory block contains an array + * of per-cpu instances of a data-structure that + * can be indexed by cpu_id. + * + * NOTE: At the end of this data-structure, additional space is + * allocated to accommodate a variable length array as follows: + * 'struct trusty_percpu_data percpu_data_table[]', + * with 'cpu_count' as its number of elements. + */ +struct trusty_sched_shared { + u32 hdr_size; + u32 cpu_count; + u32 percpu_data_size; + /* Additional space is allocated here as noted above */ +}; + +#endif /* _TRUSTY_SCHED_SHARE_H_ */ diff --git a/drivers/trusty/trusty.c b/drivers/trusty/trusty.c index ac08d51..fadead8 100644 --- a/drivers/trusty/trusty.c +++ b/drivers/trusty/trusty.c @@ -21,6 +21,7 @@ #include "trusty-smc.h" #include "trusty-trace.h" +#include "trusty-sched-share-api.h" struct trusty_state; static struct platform_driver trusty_driver; @@ -46,6 +47,7 @@ struct trusty_state { struct list_head nop_queue; spinlock_t nop_lock; /* protects nop_queue */ struct device_dma_parameters dma_parms; + struct trusty_sched_share_state *trusty_sched_share_state; void *ffa_tx; void *ffa_rx; u16 ffa_local_id; @@ -935,6 +937,8 @@ static int trusty_probe(struct platform_device *pdev) INIT_WORK(&tw->work, work_func); } + s->trusty_sched_share_state = trusty_register_sched_share(&pdev->dev); + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "Failed to add children: %d\n", ret); @@ -971,6 +975,8 @@ static int trusty_remove(struct platform_device *pdev) unsigned int cpu; struct trusty_state *s = platform_get_drvdata(pdev); + trusty_unregister_sched_share(s->trusty_sched_share_state); + device_for_each_child(&pdev->dev, NULL, trusty_remove_child); for_each_possible_cpu(cpu) { diff --git a/include/linux/trusty/smcall.h b/include/linux/trusty/smcall.h index aea3f60..9ce498d 100644 --- a/include/linux/trusty/smcall.h +++ b/include/linux/trusty/smcall.h @@ -68,6 +68,36 @@ */ #define SMC_SC_NOP SMC_STDCALL_NR(SMC_ENTITY_SECURE_MONITOR, 3) +/** + * SMC API for supporting shared-memory based trusty-linux info exchange + * + * SMC_SC_SCHED_SHARE_REGISTER - enter trusty to establish a shared-memory region + * Arguments: + * param[0]: shared-memory client-id + * param[1]: shared-memory buffer-id + * param[2]: shared-memory block size + * + * returns: + * SM_ERR_INTERNAL_FAILURE on failure. + * 0 on success. + */ +#define SMC_SC_SCHED_SHARE_REGISTER SMC_STDCALL_NR(SMC_ENTITY_SECURE_MONITOR, 4) + +/** + * SMC API for supporting shared-memory based trusty-linux info exchange + * + * SMC_SC_SCHED_SHARE_UNREGISTER - enter trusty to release the shared-memory region + * Arguments: + * param[0]: shared-memory client-id + * param[1]: shared-memory buffer-id + * + * returns: + * SM_ERR_INTERNAL_FAILURE on failure. + * 0 on success. + */ +#define SMC_SC_SCHED_SHARE_UNREGISTER \ + SMC_STDCALL_NR(SMC_ENTITY_SECURE_MONITOR, 5) + /* * Return from secure os to non-secure os with return value in r1 */ |