summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSudhin Mishra <sudhin@google.com>2022-10-18 17:11:43 +0000
committerJi Soo Shin <jisshin@google.com>2023-03-15 22:10:37 +0000
commitb097452f77a3b3da65e9d0277fce2b6bcb226356 (patch)
tree5dfe36e42c434ee4c8209f99126f0b5068039d51
parent5a3911b600dc5de99f19e56ebedb9b8a4efb3c3e (diff)
downloadtrusty-b097452f77a3b3da65e9d0277fce2b6bcb226356.tar.gz
ANDROID: trusty: Create API for sharing trusty info
Android Trusty-Driver and Trusty-Kernel need a shared-memory based data-structure for exchanging information in order to influence each other for improved performance. An API is required for the trusty-driver to register the presence of the shared-memory block with the trusty-kernel, after the trusty-driver has established it during probe(). Likewise, an API is also required to unregister the shared-memory and release resources during trusty-driver remove(). Bug: 251903627 Test: shpriotest Change-Id: I7670dcfd711f5cbeed32650dc13eac2cedc8e5db Signed-off-by: Sudhin Mishra <sudhin@google.com>
-rw-r--r--drivers/trusty/Kbuild2
-rw-r--r--drivers/trusty/trusty-sched-share-api.h19
-rw-r--r--drivers/trusty/trusty-sched-share.c220
-rw-r--r--drivers/trusty/trusty-sched-share.h58
-rw-r--r--drivers/trusty/trusty.c6
-rw-r--r--include/linux/trusty/smcall.h30
6 files changed, 334 insertions, 1 deletions
diff --git a/drivers/trusty/Kbuild b/drivers/trusty/Kbuild
index 76f6932..6fb075d 100644
--- a/drivers/trusty/Kbuild
+++ b/drivers/trusty/Kbuild
@@ -9,7 +9,7 @@ CFLAGS_trusty-irq.o = -I$(srctree)/$(src)
CFLAGS_trusty-ipc.o = -I$(srctree)/$(src)
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
*/