18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/errno.h>
78c2ecf20Sopenharmony_ci#include <linux/io.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/string.h>
118c2ecf20Sopenharmony_ci#include <linux/device.h>
128c2ecf20Sopenharmony_ci#include <linux/tee_drv.h>
138c2ecf20Sopenharmony_ci#include <linux/types.h>
148c2ecf20Sopenharmony_ci#include <linux/mm.h>
158c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
168c2ecf20Sopenharmony_ci#include <linux/firmware.h>
178c2ecf20Sopenharmony_ci#include "amdtee_private.h"
188c2ecf20Sopenharmony_ci#include "../tee_private.h"
198c2ecf20Sopenharmony_ci#include <linux/psp-tee.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic struct amdtee_driver_data *drv_data;
228c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(session_list_mutex);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic void amdtee_get_version(struct tee_device *teedev,
258c2ecf20Sopenharmony_ci			       struct tee_ioctl_version_data *vers)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	struct tee_ioctl_version_data v = {
288c2ecf20Sopenharmony_ci		.impl_id = TEE_IMPL_ID_AMDTEE,
298c2ecf20Sopenharmony_ci		.impl_caps = 0,
308c2ecf20Sopenharmony_ci		.gen_caps = TEE_GEN_CAP_GP,
318c2ecf20Sopenharmony_ci	};
328c2ecf20Sopenharmony_ci	*vers = v;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic int amdtee_open(struct tee_context *ctx)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	struct amdtee_context_data *ctxdata;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
408c2ecf20Sopenharmony_ci	if (!ctxdata)
418c2ecf20Sopenharmony_ci		return -ENOMEM;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctxdata->sess_list);
448c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctxdata->shm_list);
458c2ecf20Sopenharmony_ci	mutex_init(&ctxdata->shm_mutex);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	ctx->data = ctxdata;
488c2ecf20Sopenharmony_ci	return 0;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void release_session(struct amdtee_session *sess)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	int i;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	/* Close any open session */
568c2ecf20Sopenharmony_ci	for (i = 0; i < TEE_NUM_SESSIONS; ++i) {
578c2ecf20Sopenharmony_ci		/* Check if session entry 'i' is valid */
588c2ecf20Sopenharmony_ci		if (!test_bit(i, sess->sess_mask))
598c2ecf20Sopenharmony_ci			continue;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		handle_close_session(sess->ta_handle, sess->session_info[i]);
628c2ecf20Sopenharmony_ci		handle_unload_ta(sess->ta_handle);
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	kfree(sess);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic void amdtee_release(struct tee_context *ctx)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct amdtee_context_data *ctxdata = ctx->data;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (!ctxdata)
738c2ecf20Sopenharmony_ci		return;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	while (true) {
768c2ecf20Sopenharmony_ci		struct amdtee_session *sess;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		sess = list_first_entry_or_null(&ctxdata->sess_list,
798c2ecf20Sopenharmony_ci						struct amdtee_session,
808c2ecf20Sopenharmony_ci						list_node);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci		if (!sess)
838c2ecf20Sopenharmony_ci			break;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		list_del(&sess->list_node);
868c2ecf20Sopenharmony_ci		release_session(sess);
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci	mutex_destroy(&ctxdata->shm_mutex);
898c2ecf20Sopenharmony_ci	kfree(ctxdata);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	ctx->data = NULL;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/**
958c2ecf20Sopenharmony_ci * alloc_session() - Allocate a session structure
968c2ecf20Sopenharmony_ci * @ctxdata:    TEE Context data structure
978c2ecf20Sopenharmony_ci * @session:    Session ID for which 'struct amdtee_session' structure is to be
988c2ecf20Sopenharmony_ci *              allocated.
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci * Scans the TEE context's session list to check if TA is already loaded in to
1018c2ecf20Sopenharmony_ci * TEE. If yes, returns the 'session' structure for that TA. Else allocates,
1028c2ecf20Sopenharmony_ci * initializes a new 'session' structure and adds it to context's session list.
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * The caller must hold a mutex.
1058c2ecf20Sopenharmony_ci *
1068c2ecf20Sopenharmony_ci * Returns:
1078c2ecf20Sopenharmony_ci * 'struct amdtee_session *' on success and NULL on failure.
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_cistatic struct amdtee_session *alloc_session(struct amdtee_context_data *ctxdata,
1108c2ecf20Sopenharmony_ci					    u32 session)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct amdtee_session *sess;
1138c2ecf20Sopenharmony_ci	u32 ta_handle = get_ta_handle(session);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/* Scan session list to check if TA is already loaded in to TEE */
1168c2ecf20Sopenharmony_ci	list_for_each_entry(sess, &ctxdata->sess_list, list_node)
1178c2ecf20Sopenharmony_ci		if (sess->ta_handle == ta_handle) {
1188c2ecf20Sopenharmony_ci			kref_get(&sess->refcount);
1198c2ecf20Sopenharmony_ci			return sess;
1208c2ecf20Sopenharmony_ci		}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/* Allocate a new session and add to list */
1238c2ecf20Sopenharmony_ci	sess = kzalloc(sizeof(*sess), GFP_KERNEL);
1248c2ecf20Sopenharmony_ci	if (sess) {
1258c2ecf20Sopenharmony_ci		sess->ta_handle = ta_handle;
1268c2ecf20Sopenharmony_ci		kref_init(&sess->refcount);
1278c2ecf20Sopenharmony_ci		spin_lock_init(&sess->lock);
1288c2ecf20Sopenharmony_ci		list_add(&sess->list_node, &ctxdata->sess_list);
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return sess;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci/* Requires mutex to be held */
1358c2ecf20Sopenharmony_cistatic struct amdtee_session *find_session(struct amdtee_context_data *ctxdata,
1368c2ecf20Sopenharmony_ci					   u32 session)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	u32 ta_handle = get_ta_handle(session);
1398c2ecf20Sopenharmony_ci	u32 index = get_session_index(session);
1408c2ecf20Sopenharmony_ci	struct amdtee_session *sess;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (index >= TEE_NUM_SESSIONS)
1438c2ecf20Sopenharmony_ci		return NULL;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	list_for_each_entry(sess, &ctxdata->sess_list, list_node)
1468c2ecf20Sopenharmony_ci		if (ta_handle == sess->ta_handle &&
1478c2ecf20Sopenharmony_ci		    test_bit(index, sess->sess_mask))
1488c2ecf20Sopenharmony_ci			return sess;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return NULL;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ciu32 get_buffer_id(struct tee_shm *shm)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct amdtee_context_data *ctxdata = shm->ctx->data;
1568c2ecf20Sopenharmony_ci	struct amdtee_shm_data *shmdata;
1578c2ecf20Sopenharmony_ci	u32 buf_id = 0;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	mutex_lock(&ctxdata->shm_mutex);
1608c2ecf20Sopenharmony_ci	list_for_each_entry(shmdata, &ctxdata->shm_list, shm_node)
1618c2ecf20Sopenharmony_ci		if (shmdata->kaddr == shm->kaddr) {
1628c2ecf20Sopenharmony_ci			buf_id = shmdata->buf_id;
1638c2ecf20Sopenharmony_ci			break;
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci	mutex_unlock(&ctxdata->shm_mutex);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	return buf_id;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(drv_mutex);
1718c2ecf20Sopenharmony_cistatic int copy_ta_binary(struct tee_context *ctx, void *ptr, void **ta,
1728c2ecf20Sopenharmony_ci			  size_t *ta_size)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	const struct firmware *fw;
1758c2ecf20Sopenharmony_ci	char fw_name[TA_PATH_MAX];
1768c2ecf20Sopenharmony_ci	struct {
1778c2ecf20Sopenharmony_ci		u32 lo;
1788c2ecf20Sopenharmony_ci		u16 mid;
1798c2ecf20Sopenharmony_ci		u16 hi_ver;
1808c2ecf20Sopenharmony_ci		u8 seq_n[8];
1818c2ecf20Sopenharmony_ci	} *uuid = ptr;
1828c2ecf20Sopenharmony_ci	int n, rc = 0;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	n = snprintf(fw_name, TA_PATH_MAX,
1858c2ecf20Sopenharmony_ci		     "%s/%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x.bin",
1868c2ecf20Sopenharmony_ci		     TA_LOAD_PATH, uuid->lo, uuid->mid, uuid->hi_ver,
1878c2ecf20Sopenharmony_ci		     uuid->seq_n[0], uuid->seq_n[1],
1888c2ecf20Sopenharmony_ci		     uuid->seq_n[2], uuid->seq_n[3],
1898c2ecf20Sopenharmony_ci		     uuid->seq_n[4], uuid->seq_n[5],
1908c2ecf20Sopenharmony_ci		     uuid->seq_n[6], uuid->seq_n[7]);
1918c2ecf20Sopenharmony_ci	if (n < 0 || n >= TA_PATH_MAX) {
1928c2ecf20Sopenharmony_ci		pr_err("failed to get firmware name\n");
1938c2ecf20Sopenharmony_ci		return -EINVAL;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	mutex_lock(&drv_mutex);
1978c2ecf20Sopenharmony_ci	n = request_firmware(&fw, fw_name, &ctx->teedev->dev);
1988c2ecf20Sopenharmony_ci	if (n) {
1998c2ecf20Sopenharmony_ci		pr_err("failed to load firmware %s\n", fw_name);
2008c2ecf20Sopenharmony_ci		rc = -ENOMEM;
2018c2ecf20Sopenharmony_ci		goto unlock;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	*ta_size = roundup(fw->size, PAGE_SIZE);
2058c2ecf20Sopenharmony_ci	*ta = (void *)__get_free_pages(GFP_KERNEL, get_order(*ta_size));
2068c2ecf20Sopenharmony_ci	if (!*ta) {
2078c2ecf20Sopenharmony_ci		pr_err("%s: get_free_pages failed\n", __func__);
2088c2ecf20Sopenharmony_ci		rc = -ENOMEM;
2098c2ecf20Sopenharmony_ci		goto rel_fw;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	memcpy(*ta, fw->data, fw->size);
2138c2ecf20Sopenharmony_cirel_fw:
2148c2ecf20Sopenharmony_ci	release_firmware(fw);
2158c2ecf20Sopenharmony_ciunlock:
2168c2ecf20Sopenharmony_ci	mutex_unlock(&drv_mutex);
2178c2ecf20Sopenharmony_ci	return rc;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/* mutex must be held by caller */
2218c2ecf20Sopenharmony_cistatic void destroy_session(struct kref *ref)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct amdtee_session *sess = container_of(ref, struct amdtee_session,
2248c2ecf20Sopenharmony_ci						   refcount);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	list_del(&sess->list_node);
2278c2ecf20Sopenharmony_ci	mutex_unlock(&session_list_mutex);
2288c2ecf20Sopenharmony_ci	kfree(sess);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ciint amdtee_open_session(struct tee_context *ctx,
2328c2ecf20Sopenharmony_ci			struct tee_ioctl_open_session_arg *arg,
2338c2ecf20Sopenharmony_ci			struct tee_param *param)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct amdtee_context_data *ctxdata = ctx->data;
2368c2ecf20Sopenharmony_ci	struct amdtee_session *sess = NULL;
2378c2ecf20Sopenharmony_ci	u32 session_info, ta_handle;
2388c2ecf20Sopenharmony_ci	size_t ta_size;
2398c2ecf20Sopenharmony_ci	int rc, i;
2408c2ecf20Sopenharmony_ci	void *ta;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (arg->clnt_login != TEE_IOCTL_LOGIN_PUBLIC) {
2438c2ecf20Sopenharmony_ci		pr_err("unsupported client login method\n");
2448c2ecf20Sopenharmony_ci		return -EINVAL;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	rc = copy_ta_binary(ctx, &arg->uuid[0], &ta, &ta_size);
2488c2ecf20Sopenharmony_ci	if (rc) {
2498c2ecf20Sopenharmony_ci		pr_err("failed to copy TA binary\n");
2508c2ecf20Sopenharmony_ci		return rc;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* Load the TA binary into TEE environment */
2548c2ecf20Sopenharmony_ci	handle_load_ta(ta, ta_size, arg);
2558c2ecf20Sopenharmony_ci	if (arg->ret != TEEC_SUCCESS)
2568c2ecf20Sopenharmony_ci		goto out;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	ta_handle = get_ta_handle(arg->session);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	mutex_lock(&session_list_mutex);
2618c2ecf20Sopenharmony_ci	sess = alloc_session(ctxdata, arg->session);
2628c2ecf20Sopenharmony_ci	mutex_unlock(&session_list_mutex);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (!sess) {
2658c2ecf20Sopenharmony_ci		handle_unload_ta(ta_handle);
2668c2ecf20Sopenharmony_ci		rc = -ENOMEM;
2678c2ecf20Sopenharmony_ci		goto out;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	/* Open session with loaded TA */
2718c2ecf20Sopenharmony_ci	handle_open_session(arg, &session_info, param);
2728c2ecf20Sopenharmony_ci	if (arg->ret != TEEC_SUCCESS) {
2738c2ecf20Sopenharmony_ci		pr_err("open_session failed %d\n", arg->ret);
2748c2ecf20Sopenharmony_ci		handle_unload_ta(ta_handle);
2758c2ecf20Sopenharmony_ci		kref_put_mutex(&sess->refcount, destroy_session,
2768c2ecf20Sopenharmony_ci			       &session_list_mutex);
2778c2ecf20Sopenharmony_ci		goto out;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* Find an empty session index for the given TA */
2818c2ecf20Sopenharmony_ci	spin_lock(&sess->lock);
2828c2ecf20Sopenharmony_ci	i = find_first_zero_bit(sess->sess_mask, TEE_NUM_SESSIONS);
2838c2ecf20Sopenharmony_ci	if (i < TEE_NUM_SESSIONS) {
2848c2ecf20Sopenharmony_ci		sess->session_info[i] = session_info;
2858c2ecf20Sopenharmony_ci		set_session_id(ta_handle, i, &arg->session);
2868c2ecf20Sopenharmony_ci		set_bit(i, sess->sess_mask);
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci	spin_unlock(&sess->lock);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (i >= TEE_NUM_SESSIONS) {
2918c2ecf20Sopenharmony_ci		pr_err("reached maximum session count %d\n", TEE_NUM_SESSIONS);
2928c2ecf20Sopenharmony_ci		handle_close_session(ta_handle, session_info);
2938c2ecf20Sopenharmony_ci		handle_unload_ta(ta_handle);
2948c2ecf20Sopenharmony_ci		kref_put_mutex(&sess->refcount, destroy_session,
2958c2ecf20Sopenharmony_ci			       &session_list_mutex);
2968c2ecf20Sopenharmony_ci		rc = -ENOMEM;
2978c2ecf20Sopenharmony_ci		goto out;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ciout:
3018c2ecf20Sopenharmony_ci	free_pages((u64)ta, get_order(ta_size));
3028c2ecf20Sopenharmony_ci	return rc;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ciint amdtee_close_session(struct tee_context *ctx, u32 session)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct amdtee_context_data *ctxdata = ctx->data;
3088c2ecf20Sopenharmony_ci	u32 i, ta_handle, session_info;
3098c2ecf20Sopenharmony_ci	struct amdtee_session *sess;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	pr_debug("%s: sid = 0x%x\n", __func__, session);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/*
3148c2ecf20Sopenharmony_ci	 * Check that the session is valid and clear the session
3158c2ecf20Sopenharmony_ci	 * usage bit
3168c2ecf20Sopenharmony_ci	 */
3178c2ecf20Sopenharmony_ci	mutex_lock(&session_list_mutex);
3188c2ecf20Sopenharmony_ci	sess = find_session(ctxdata, session);
3198c2ecf20Sopenharmony_ci	if (sess) {
3208c2ecf20Sopenharmony_ci		ta_handle = get_ta_handle(session);
3218c2ecf20Sopenharmony_ci		i = get_session_index(session);
3228c2ecf20Sopenharmony_ci		session_info = sess->session_info[i];
3238c2ecf20Sopenharmony_ci		spin_lock(&sess->lock);
3248c2ecf20Sopenharmony_ci		clear_bit(i, sess->sess_mask);
3258c2ecf20Sopenharmony_ci		spin_unlock(&sess->lock);
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci	mutex_unlock(&session_list_mutex);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (!sess)
3308c2ecf20Sopenharmony_ci		return -EINVAL;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/* Close the session */
3338c2ecf20Sopenharmony_ci	handle_close_session(ta_handle, session_info);
3348c2ecf20Sopenharmony_ci	handle_unload_ta(ta_handle);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	kref_put_mutex(&sess->refcount, destroy_session, &session_list_mutex);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	return 0;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ciint amdtee_map_shmem(struct tee_shm *shm)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct amdtee_context_data *ctxdata;
3448c2ecf20Sopenharmony_ci	struct amdtee_shm_data *shmnode;
3458c2ecf20Sopenharmony_ci	struct shmem_desc shmem;
3468c2ecf20Sopenharmony_ci	int rc, count;
3478c2ecf20Sopenharmony_ci	u32 buf_id;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (!shm)
3508c2ecf20Sopenharmony_ci		return -EINVAL;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	shmnode = kmalloc(sizeof(*shmnode), GFP_KERNEL);
3538c2ecf20Sopenharmony_ci	if (!shmnode)
3548c2ecf20Sopenharmony_ci		return -ENOMEM;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	count = 1;
3578c2ecf20Sopenharmony_ci	shmem.kaddr = shm->kaddr;
3588c2ecf20Sopenharmony_ci	shmem.size = shm->size;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/*
3618c2ecf20Sopenharmony_ci	 * Send a MAP command to TEE and get the corresponding
3628c2ecf20Sopenharmony_ci	 * buffer Id
3638c2ecf20Sopenharmony_ci	 */
3648c2ecf20Sopenharmony_ci	rc = handle_map_shmem(count, &shmem, &buf_id);
3658c2ecf20Sopenharmony_ci	if (rc) {
3668c2ecf20Sopenharmony_ci		pr_err("map_shmem failed: ret = %d\n", rc);
3678c2ecf20Sopenharmony_ci		kfree(shmnode);
3688c2ecf20Sopenharmony_ci		return rc;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	shmnode->kaddr = shm->kaddr;
3728c2ecf20Sopenharmony_ci	shmnode->buf_id = buf_id;
3738c2ecf20Sopenharmony_ci	ctxdata = shm->ctx->data;
3748c2ecf20Sopenharmony_ci	mutex_lock(&ctxdata->shm_mutex);
3758c2ecf20Sopenharmony_ci	list_add(&shmnode->shm_node, &ctxdata->shm_list);
3768c2ecf20Sopenharmony_ci	mutex_unlock(&ctxdata->shm_mutex);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	pr_debug("buf_id :[%x] kaddr[%p]\n", shmnode->buf_id, shmnode->kaddr);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	return 0;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_civoid amdtee_unmap_shmem(struct tee_shm *shm)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct amdtee_context_data *ctxdata;
3868c2ecf20Sopenharmony_ci	struct amdtee_shm_data *shmnode;
3878c2ecf20Sopenharmony_ci	u32 buf_id;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (!shm)
3908c2ecf20Sopenharmony_ci		return;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	buf_id = get_buffer_id(shm);
3938c2ecf20Sopenharmony_ci	/* Unmap the shared memory from TEE */
3948c2ecf20Sopenharmony_ci	handle_unmap_shmem(buf_id);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	ctxdata = shm->ctx->data;
3978c2ecf20Sopenharmony_ci	mutex_lock(&ctxdata->shm_mutex);
3988c2ecf20Sopenharmony_ci	list_for_each_entry(shmnode, &ctxdata->shm_list, shm_node)
3998c2ecf20Sopenharmony_ci		if (buf_id == shmnode->buf_id) {
4008c2ecf20Sopenharmony_ci			list_del(&shmnode->shm_node);
4018c2ecf20Sopenharmony_ci			kfree(shmnode);
4028c2ecf20Sopenharmony_ci			break;
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci	mutex_unlock(&ctxdata->shm_mutex);
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ciint amdtee_invoke_func(struct tee_context *ctx,
4088c2ecf20Sopenharmony_ci		       struct tee_ioctl_invoke_arg *arg,
4098c2ecf20Sopenharmony_ci		       struct tee_param *param)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	struct amdtee_context_data *ctxdata = ctx->data;
4128c2ecf20Sopenharmony_ci	struct amdtee_session *sess;
4138c2ecf20Sopenharmony_ci	u32 i, session_info;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* Check that the session is valid */
4168c2ecf20Sopenharmony_ci	mutex_lock(&session_list_mutex);
4178c2ecf20Sopenharmony_ci	sess = find_session(ctxdata, arg->session);
4188c2ecf20Sopenharmony_ci	if (sess) {
4198c2ecf20Sopenharmony_ci		i = get_session_index(arg->session);
4208c2ecf20Sopenharmony_ci		session_info = sess->session_info[i];
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci	mutex_unlock(&session_list_mutex);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (!sess)
4258c2ecf20Sopenharmony_ci		return -EINVAL;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	handle_invoke_cmd(arg, session_info, param);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	return 0;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ciint amdtee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	return -EINVAL;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic const struct tee_driver_ops amdtee_ops = {
4388c2ecf20Sopenharmony_ci	.get_version = amdtee_get_version,
4398c2ecf20Sopenharmony_ci	.open = amdtee_open,
4408c2ecf20Sopenharmony_ci	.release = amdtee_release,
4418c2ecf20Sopenharmony_ci	.open_session = amdtee_open_session,
4428c2ecf20Sopenharmony_ci	.close_session = amdtee_close_session,
4438c2ecf20Sopenharmony_ci	.invoke_func = amdtee_invoke_func,
4448c2ecf20Sopenharmony_ci	.cancel_req = amdtee_cancel_req,
4458c2ecf20Sopenharmony_ci};
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic const struct tee_desc amdtee_desc = {
4488c2ecf20Sopenharmony_ci	.name = DRIVER_NAME "-clnt",
4498c2ecf20Sopenharmony_ci	.ops = &amdtee_ops,
4508c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
4518c2ecf20Sopenharmony_ci};
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic int __init amdtee_driver_init(void)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct tee_device *teedev;
4568c2ecf20Sopenharmony_ci	struct tee_shm_pool *pool;
4578c2ecf20Sopenharmony_ci	struct amdtee *amdtee;
4588c2ecf20Sopenharmony_ci	int rc;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	rc = psp_check_tee_status();
4618c2ecf20Sopenharmony_ci	if (rc) {
4628c2ecf20Sopenharmony_ci		pr_err("amd-tee driver: tee not present\n");
4638c2ecf20Sopenharmony_ci		return rc;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
4678c2ecf20Sopenharmony_ci	if (!drv_data)
4688c2ecf20Sopenharmony_ci		return -ENOMEM;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	amdtee = kzalloc(sizeof(*amdtee), GFP_KERNEL);
4718c2ecf20Sopenharmony_ci	if (!amdtee) {
4728c2ecf20Sopenharmony_ci		rc = -ENOMEM;
4738c2ecf20Sopenharmony_ci		goto err_kfree_drv_data;
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	pool = amdtee_config_shm();
4778c2ecf20Sopenharmony_ci	if (IS_ERR(pool)) {
4788c2ecf20Sopenharmony_ci		pr_err("shared pool configuration error\n");
4798c2ecf20Sopenharmony_ci		rc = PTR_ERR(pool);
4808c2ecf20Sopenharmony_ci		goto err_kfree_amdtee;
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	teedev = tee_device_alloc(&amdtee_desc, NULL, pool, amdtee);
4848c2ecf20Sopenharmony_ci	if (IS_ERR(teedev)) {
4858c2ecf20Sopenharmony_ci		rc = PTR_ERR(teedev);
4868c2ecf20Sopenharmony_ci		goto err_free_pool;
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci	amdtee->teedev = teedev;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	rc = tee_device_register(amdtee->teedev);
4918c2ecf20Sopenharmony_ci	if (rc)
4928c2ecf20Sopenharmony_ci		goto err_device_unregister;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	amdtee->pool = pool;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	drv_data->amdtee = amdtee;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	pr_info("amd-tee driver initialization successful\n");
4998c2ecf20Sopenharmony_ci	return 0;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cierr_device_unregister:
5028c2ecf20Sopenharmony_ci	tee_device_unregister(amdtee->teedev);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cierr_free_pool:
5058c2ecf20Sopenharmony_ci	tee_shm_pool_free(pool);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cierr_kfree_amdtee:
5088c2ecf20Sopenharmony_ci	kfree(amdtee);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cierr_kfree_drv_data:
5118c2ecf20Sopenharmony_ci	kfree(drv_data);
5128c2ecf20Sopenharmony_ci	drv_data = NULL;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	pr_err("amd-tee driver initialization failed\n");
5158c2ecf20Sopenharmony_ci	return rc;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_cimodule_init(amdtee_driver_init);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic void __exit amdtee_driver_exit(void)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	struct amdtee *amdtee;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (!drv_data || !drv_data->amdtee)
5248c2ecf20Sopenharmony_ci		return;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	amdtee = drv_data->amdtee;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	tee_device_unregister(amdtee->teedev);
5298c2ecf20Sopenharmony_ci	tee_shm_pool_free(amdtee->pool);
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_cimodule_exit(amdtee_driver_exit);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
5348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AMD-TEE driver");
5358c2ecf20Sopenharmony_ciMODULE_VERSION("1.0");
5368c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL");
537