162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/errno.h>
762306a36Sopenharmony_ci#include <linux/io.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/string.h>
1162306a36Sopenharmony_ci#include <linux/device.h>
1262306a36Sopenharmony_ci#include <linux/tee_drv.h>
1362306a36Sopenharmony_ci#include <linux/types.h>
1462306a36Sopenharmony_ci#include <linux/mm.h>
1562306a36Sopenharmony_ci#include <linux/uaccess.h>
1662306a36Sopenharmony_ci#include <linux/firmware.h>
1762306a36Sopenharmony_ci#include "amdtee_private.h"
1862306a36Sopenharmony_ci#include "../tee_private.h"
1962306a36Sopenharmony_ci#include <linux/psp-tee.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic struct amdtee_driver_data *drv_data;
2262306a36Sopenharmony_cistatic DEFINE_MUTEX(session_list_mutex);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic void amdtee_get_version(struct tee_device *teedev,
2562306a36Sopenharmony_ci			       struct tee_ioctl_version_data *vers)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct tee_ioctl_version_data v = {
2862306a36Sopenharmony_ci		.impl_id = TEE_IMPL_ID_AMDTEE,
2962306a36Sopenharmony_ci		.impl_caps = 0,
3062306a36Sopenharmony_ci		.gen_caps = TEE_GEN_CAP_GP,
3162306a36Sopenharmony_ci	};
3262306a36Sopenharmony_ci	*vers = v;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic int amdtee_open(struct tee_context *ctx)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct amdtee_context_data *ctxdata;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
4062306a36Sopenharmony_ci	if (!ctxdata)
4162306a36Sopenharmony_ci		return -ENOMEM;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	INIT_LIST_HEAD(&ctxdata->sess_list);
4462306a36Sopenharmony_ci	INIT_LIST_HEAD(&ctxdata->shm_list);
4562306a36Sopenharmony_ci	mutex_init(&ctxdata->shm_mutex);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	ctx->data = ctxdata;
4862306a36Sopenharmony_ci	return 0;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic void release_session(struct amdtee_session *sess)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	int i;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* Close any open session */
5662306a36Sopenharmony_ci	for (i = 0; i < TEE_NUM_SESSIONS; ++i) {
5762306a36Sopenharmony_ci		/* Check if session entry 'i' is valid */
5862306a36Sopenharmony_ci		if (!test_bit(i, sess->sess_mask))
5962306a36Sopenharmony_ci			continue;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		handle_close_session(sess->ta_handle, sess->session_info[i]);
6262306a36Sopenharmony_ci		handle_unload_ta(sess->ta_handle);
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	kfree(sess);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic void amdtee_release(struct tee_context *ctx)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct amdtee_context_data *ctxdata = ctx->data;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (!ctxdata)
7362306a36Sopenharmony_ci		return;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	while (true) {
7662306a36Sopenharmony_ci		struct amdtee_session *sess;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		sess = list_first_entry_or_null(&ctxdata->sess_list,
7962306a36Sopenharmony_ci						struct amdtee_session,
8062306a36Sopenharmony_ci						list_node);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci		if (!sess)
8362306a36Sopenharmony_ci			break;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		list_del(&sess->list_node);
8662306a36Sopenharmony_ci		release_session(sess);
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci	mutex_destroy(&ctxdata->shm_mutex);
8962306a36Sopenharmony_ci	kfree(ctxdata);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	ctx->data = NULL;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/**
9562306a36Sopenharmony_ci * alloc_session() - Allocate a session structure
9662306a36Sopenharmony_ci * @ctxdata:    TEE Context data structure
9762306a36Sopenharmony_ci * @session:    Session ID for which 'struct amdtee_session' structure is to be
9862306a36Sopenharmony_ci *              allocated.
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * Scans the TEE context's session list to check if TA is already loaded in to
10162306a36Sopenharmony_ci * TEE. If yes, returns the 'session' structure for that TA. Else allocates,
10262306a36Sopenharmony_ci * initializes a new 'session' structure and adds it to context's session list.
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci * The caller must hold a mutex.
10562306a36Sopenharmony_ci *
10662306a36Sopenharmony_ci * Returns:
10762306a36Sopenharmony_ci * 'struct amdtee_session *' on success and NULL on failure.
10862306a36Sopenharmony_ci */
10962306a36Sopenharmony_cistatic struct amdtee_session *alloc_session(struct amdtee_context_data *ctxdata,
11062306a36Sopenharmony_ci					    u32 session)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct amdtee_session *sess;
11362306a36Sopenharmony_ci	u32 ta_handle = get_ta_handle(session);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* Scan session list to check if TA is already loaded in to TEE */
11662306a36Sopenharmony_ci	list_for_each_entry(sess, &ctxdata->sess_list, list_node)
11762306a36Sopenharmony_ci		if (sess->ta_handle == ta_handle) {
11862306a36Sopenharmony_ci			kref_get(&sess->refcount);
11962306a36Sopenharmony_ci			return sess;
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* Allocate a new session and add to list */
12362306a36Sopenharmony_ci	sess = kzalloc(sizeof(*sess), GFP_KERNEL);
12462306a36Sopenharmony_ci	if (sess) {
12562306a36Sopenharmony_ci		sess->ta_handle = ta_handle;
12662306a36Sopenharmony_ci		kref_init(&sess->refcount);
12762306a36Sopenharmony_ci		spin_lock_init(&sess->lock);
12862306a36Sopenharmony_ci		list_add(&sess->list_node, &ctxdata->sess_list);
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return sess;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/* Requires mutex to be held */
13562306a36Sopenharmony_cistatic struct amdtee_session *find_session(struct amdtee_context_data *ctxdata,
13662306a36Sopenharmony_ci					   u32 session)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	u32 ta_handle = get_ta_handle(session);
13962306a36Sopenharmony_ci	u32 index = get_session_index(session);
14062306a36Sopenharmony_ci	struct amdtee_session *sess;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (index >= TEE_NUM_SESSIONS)
14362306a36Sopenharmony_ci		return NULL;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	list_for_each_entry(sess, &ctxdata->sess_list, list_node)
14662306a36Sopenharmony_ci		if (ta_handle == sess->ta_handle &&
14762306a36Sopenharmony_ci		    test_bit(index, sess->sess_mask))
14862306a36Sopenharmony_ci			return sess;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return NULL;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ciu32 get_buffer_id(struct tee_shm *shm)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct amdtee_context_data *ctxdata = shm->ctx->data;
15662306a36Sopenharmony_ci	struct amdtee_shm_data *shmdata;
15762306a36Sopenharmony_ci	u32 buf_id = 0;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	mutex_lock(&ctxdata->shm_mutex);
16062306a36Sopenharmony_ci	list_for_each_entry(shmdata, &ctxdata->shm_list, shm_node)
16162306a36Sopenharmony_ci		if (shmdata->kaddr == shm->kaddr) {
16262306a36Sopenharmony_ci			buf_id = shmdata->buf_id;
16362306a36Sopenharmony_ci			break;
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci	mutex_unlock(&ctxdata->shm_mutex);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return buf_id;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic DEFINE_MUTEX(drv_mutex);
17162306a36Sopenharmony_cistatic int copy_ta_binary(struct tee_context *ctx, void *ptr, void **ta,
17262306a36Sopenharmony_ci			  size_t *ta_size)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	const struct firmware *fw;
17562306a36Sopenharmony_ci	char fw_name[TA_PATH_MAX];
17662306a36Sopenharmony_ci	struct {
17762306a36Sopenharmony_ci		u32 lo;
17862306a36Sopenharmony_ci		u16 mid;
17962306a36Sopenharmony_ci		u16 hi_ver;
18062306a36Sopenharmony_ci		u8 seq_n[8];
18162306a36Sopenharmony_ci	} *uuid = ptr;
18262306a36Sopenharmony_ci	int n, rc = 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	n = snprintf(fw_name, TA_PATH_MAX,
18562306a36Sopenharmony_ci		     "%s/%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x.bin",
18662306a36Sopenharmony_ci		     TA_LOAD_PATH, uuid->lo, uuid->mid, uuid->hi_ver,
18762306a36Sopenharmony_ci		     uuid->seq_n[0], uuid->seq_n[1],
18862306a36Sopenharmony_ci		     uuid->seq_n[2], uuid->seq_n[3],
18962306a36Sopenharmony_ci		     uuid->seq_n[4], uuid->seq_n[5],
19062306a36Sopenharmony_ci		     uuid->seq_n[6], uuid->seq_n[7]);
19162306a36Sopenharmony_ci	if (n < 0 || n >= TA_PATH_MAX) {
19262306a36Sopenharmony_ci		pr_err("failed to get firmware name\n");
19362306a36Sopenharmony_ci		return -EINVAL;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	mutex_lock(&drv_mutex);
19762306a36Sopenharmony_ci	n = request_firmware(&fw, fw_name, &ctx->teedev->dev);
19862306a36Sopenharmony_ci	if (n) {
19962306a36Sopenharmony_ci		pr_err("failed to load firmware %s\n", fw_name);
20062306a36Sopenharmony_ci		rc = -ENOMEM;
20162306a36Sopenharmony_ci		goto unlock;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	*ta_size = roundup(fw->size, PAGE_SIZE);
20562306a36Sopenharmony_ci	*ta = (void *)__get_free_pages(GFP_KERNEL, get_order(*ta_size));
20662306a36Sopenharmony_ci	if (!*ta) {
20762306a36Sopenharmony_ci		pr_err("%s: get_free_pages failed\n", __func__);
20862306a36Sopenharmony_ci		rc = -ENOMEM;
20962306a36Sopenharmony_ci		goto rel_fw;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	memcpy(*ta, fw->data, fw->size);
21362306a36Sopenharmony_cirel_fw:
21462306a36Sopenharmony_ci	release_firmware(fw);
21562306a36Sopenharmony_ciunlock:
21662306a36Sopenharmony_ci	mutex_unlock(&drv_mutex);
21762306a36Sopenharmony_ci	return rc;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/* mutex must be held by caller */
22162306a36Sopenharmony_cistatic void destroy_session(struct kref *ref)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct amdtee_session *sess = container_of(ref, struct amdtee_session,
22462306a36Sopenharmony_ci						   refcount);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	list_del(&sess->list_node);
22762306a36Sopenharmony_ci	mutex_unlock(&session_list_mutex);
22862306a36Sopenharmony_ci	kfree(sess);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ciint amdtee_open_session(struct tee_context *ctx,
23262306a36Sopenharmony_ci			struct tee_ioctl_open_session_arg *arg,
23362306a36Sopenharmony_ci			struct tee_param *param)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct amdtee_context_data *ctxdata = ctx->data;
23662306a36Sopenharmony_ci	struct amdtee_session *sess = NULL;
23762306a36Sopenharmony_ci	u32 session_info, ta_handle;
23862306a36Sopenharmony_ci	size_t ta_size;
23962306a36Sopenharmony_ci	int rc, i;
24062306a36Sopenharmony_ci	void *ta;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (arg->clnt_login != TEE_IOCTL_LOGIN_PUBLIC) {
24362306a36Sopenharmony_ci		pr_err("unsupported client login method\n");
24462306a36Sopenharmony_ci		return -EINVAL;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	rc = copy_ta_binary(ctx, &arg->uuid[0], &ta, &ta_size);
24862306a36Sopenharmony_ci	if (rc) {
24962306a36Sopenharmony_ci		pr_err("failed to copy TA binary\n");
25062306a36Sopenharmony_ci		return rc;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Load the TA binary into TEE environment */
25462306a36Sopenharmony_ci	handle_load_ta(ta, ta_size, arg);
25562306a36Sopenharmony_ci	if (arg->ret != TEEC_SUCCESS)
25662306a36Sopenharmony_ci		goto out;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	ta_handle = get_ta_handle(arg->session);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	mutex_lock(&session_list_mutex);
26162306a36Sopenharmony_ci	sess = alloc_session(ctxdata, arg->session);
26262306a36Sopenharmony_ci	mutex_unlock(&session_list_mutex);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (!sess) {
26562306a36Sopenharmony_ci		handle_unload_ta(ta_handle);
26662306a36Sopenharmony_ci		rc = -ENOMEM;
26762306a36Sopenharmony_ci		goto out;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/* Open session with loaded TA */
27162306a36Sopenharmony_ci	handle_open_session(arg, &session_info, param);
27262306a36Sopenharmony_ci	if (arg->ret != TEEC_SUCCESS) {
27362306a36Sopenharmony_ci		pr_err("open_session failed %d\n", arg->ret);
27462306a36Sopenharmony_ci		handle_unload_ta(ta_handle);
27562306a36Sopenharmony_ci		kref_put_mutex(&sess->refcount, destroy_session,
27662306a36Sopenharmony_ci			       &session_list_mutex);
27762306a36Sopenharmony_ci		goto out;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* Find an empty session index for the given TA */
28162306a36Sopenharmony_ci	spin_lock(&sess->lock);
28262306a36Sopenharmony_ci	i = find_first_zero_bit(sess->sess_mask, TEE_NUM_SESSIONS);
28362306a36Sopenharmony_ci	if (i < TEE_NUM_SESSIONS) {
28462306a36Sopenharmony_ci		sess->session_info[i] = session_info;
28562306a36Sopenharmony_ci		set_session_id(ta_handle, i, &arg->session);
28662306a36Sopenharmony_ci		set_bit(i, sess->sess_mask);
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci	spin_unlock(&sess->lock);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (i >= TEE_NUM_SESSIONS) {
29162306a36Sopenharmony_ci		pr_err("reached maximum session count %d\n", TEE_NUM_SESSIONS);
29262306a36Sopenharmony_ci		handle_close_session(ta_handle, session_info);
29362306a36Sopenharmony_ci		handle_unload_ta(ta_handle);
29462306a36Sopenharmony_ci		kref_put_mutex(&sess->refcount, destroy_session,
29562306a36Sopenharmony_ci			       &session_list_mutex);
29662306a36Sopenharmony_ci		rc = -ENOMEM;
29762306a36Sopenharmony_ci		goto out;
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ciout:
30162306a36Sopenharmony_ci	free_pages((u64)ta, get_order(ta_size));
30262306a36Sopenharmony_ci	return rc;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ciint amdtee_close_session(struct tee_context *ctx, u32 session)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct amdtee_context_data *ctxdata = ctx->data;
30862306a36Sopenharmony_ci	u32 i, ta_handle, session_info;
30962306a36Sopenharmony_ci	struct amdtee_session *sess;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	pr_debug("%s: sid = 0x%x\n", __func__, session);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/*
31462306a36Sopenharmony_ci	 * Check that the session is valid and clear the session
31562306a36Sopenharmony_ci	 * usage bit
31662306a36Sopenharmony_ci	 */
31762306a36Sopenharmony_ci	mutex_lock(&session_list_mutex);
31862306a36Sopenharmony_ci	sess = find_session(ctxdata, session);
31962306a36Sopenharmony_ci	if (sess) {
32062306a36Sopenharmony_ci		ta_handle = get_ta_handle(session);
32162306a36Sopenharmony_ci		i = get_session_index(session);
32262306a36Sopenharmony_ci		session_info = sess->session_info[i];
32362306a36Sopenharmony_ci		spin_lock(&sess->lock);
32462306a36Sopenharmony_ci		clear_bit(i, sess->sess_mask);
32562306a36Sopenharmony_ci		spin_unlock(&sess->lock);
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci	mutex_unlock(&session_list_mutex);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (!sess)
33062306a36Sopenharmony_ci		return -EINVAL;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* Close the session */
33362306a36Sopenharmony_ci	handle_close_session(ta_handle, session_info);
33462306a36Sopenharmony_ci	handle_unload_ta(ta_handle);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	kref_put_mutex(&sess->refcount, destroy_session, &session_list_mutex);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	return 0;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ciint amdtee_map_shmem(struct tee_shm *shm)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct amdtee_context_data *ctxdata;
34462306a36Sopenharmony_ci	struct amdtee_shm_data *shmnode;
34562306a36Sopenharmony_ci	struct shmem_desc shmem;
34662306a36Sopenharmony_ci	int rc, count;
34762306a36Sopenharmony_ci	u32 buf_id;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (!shm)
35062306a36Sopenharmony_ci		return -EINVAL;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	shmnode = kmalloc(sizeof(*shmnode), GFP_KERNEL);
35362306a36Sopenharmony_ci	if (!shmnode)
35462306a36Sopenharmony_ci		return -ENOMEM;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	count = 1;
35762306a36Sopenharmony_ci	shmem.kaddr = shm->kaddr;
35862306a36Sopenharmony_ci	shmem.size = shm->size;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	/*
36162306a36Sopenharmony_ci	 * Send a MAP command to TEE and get the corresponding
36262306a36Sopenharmony_ci	 * buffer Id
36362306a36Sopenharmony_ci	 */
36462306a36Sopenharmony_ci	rc = handle_map_shmem(count, &shmem, &buf_id);
36562306a36Sopenharmony_ci	if (rc) {
36662306a36Sopenharmony_ci		pr_err("map_shmem failed: ret = %d\n", rc);
36762306a36Sopenharmony_ci		kfree(shmnode);
36862306a36Sopenharmony_ci		return rc;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	shmnode->kaddr = shm->kaddr;
37262306a36Sopenharmony_ci	shmnode->buf_id = buf_id;
37362306a36Sopenharmony_ci	ctxdata = shm->ctx->data;
37462306a36Sopenharmony_ci	mutex_lock(&ctxdata->shm_mutex);
37562306a36Sopenharmony_ci	list_add(&shmnode->shm_node, &ctxdata->shm_list);
37662306a36Sopenharmony_ci	mutex_unlock(&ctxdata->shm_mutex);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	pr_debug("buf_id :[%x] kaddr[%p]\n", shmnode->buf_id, shmnode->kaddr);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return 0;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_civoid amdtee_unmap_shmem(struct tee_shm *shm)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct amdtee_context_data *ctxdata;
38662306a36Sopenharmony_ci	struct amdtee_shm_data *shmnode;
38762306a36Sopenharmony_ci	u32 buf_id;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (!shm)
39062306a36Sopenharmony_ci		return;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	buf_id = get_buffer_id(shm);
39362306a36Sopenharmony_ci	/* Unmap the shared memory from TEE */
39462306a36Sopenharmony_ci	handle_unmap_shmem(buf_id);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ctxdata = shm->ctx->data;
39762306a36Sopenharmony_ci	mutex_lock(&ctxdata->shm_mutex);
39862306a36Sopenharmony_ci	list_for_each_entry(shmnode, &ctxdata->shm_list, shm_node)
39962306a36Sopenharmony_ci		if (buf_id == shmnode->buf_id) {
40062306a36Sopenharmony_ci			list_del(&shmnode->shm_node);
40162306a36Sopenharmony_ci			kfree(shmnode);
40262306a36Sopenharmony_ci			break;
40362306a36Sopenharmony_ci		}
40462306a36Sopenharmony_ci	mutex_unlock(&ctxdata->shm_mutex);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ciint amdtee_invoke_func(struct tee_context *ctx,
40862306a36Sopenharmony_ci		       struct tee_ioctl_invoke_arg *arg,
40962306a36Sopenharmony_ci		       struct tee_param *param)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	struct amdtee_context_data *ctxdata = ctx->data;
41262306a36Sopenharmony_ci	struct amdtee_session *sess;
41362306a36Sopenharmony_ci	u32 i, session_info;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* Check that the session is valid */
41662306a36Sopenharmony_ci	mutex_lock(&session_list_mutex);
41762306a36Sopenharmony_ci	sess = find_session(ctxdata, arg->session);
41862306a36Sopenharmony_ci	if (sess) {
41962306a36Sopenharmony_ci		i = get_session_index(arg->session);
42062306a36Sopenharmony_ci		session_info = sess->session_info[i];
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci	mutex_unlock(&session_list_mutex);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	if (!sess)
42562306a36Sopenharmony_ci		return -EINVAL;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	handle_invoke_cmd(arg, session_info, param);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ciint amdtee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	return -EINVAL;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic const struct tee_driver_ops amdtee_ops = {
43862306a36Sopenharmony_ci	.get_version = amdtee_get_version,
43962306a36Sopenharmony_ci	.open = amdtee_open,
44062306a36Sopenharmony_ci	.release = amdtee_release,
44162306a36Sopenharmony_ci	.open_session = amdtee_open_session,
44262306a36Sopenharmony_ci	.close_session = amdtee_close_session,
44362306a36Sopenharmony_ci	.invoke_func = amdtee_invoke_func,
44462306a36Sopenharmony_ci	.cancel_req = amdtee_cancel_req,
44562306a36Sopenharmony_ci};
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic const struct tee_desc amdtee_desc = {
44862306a36Sopenharmony_ci	.name = DRIVER_NAME "-clnt",
44962306a36Sopenharmony_ci	.ops = &amdtee_ops,
45062306a36Sopenharmony_ci	.owner = THIS_MODULE,
45162306a36Sopenharmony_ci};
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int __init amdtee_driver_init(void)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	struct tee_device *teedev;
45662306a36Sopenharmony_ci	struct tee_shm_pool *pool;
45762306a36Sopenharmony_ci	struct amdtee *amdtee;
45862306a36Sopenharmony_ci	int rc;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	rc = psp_check_tee_status();
46162306a36Sopenharmony_ci	if (rc) {
46262306a36Sopenharmony_ci		pr_err("amd-tee driver: tee not present\n");
46362306a36Sopenharmony_ci		return rc;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
46762306a36Sopenharmony_ci	if (!drv_data)
46862306a36Sopenharmony_ci		return -ENOMEM;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	amdtee = kzalloc(sizeof(*amdtee), GFP_KERNEL);
47162306a36Sopenharmony_ci	if (!amdtee) {
47262306a36Sopenharmony_ci		rc = -ENOMEM;
47362306a36Sopenharmony_ci		goto err_kfree_drv_data;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	pool = amdtee_config_shm();
47762306a36Sopenharmony_ci	if (IS_ERR(pool)) {
47862306a36Sopenharmony_ci		pr_err("shared pool configuration error\n");
47962306a36Sopenharmony_ci		rc = PTR_ERR(pool);
48062306a36Sopenharmony_ci		goto err_kfree_amdtee;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	teedev = tee_device_alloc(&amdtee_desc, NULL, pool, amdtee);
48462306a36Sopenharmony_ci	if (IS_ERR(teedev)) {
48562306a36Sopenharmony_ci		rc = PTR_ERR(teedev);
48662306a36Sopenharmony_ci		goto err_free_pool;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci	amdtee->teedev = teedev;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	rc = tee_device_register(amdtee->teedev);
49162306a36Sopenharmony_ci	if (rc)
49262306a36Sopenharmony_ci		goto err_device_unregister;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	amdtee->pool = pool;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	drv_data->amdtee = amdtee;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	pr_info("amd-tee driver initialization successful\n");
49962306a36Sopenharmony_ci	return 0;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cierr_device_unregister:
50262306a36Sopenharmony_ci	tee_device_unregister(amdtee->teedev);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cierr_free_pool:
50562306a36Sopenharmony_ci	tee_shm_pool_free(pool);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cierr_kfree_amdtee:
50862306a36Sopenharmony_ci	kfree(amdtee);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cierr_kfree_drv_data:
51162306a36Sopenharmony_ci	kfree(drv_data);
51262306a36Sopenharmony_ci	drv_data = NULL;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	pr_err("amd-tee driver initialization failed\n");
51562306a36Sopenharmony_ci	return rc;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_cimodule_init(amdtee_driver_init);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic void __exit amdtee_driver_exit(void)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct amdtee *amdtee;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (!drv_data || !drv_data->amdtee)
52462306a36Sopenharmony_ci		return;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	amdtee = drv_data->amdtee;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	tee_device_unregister(amdtee->teedev);
52962306a36Sopenharmony_ci	tee_shm_pool_free(amdtee->pool);
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_cimodule_exit(amdtee_driver_exit);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
53462306a36Sopenharmony_ciMODULE_DESCRIPTION("AMD-TEE driver");
53562306a36Sopenharmony_ciMODULE_VERSION("1.0");
53662306a36Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL");
537