xref: /linux/drivers/tee/amdtee/core.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
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