1757cc3e9SRijo Thomas // SPDX-License-Identifier: MIT
2757cc3e9SRijo Thomas /*
3757cc3e9SRijo Thomas * Copyright 2019 Advanced Micro Devices, Inc.
4757cc3e9SRijo Thomas */
5757cc3e9SRijo Thomas
67b032366SMario Limonciello #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
77b032366SMario Limonciello
8757cc3e9SRijo Thomas #include <linux/errno.h>
9*136deca5SMario Limonciello #include <linux/device.h>
10*136deca5SMario Limonciello #include <linux/firmware.h>
11757cc3e9SRijo Thomas #include <linux/io.h>
12*136deca5SMario Limonciello #include <linux/mm.h>
13757cc3e9SRijo Thomas #include <linux/module.h>
14*136deca5SMario Limonciello #include <linux/psp-tee.h>
15757cc3e9SRijo Thomas #include <linux/slab.h>
16757cc3e9SRijo Thomas #include <linux/string.h>
170439fcffSSumit Garg #include <linux/tee_core.h>
18757cc3e9SRijo Thomas #include <linux/types.h>
19757cc3e9SRijo Thomas #include <linux/uaccess.h>
20*136deca5SMario Limonciello
21757cc3e9SRijo Thomas #include "amdtee_private.h"
22757cc3e9SRijo Thomas
23757cc3e9SRijo Thomas static struct amdtee_driver_data *drv_data;
24757cc3e9SRijo Thomas static DEFINE_MUTEX(session_list_mutex);
25757cc3e9SRijo Thomas
amdtee_get_version(struct tee_device * teedev,struct tee_ioctl_version_data * vers)26757cc3e9SRijo Thomas static void amdtee_get_version(struct tee_device *teedev,
27757cc3e9SRijo Thomas struct tee_ioctl_version_data *vers)
28757cc3e9SRijo Thomas {
29757cc3e9SRijo Thomas struct tee_ioctl_version_data v = {
30757cc3e9SRijo Thomas .impl_id = TEE_IMPL_ID_AMDTEE,
31757cc3e9SRijo Thomas .impl_caps = 0,
32757cc3e9SRijo Thomas .gen_caps = TEE_GEN_CAP_GP,
33757cc3e9SRijo Thomas };
34757cc3e9SRijo Thomas *vers = v;
35757cc3e9SRijo Thomas }
36757cc3e9SRijo Thomas
amdtee_open(struct tee_context * ctx)37757cc3e9SRijo Thomas static int amdtee_open(struct tee_context *ctx)
38757cc3e9SRijo Thomas {
39757cc3e9SRijo Thomas struct amdtee_context_data *ctxdata;
40757cc3e9SRijo Thomas
41757cc3e9SRijo Thomas ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
42757cc3e9SRijo Thomas if (!ctxdata)
43757cc3e9SRijo Thomas return -ENOMEM;
44757cc3e9SRijo Thomas
45757cc3e9SRijo Thomas INIT_LIST_HEAD(&ctxdata->sess_list);
46ff1f8558SRijo Thomas INIT_LIST_HEAD(&ctxdata->shm_list);
47be353be2SRijo Thomas mutex_init(&ctxdata->shm_mutex);
48757cc3e9SRijo Thomas
49757cc3e9SRijo Thomas ctx->data = ctxdata;
50757cc3e9SRijo Thomas return 0;
51757cc3e9SRijo Thomas }
52757cc3e9SRijo Thomas
release_session(struct amdtee_session * sess)53757cc3e9SRijo Thomas static void release_session(struct amdtee_session *sess)
54757cc3e9SRijo Thomas {
555ae63958SRijo Thomas int i;
56757cc3e9SRijo Thomas
57757cc3e9SRijo Thomas /* Close any open session */
58757cc3e9SRijo Thomas for (i = 0; i < TEE_NUM_SESSIONS; ++i) {
59757cc3e9SRijo Thomas /* Check if session entry 'i' is valid */
60757cc3e9SRijo Thomas if (!test_bit(i, sess->sess_mask))
61757cc3e9SRijo Thomas continue;
62757cc3e9SRijo Thomas
63757cc3e9SRijo Thomas handle_close_session(sess->ta_handle, sess->session_info[i]);
649f015b37SRijo Thomas handle_unload_ta(sess->ta_handle);
65757cc3e9SRijo Thomas }
66757cc3e9SRijo Thomas
67757cc3e9SRijo Thomas kfree(sess);
68757cc3e9SRijo Thomas }
69757cc3e9SRijo Thomas
amdtee_release(struct tee_context * ctx)70757cc3e9SRijo Thomas static void amdtee_release(struct tee_context *ctx)
71757cc3e9SRijo Thomas {
72757cc3e9SRijo Thomas struct amdtee_context_data *ctxdata = ctx->data;
73757cc3e9SRijo Thomas
74757cc3e9SRijo Thomas if (!ctxdata)
75757cc3e9SRijo Thomas return;
76757cc3e9SRijo Thomas
77757cc3e9SRijo Thomas while (true) {
78757cc3e9SRijo Thomas struct amdtee_session *sess;
79757cc3e9SRijo Thomas
80757cc3e9SRijo Thomas sess = list_first_entry_or_null(&ctxdata->sess_list,
81757cc3e9SRijo Thomas struct amdtee_session,
82757cc3e9SRijo Thomas list_node);
83757cc3e9SRijo Thomas
84757cc3e9SRijo Thomas if (!sess)
85757cc3e9SRijo Thomas break;
86757cc3e9SRijo Thomas
87757cc3e9SRijo Thomas list_del(&sess->list_node);
88757cc3e9SRijo Thomas release_session(sess);
89757cc3e9SRijo Thomas }
90be353be2SRijo Thomas mutex_destroy(&ctxdata->shm_mutex);
91757cc3e9SRijo Thomas kfree(ctxdata);
92757cc3e9SRijo Thomas
93757cc3e9SRijo Thomas ctx->data = NULL;
94757cc3e9SRijo Thomas }
95757cc3e9SRijo Thomas
96757cc3e9SRijo Thomas /**
97757cc3e9SRijo Thomas * alloc_session() - Allocate a session structure
98757cc3e9SRijo Thomas * @ctxdata: TEE Context data structure
99757cc3e9SRijo Thomas * @session: Session ID for which 'struct amdtee_session' structure is to be
100757cc3e9SRijo Thomas * allocated.
101757cc3e9SRijo Thomas *
102757cc3e9SRijo Thomas * Scans the TEE context's session list to check if TA is already loaded in to
103757cc3e9SRijo Thomas * TEE. If yes, returns the 'session' structure for that TA. Else allocates,
104757cc3e9SRijo Thomas * initializes a new 'session' structure and adds it to context's session list.
105757cc3e9SRijo Thomas *
106757cc3e9SRijo Thomas * The caller must hold a mutex.
107757cc3e9SRijo Thomas *
108757cc3e9SRijo Thomas * Returns:
109757cc3e9SRijo Thomas * 'struct amdtee_session *' on success and NULL on failure.
110757cc3e9SRijo Thomas */
alloc_session(struct amdtee_context_data * ctxdata,u32 session)111757cc3e9SRijo Thomas static struct amdtee_session *alloc_session(struct amdtee_context_data *ctxdata,
112757cc3e9SRijo Thomas u32 session)
113757cc3e9SRijo Thomas {
114757cc3e9SRijo Thomas struct amdtee_session *sess;
115757cc3e9SRijo Thomas u32 ta_handle = get_ta_handle(session);
116757cc3e9SRijo Thomas
117757cc3e9SRijo Thomas /* Scan session list to check if TA is already loaded in to TEE */
118757cc3e9SRijo Thomas list_for_each_entry(sess, &ctxdata->sess_list, list_node)
119757cc3e9SRijo Thomas if (sess->ta_handle == ta_handle) {
120757cc3e9SRijo Thomas kref_get(&sess->refcount);
121757cc3e9SRijo Thomas return sess;
122757cc3e9SRijo Thomas }
123757cc3e9SRijo Thomas
124757cc3e9SRijo Thomas /* Allocate a new session and add to list */
125757cc3e9SRijo Thomas sess = kzalloc(sizeof(*sess), GFP_KERNEL);
126757cc3e9SRijo Thomas if (sess) {
127757cc3e9SRijo Thomas sess->ta_handle = ta_handle;
128757cc3e9SRijo Thomas kref_init(&sess->refcount);
129757cc3e9SRijo Thomas spin_lock_init(&sess->lock);
130757cc3e9SRijo Thomas list_add(&sess->list_node, &ctxdata->sess_list);
131757cc3e9SRijo Thomas }
132757cc3e9SRijo Thomas
133757cc3e9SRijo Thomas return sess;
134757cc3e9SRijo Thomas }
135757cc3e9SRijo Thomas
136757cc3e9SRijo Thomas /* Requires mutex to be held */
find_session(struct amdtee_context_data * ctxdata,u32 session)137757cc3e9SRijo Thomas static struct amdtee_session *find_session(struct amdtee_context_data *ctxdata,
138757cc3e9SRijo Thomas u32 session)
139757cc3e9SRijo Thomas {
140757cc3e9SRijo Thomas u32 ta_handle = get_ta_handle(session);
141757cc3e9SRijo Thomas u32 index = get_session_index(session);
142757cc3e9SRijo Thomas struct amdtee_session *sess;
143757cc3e9SRijo Thomas
14436fa3e50SDan Carpenter if (index >= TEE_NUM_SESSIONS)
14536fa3e50SDan Carpenter return NULL;
14636fa3e50SDan Carpenter
147757cc3e9SRijo Thomas list_for_each_entry(sess, &ctxdata->sess_list, list_node)
148757cc3e9SRijo Thomas if (ta_handle == sess->ta_handle &&
149757cc3e9SRijo Thomas test_bit(index, sess->sess_mask))
150757cc3e9SRijo Thomas return sess;
151757cc3e9SRijo Thomas
152757cc3e9SRijo Thomas return NULL;
153757cc3e9SRijo Thomas }
154757cc3e9SRijo Thomas
get_buffer_id(struct tee_shm * shm)155757cc3e9SRijo Thomas u32 get_buffer_id(struct tee_shm *shm)
156757cc3e9SRijo Thomas {
157ff1f8558SRijo Thomas struct amdtee_context_data *ctxdata = shm->ctx->data;
158757cc3e9SRijo Thomas struct amdtee_shm_data *shmdata;
159ff1f8558SRijo Thomas u32 buf_id = 0;
160757cc3e9SRijo Thomas
161be353be2SRijo Thomas mutex_lock(&ctxdata->shm_mutex);
162ff1f8558SRijo Thomas list_for_each_entry(shmdata, &ctxdata->shm_list, shm_node)
163757cc3e9SRijo Thomas if (shmdata->kaddr == shm->kaddr) {
164757cc3e9SRijo Thomas buf_id = shmdata->buf_id;
165757cc3e9SRijo Thomas break;
166757cc3e9SRijo Thomas }
167be353be2SRijo Thomas mutex_unlock(&ctxdata->shm_mutex);
168757cc3e9SRijo Thomas
169757cc3e9SRijo Thomas return buf_id;
170757cc3e9SRijo Thomas }
171757cc3e9SRijo Thomas
172757cc3e9SRijo Thomas static DEFINE_MUTEX(drv_mutex);
copy_ta_binary(struct tee_context * ctx,void * ptr,void ** ta,size_t * ta_size)173757cc3e9SRijo Thomas static int copy_ta_binary(struct tee_context *ctx, void *ptr, void **ta,
174757cc3e9SRijo Thomas size_t *ta_size)
175757cc3e9SRijo Thomas {
176757cc3e9SRijo Thomas const struct firmware *fw;
177757cc3e9SRijo Thomas char fw_name[TA_PATH_MAX];
178757cc3e9SRijo Thomas struct {
179757cc3e9SRijo Thomas u32 lo;
180757cc3e9SRijo Thomas u16 mid;
181757cc3e9SRijo Thomas u16 hi_ver;
182757cc3e9SRijo Thomas u8 seq_n[8];
183757cc3e9SRijo Thomas } *uuid = ptr;
1845ae63958SRijo Thomas int n, rc = 0;
185757cc3e9SRijo Thomas
186757cc3e9SRijo Thomas n = snprintf(fw_name, TA_PATH_MAX,
187757cc3e9SRijo Thomas "%s/%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x.bin",
188757cc3e9SRijo Thomas TA_LOAD_PATH, uuid->lo, uuid->mid, uuid->hi_ver,
189757cc3e9SRijo Thomas uuid->seq_n[0], uuid->seq_n[1],
190757cc3e9SRijo Thomas uuid->seq_n[2], uuid->seq_n[3],
191757cc3e9SRijo Thomas uuid->seq_n[4], uuid->seq_n[5],
192757cc3e9SRijo Thomas uuid->seq_n[6], uuid->seq_n[7]);
193757cc3e9SRijo Thomas if (n < 0 || n >= TA_PATH_MAX) {
194757cc3e9SRijo Thomas pr_err("failed to get firmware name\n");
195757cc3e9SRijo Thomas return -EINVAL;
196757cc3e9SRijo Thomas }
197757cc3e9SRijo Thomas
198757cc3e9SRijo Thomas mutex_lock(&drv_mutex);
199757cc3e9SRijo Thomas n = request_firmware(&fw, fw_name, &ctx->teedev->dev);
200757cc3e9SRijo Thomas if (n) {
201757cc3e9SRijo Thomas pr_err("failed to load firmware %s\n", fw_name);
202757cc3e9SRijo Thomas rc = -ENOMEM;
203757cc3e9SRijo Thomas goto unlock;
204757cc3e9SRijo Thomas }
205757cc3e9SRijo Thomas
206757cc3e9SRijo Thomas *ta_size = roundup(fw->size, PAGE_SIZE);
207757cc3e9SRijo Thomas *ta = (void *)__get_free_pages(GFP_KERNEL, get_order(*ta_size));
2089d748277SDan Carpenter if (!*ta) {
2099d748277SDan Carpenter pr_err("%s: get_free_pages failed\n", __func__);
210757cc3e9SRijo Thomas rc = -ENOMEM;
211757cc3e9SRijo Thomas goto rel_fw;
212757cc3e9SRijo Thomas }
213757cc3e9SRijo Thomas
214757cc3e9SRijo Thomas memcpy(*ta, fw->data, fw->size);
215757cc3e9SRijo Thomas rel_fw:
216757cc3e9SRijo Thomas release_firmware(fw);
217757cc3e9SRijo Thomas unlock:
218757cc3e9SRijo Thomas mutex_unlock(&drv_mutex);
219757cc3e9SRijo Thomas return rc;
220757cc3e9SRijo Thomas }
221757cc3e9SRijo Thomas
222f4384b3eSRijo Thomas /* mutex must be held by caller */
destroy_session(struct kref * ref)223b83685bcSDan Carpenter static void destroy_session(struct kref *ref)
224b83685bcSDan Carpenter {
225b83685bcSDan Carpenter struct amdtee_session *sess = container_of(ref, struct amdtee_session,
226b83685bcSDan Carpenter refcount);
227b83685bcSDan Carpenter
228b83685bcSDan Carpenter list_del(&sess->list_node);
229b83685bcSDan Carpenter mutex_unlock(&session_list_mutex);
230b83685bcSDan Carpenter kfree(sess);
231b83685bcSDan Carpenter }
232b83685bcSDan Carpenter
amdtee_open_session(struct tee_context * ctx,struct tee_ioctl_open_session_arg * arg,struct tee_param * param)233757cc3e9SRijo Thomas int amdtee_open_session(struct tee_context *ctx,
234757cc3e9SRijo Thomas struct tee_ioctl_open_session_arg *arg,
235757cc3e9SRijo Thomas struct tee_param *param)
236757cc3e9SRijo Thomas {
237757cc3e9SRijo Thomas struct amdtee_context_data *ctxdata = ctx->data;
238757cc3e9SRijo Thomas struct amdtee_session *sess = NULL;
2399f015b37SRijo Thomas u32 session_info, ta_handle;
240757cc3e9SRijo Thomas size_t ta_size;
2415ae63958SRijo Thomas int rc, i;
2425ae63958SRijo Thomas void *ta;
243757cc3e9SRijo Thomas
244757cc3e9SRijo Thomas if (arg->clnt_login != TEE_IOCTL_LOGIN_PUBLIC) {
245757cc3e9SRijo Thomas pr_err("unsupported client login method\n");
246757cc3e9SRijo Thomas return -EINVAL;
247757cc3e9SRijo Thomas }
248757cc3e9SRijo Thomas
249757cc3e9SRijo Thomas rc = copy_ta_binary(ctx, &arg->uuid[0], &ta, &ta_size);
250757cc3e9SRijo Thomas if (rc) {
251757cc3e9SRijo Thomas pr_err("failed to copy TA binary\n");
252757cc3e9SRijo Thomas return rc;
253757cc3e9SRijo Thomas }
254757cc3e9SRijo Thomas
255757cc3e9SRijo Thomas /* Load the TA binary into TEE environment */
256757cc3e9SRijo Thomas handle_load_ta(ta, ta_size, arg);
257b83685bcSDan Carpenter if (arg->ret != TEEC_SUCCESS)
258b83685bcSDan Carpenter goto out;
259b83685bcSDan Carpenter
2609f015b37SRijo Thomas ta_handle = get_ta_handle(arg->session);
2619f015b37SRijo Thomas
262757cc3e9SRijo Thomas mutex_lock(&session_list_mutex);
263757cc3e9SRijo Thomas sess = alloc_session(ctxdata, arg->session);
264757cc3e9SRijo Thomas mutex_unlock(&session_list_mutex);
265757cc3e9SRijo Thomas
266757cc3e9SRijo Thomas if (!sess) {
2679f015b37SRijo Thomas handle_unload_ta(ta_handle);
268757cc3e9SRijo Thomas rc = -ENOMEM;
269757cc3e9SRijo Thomas goto out;
270757cc3e9SRijo Thomas }
271757cc3e9SRijo Thomas
272f8502fbaSRijo Thomas /* Open session with loaded TA */
273f8502fbaSRijo Thomas handle_open_session(arg, &session_info, param);
274f8502fbaSRijo Thomas if (arg->ret != TEEC_SUCCESS) {
275f8502fbaSRijo Thomas pr_err("open_session failed %d\n", arg->ret);
276f8502fbaSRijo Thomas handle_unload_ta(ta_handle);
277f4384b3eSRijo Thomas kref_put_mutex(&sess->refcount, destroy_session,
278f4384b3eSRijo Thomas &session_list_mutex);
279f8502fbaSRijo Thomas goto out;
280f8502fbaSRijo Thomas }
281f8502fbaSRijo Thomas
282757cc3e9SRijo Thomas /* Find an empty session index for the given TA */
283757cc3e9SRijo Thomas spin_lock(&sess->lock);
284757cc3e9SRijo Thomas i = find_first_zero_bit(sess->sess_mask, TEE_NUM_SESSIONS);
285f8502fbaSRijo Thomas if (i < TEE_NUM_SESSIONS) {
286f8502fbaSRijo Thomas sess->session_info[i] = session_info;
287f8502fbaSRijo Thomas set_session_id(ta_handle, i, &arg->session);
288757cc3e9SRijo Thomas set_bit(i, sess->sess_mask);
289f8502fbaSRijo Thomas }
290757cc3e9SRijo Thomas spin_unlock(&sess->lock);
291757cc3e9SRijo Thomas
292757cc3e9SRijo Thomas if (i >= TEE_NUM_SESSIONS) {
293757cc3e9SRijo Thomas pr_err("reached maximum session count %d\n", TEE_NUM_SESSIONS);
294f8502fbaSRijo Thomas handle_close_session(ta_handle, session_info);
2959f015b37SRijo Thomas handle_unload_ta(ta_handle);
296f4384b3eSRijo Thomas kref_put_mutex(&sess->refcount, destroy_session,
297f4384b3eSRijo Thomas &session_list_mutex);
298757cc3e9SRijo Thomas rc = -ENOMEM;
299757cc3e9SRijo Thomas goto out;
300757cc3e9SRijo Thomas }
301757cc3e9SRijo Thomas
302757cc3e9SRijo Thomas out:
303757cc3e9SRijo Thomas free_pages((u64)ta, get_order(ta_size));
304757cc3e9SRijo Thomas return rc;
305757cc3e9SRijo Thomas }
306757cc3e9SRijo Thomas
amdtee_close_session(struct tee_context * ctx,u32 session)307757cc3e9SRijo Thomas int amdtee_close_session(struct tee_context *ctx, u32 session)
308757cc3e9SRijo Thomas {
309757cc3e9SRijo Thomas struct amdtee_context_data *ctxdata = ctx->data;
310757cc3e9SRijo Thomas u32 i, ta_handle, session_info;
311757cc3e9SRijo Thomas struct amdtee_session *sess;
312757cc3e9SRijo Thomas
313757cc3e9SRijo Thomas pr_debug("%s: sid = 0x%x\n", __func__, session);
314757cc3e9SRijo Thomas
315757cc3e9SRijo Thomas /*
316757cc3e9SRijo Thomas * Check that the session is valid and clear the session
317757cc3e9SRijo Thomas * usage bit
318757cc3e9SRijo Thomas */
319757cc3e9SRijo Thomas mutex_lock(&session_list_mutex);
320757cc3e9SRijo Thomas sess = find_session(ctxdata, session);
321757cc3e9SRijo Thomas if (sess) {
322757cc3e9SRijo Thomas ta_handle = get_ta_handle(session);
323757cc3e9SRijo Thomas i = get_session_index(session);
324757cc3e9SRijo Thomas session_info = sess->session_info[i];
325757cc3e9SRijo Thomas spin_lock(&sess->lock);
326757cc3e9SRijo Thomas clear_bit(i, sess->sess_mask);
327757cc3e9SRijo Thomas spin_unlock(&sess->lock);
328757cc3e9SRijo Thomas }
329757cc3e9SRijo Thomas mutex_unlock(&session_list_mutex);
330757cc3e9SRijo Thomas
331757cc3e9SRijo Thomas if (!sess)
332757cc3e9SRijo Thomas return -EINVAL;
333757cc3e9SRijo Thomas
334757cc3e9SRijo Thomas /* Close the session */
335757cc3e9SRijo Thomas handle_close_session(ta_handle, session_info);
3369f015b37SRijo Thomas handle_unload_ta(ta_handle);
337757cc3e9SRijo Thomas
338f4384b3eSRijo Thomas kref_put_mutex(&sess->refcount, destroy_session, &session_list_mutex);
339757cc3e9SRijo Thomas
340757cc3e9SRijo Thomas return 0;
341757cc3e9SRijo Thomas }
342757cc3e9SRijo Thomas
amdtee_map_shmem(struct tee_shm * shm)343757cc3e9SRijo Thomas int amdtee_map_shmem(struct tee_shm *shm)
344757cc3e9SRijo Thomas {
345ff1f8558SRijo Thomas struct amdtee_context_data *ctxdata;
346757cc3e9SRijo Thomas struct amdtee_shm_data *shmnode;
347ff1f8558SRijo Thomas struct shmem_desc shmem;
348757cc3e9SRijo Thomas int rc, count;
349757cc3e9SRijo Thomas u32 buf_id;
350757cc3e9SRijo Thomas
351757cc3e9SRijo Thomas if (!shm)
352757cc3e9SRijo Thomas return -EINVAL;
353757cc3e9SRijo Thomas
354757cc3e9SRijo Thomas shmnode = kmalloc(sizeof(*shmnode), GFP_KERNEL);
355757cc3e9SRijo Thomas if (!shmnode)
356757cc3e9SRijo Thomas return -ENOMEM;
357757cc3e9SRijo Thomas
358757cc3e9SRijo Thomas count = 1;
359757cc3e9SRijo Thomas shmem.kaddr = shm->kaddr;
360757cc3e9SRijo Thomas shmem.size = shm->size;
361757cc3e9SRijo Thomas
362757cc3e9SRijo Thomas /*
363757cc3e9SRijo Thomas * Send a MAP command to TEE and get the corresponding
364757cc3e9SRijo Thomas * buffer Id
365757cc3e9SRijo Thomas */
366757cc3e9SRijo Thomas rc = handle_map_shmem(count, &shmem, &buf_id);
367757cc3e9SRijo Thomas if (rc) {
368757cc3e9SRijo Thomas pr_err("map_shmem failed: ret = %d\n", rc);
369757cc3e9SRijo Thomas kfree(shmnode);
370757cc3e9SRijo Thomas return rc;
371757cc3e9SRijo Thomas }
372757cc3e9SRijo Thomas
373757cc3e9SRijo Thomas shmnode->kaddr = shm->kaddr;
374757cc3e9SRijo Thomas shmnode->buf_id = buf_id;
375ff1f8558SRijo Thomas ctxdata = shm->ctx->data;
376be353be2SRijo Thomas mutex_lock(&ctxdata->shm_mutex);
377ff1f8558SRijo Thomas list_add(&shmnode->shm_node, &ctxdata->shm_list);
378be353be2SRijo Thomas mutex_unlock(&ctxdata->shm_mutex);
379757cc3e9SRijo Thomas
380757cc3e9SRijo Thomas pr_debug("buf_id :[%x] kaddr[%p]\n", shmnode->buf_id, shmnode->kaddr);
381757cc3e9SRijo Thomas
382757cc3e9SRijo Thomas return 0;
383757cc3e9SRijo Thomas }
384757cc3e9SRijo Thomas
amdtee_unmap_shmem(struct tee_shm * shm)385757cc3e9SRijo Thomas void amdtee_unmap_shmem(struct tee_shm *shm)
386757cc3e9SRijo Thomas {
387ff1f8558SRijo Thomas struct amdtee_context_data *ctxdata;
3885ae63958SRijo Thomas struct amdtee_shm_data *shmnode;
389757cc3e9SRijo Thomas u32 buf_id;
390757cc3e9SRijo Thomas
391757cc3e9SRijo Thomas if (!shm)
392757cc3e9SRijo Thomas return;
393757cc3e9SRijo Thomas
394757cc3e9SRijo Thomas buf_id = get_buffer_id(shm);
395757cc3e9SRijo Thomas /* Unmap the shared memory from TEE */
396757cc3e9SRijo Thomas handle_unmap_shmem(buf_id);
397757cc3e9SRijo Thomas
398ff1f8558SRijo Thomas ctxdata = shm->ctx->data;
399be353be2SRijo Thomas mutex_lock(&ctxdata->shm_mutex);
400ff1f8558SRijo Thomas list_for_each_entry(shmnode, &ctxdata->shm_list, shm_node)
401757cc3e9SRijo Thomas if (buf_id == shmnode->buf_id) {
402757cc3e9SRijo Thomas list_del(&shmnode->shm_node);
403757cc3e9SRijo Thomas kfree(shmnode);
404757cc3e9SRijo Thomas break;
405757cc3e9SRijo Thomas }
406be353be2SRijo Thomas mutex_unlock(&ctxdata->shm_mutex);
407757cc3e9SRijo Thomas }
408757cc3e9SRijo Thomas
amdtee_invoke_func(struct tee_context * ctx,struct tee_ioctl_invoke_arg * arg,struct tee_param * param)409757cc3e9SRijo Thomas int amdtee_invoke_func(struct tee_context *ctx,
410757cc3e9SRijo Thomas struct tee_ioctl_invoke_arg *arg,
411757cc3e9SRijo Thomas struct tee_param *param)
412757cc3e9SRijo Thomas {
413757cc3e9SRijo Thomas struct amdtee_context_data *ctxdata = ctx->data;
414757cc3e9SRijo Thomas struct amdtee_session *sess;
415757cc3e9SRijo Thomas u32 i, session_info;
416757cc3e9SRijo Thomas
417757cc3e9SRijo Thomas /* Check that the session is valid */
418757cc3e9SRijo Thomas mutex_lock(&session_list_mutex);
419757cc3e9SRijo Thomas sess = find_session(ctxdata, arg->session);
420757cc3e9SRijo Thomas if (sess) {
421757cc3e9SRijo Thomas i = get_session_index(arg->session);
422757cc3e9SRijo Thomas session_info = sess->session_info[i];
423757cc3e9SRijo Thomas }
424757cc3e9SRijo Thomas mutex_unlock(&session_list_mutex);
425757cc3e9SRijo Thomas
426757cc3e9SRijo Thomas if (!sess)
427757cc3e9SRijo Thomas return -EINVAL;
428757cc3e9SRijo Thomas
429757cc3e9SRijo Thomas handle_invoke_cmd(arg, session_info, param);
430757cc3e9SRijo Thomas
431757cc3e9SRijo Thomas return 0;
432757cc3e9SRijo Thomas }
433757cc3e9SRijo Thomas
amdtee_cancel_req(struct tee_context * ctx,u32 cancel_id,u32 session)434757cc3e9SRijo Thomas int amdtee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
435757cc3e9SRijo Thomas {
436757cc3e9SRijo Thomas return -EINVAL;
437757cc3e9SRijo Thomas }
438757cc3e9SRijo Thomas
439757cc3e9SRijo Thomas static const struct tee_driver_ops amdtee_ops = {
440757cc3e9SRijo Thomas .get_version = amdtee_get_version,
441757cc3e9SRijo Thomas .open = amdtee_open,
442757cc3e9SRijo Thomas .release = amdtee_release,
443757cc3e9SRijo Thomas .open_session = amdtee_open_session,
444757cc3e9SRijo Thomas .close_session = amdtee_close_session,
445757cc3e9SRijo Thomas .invoke_func = amdtee_invoke_func,
446757cc3e9SRijo Thomas .cancel_req = amdtee_cancel_req,
447757cc3e9SRijo Thomas };
448757cc3e9SRijo Thomas
449757cc3e9SRijo Thomas static const struct tee_desc amdtee_desc = {
450757cc3e9SRijo Thomas .name = DRIVER_NAME "-clnt",
451757cc3e9SRijo Thomas .ops = &amdtee_ops,
452757cc3e9SRijo Thomas .owner = THIS_MODULE,
453757cc3e9SRijo Thomas };
454757cc3e9SRijo Thomas
amdtee_driver_init(void)455757cc3e9SRijo Thomas static int __init amdtee_driver_init(void)
456757cc3e9SRijo Thomas {
457757cc3e9SRijo Thomas struct tee_device *teedev;
4585ae63958SRijo Thomas struct tee_shm_pool *pool;
4595ae63958SRijo Thomas struct amdtee *amdtee;
460757cc3e9SRijo Thomas int rc;
461757cc3e9SRijo Thomas
462bade7e1fSRijo Thomas rc = psp_check_tee_status();
463f4c58c37SRijo Thomas if (rc) {
4647b032366SMario Limonciello pr_err("tee not present\n");
465f4c58c37SRijo Thomas return rc;
466f4c58c37SRijo Thomas }
467bade7e1fSRijo Thomas
468757cc3e9SRijo Thomas drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
46948d625e4SColin Ian King if (!drv_data)
470757cc3e9SRijo Thomas return -ENOMEM;
471757cc3e9SRijo Thomas
472757cc3e9SRijo Thomas amdtee = kzalloc(sizeof(*amdtee), GFP_KERNEL);
47348d625e4SColin Ian King if (!amdtee) {
474757cc3e9SRijo Thomas rc = -ENOMEM;
475757cc3e9SRijo Thomas goto err_kfree_drv_data;
476757cc3e9SRijo Thomas }
477757cc3e9SRijo Thomas
478757cc3e9SRijo Thomas pool = amdtee_config_shm();
479757cc3e9SRijo Thomas if (IS_ERR(pool)) {
480757cc3e9SRijo Thomas pr_err("shared pool configuration error\n");
481757cc3e9SRijo Thomas rc = PTR_ERR(pool);
482757cc3e9SRijo Thomas goto err_kfree_amdtee;
483757cc3e9SRijo Thomas }
484757cc3e9SRijo Thomas
485757cc3e9SRijo Thomas teedev = tee_device_alloc(&amdtee_desc, NULL, pool, amdtee);
486757cc3e9SRijo Thomas if (IS_ERR(teedev)) {
487757cc3e9SRijo Thomas rc = PTR_ERR(teedev);
48829290155SRijo Thomas goto err_free_pool;
489757cc3e9SRijo Thomas }
490757cc3e9SRijo Thomas amdtee->teedev = teedev;
491757cc3e9SRijo Thomas
492757cc3e9SRijo Thomas rc = tee_device_register(amdtee->teedev);
493757cc3e9SRijo Thomas if (rc)
494f9568eaeSRijo Thomas goto err_device_unregister;
495757cc3e9SRijo Thomas
496757cc3e9SRijo Thomas amdtee->pool = pool;
497757cc3e9SRijo Thomas
498757cc3e9SRijo Thomas drv_data->amdtee = amdtee;
499757cc3e9SRijo Thomas
500757cc3e9SRijo Thomas return 0;
501757cc3e9SRijo Thomas
502f9568eaeSRijo Thomas err_device_unregister:
503757cc3e9SRijo Thomas tee_device_unregister(amdtee->teedev);
50429290155SRijo Thomas
50529290155SRijo Thomas err_free_pool:
506757cc3e9SRijo Thomas tee_shm_pool_free(pool);
507757cc3e9SRijo Thomas
508757cc3e9SRijo Thomas err_kfree_amdtee:
509757cc3e9SRijo Thomas kfree(amdtee);
510757cc3e9SRijo Thomas
511757cc3e9SRijo Thomas err_kfree_drv_data:
512757cc3e9SRijo Thomas kfree(drv_data);
513757cc3e9SRijo Thomas drv_data = NULL;
514757cc3e9SRijo Thomas
5157b032366SMario Limonciello pr_err("initialization failed\n");
516757cc3e9SRijo Thomas return rc;
517757cc3e9SRijo Thomas }
518757cc3e9SRijo Thomas module_init(amdtee_driver_init);
519757cc3e9SRijo Thomas
amdtee_driver_exit(void)520757cc3e9SRijo Thomas static void __exit amdtee_driver_exit(void)
521757cc3e9SRijo Thomas {
522757cc3e9SRijo Thomas struct amdtee *amdtee;
523757cc3e9SRijo Thomas
524757cc3e9SRijo Thomas if (!drv_data || !drv_data->amdtee)
525757cc3e9SRijo Thomas return;
526757cc3e9SRijo Thomas
527757cc3e9SRijo Thomas amdtee = drv_data->amdtee;
528757cc3e9SRijo Thomas
529757cc3e9SRijo Thomas tee_device_unregister(amdtee->teedev);
530757cc3e9SRijo Thomas tee_shm_pool_free(amdtee->pool);
531757cc3e9SRijo Thomas }
532757cc3e9SRijo Thomas module_exit(amdtee_driver_exit);
533757cc3e9SRijo Thomas
534757cc3e9SRijo Thomas MODULE_AUTHOR(DRIVER_AUTHOR);
535757cc3e9SRijo Thomas MODULE_DESCRIPTION("AMD-TEE driver");
536757cc3e9SRijo Thomas MODULE_VERSION("1.0");
537757cc3e9SRijo Thomas MODULE_LICENSE("Dual MIT/GPL");
538