kernel-brax3-ubuntu-touch/drivers/misc/mediatek/trusted_mem/mtee_impl/mtee_ops.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

447 lines
12 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#define PR_FMT_HEADER_MUST_BE_INCLUDED_BEFORE_ALL_HDRS
#include "private/tmem_pr_fmt.h" PR_FMT_HEADER_MUST_BE_INCLUDED_BEFORE_ALL_HDRS
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/sizes.h>
#if IS_ENABLED(CONFIG_MTK_GZ_KREE)
#include <kree/system.h>
#include <kree/mem.h>
#include <kree/tz_mod.h>
#include <tz_cross/ta_mem.h>
#endif
#include "private/mld_helper.h"
#include "private/tmem_device.h"
#include "private/tmem_error.h"
#include "private/tmem_utils.h"
#include "private/tmem_dev_desc.h"
#include "public/mtee_regions.h"
/* clang-format off */
#include "mtee_impl/mtee_ops.h"
#include "mtee_impl/tmem_carveout_heap.h"
/* clang-format on */
#include "tee_impl/tee_invoke.h"
#include "memory_ssmr.h"
static const char mem_srv_name[] = "com.mediatek.geniezone.srv.mem";
#define LOCK_BY_CALLEE (0)
#if LOCK_BY_CALLEE
#define MTEE_SESSION_LOCK_INIT() mutex_init(&sess_data->lock)
#define MTEE_SESSION_LOCK() mutex_lock(&sess_data->lock)
#define MTEE_SESSION_UNLOCK() mutex_unlock(&sess_data->lock)
#else
#define MTEE_SESSION_LOCK_INIT()
#define MTEE_SESSION_LOCK()
#define MTEE_SESSION_UNLOCK()
#endif
struct MTEE_SESSION_DATA {
KREE_SESSION_HANDLE session_handle;
KREE_SECUREMEM_HANDLE append_mem_handle;
#if LOCK_BY_CALLEE
struct mutex lock;
#endif
};
static struct MTEE_SESSION_DATA *
mtee_create_session_data(enum TRUSTED_MEM_TYPE mem_type)
{
struct MTEE_SESSION_DATA *sess_data;
sess_data = mld_kmalloc(sizeof(struct MTEE_SESSION_DATA), GFP_KERNEL);
if (INVALID(sess_data)) {
pr_info("%s:%d %d:out of memory!\n", __func__, __LINE__,
mem_type);
return NULL;
}
memset(sess_data, 0x0, sizeof(struct MTEE_SESSION_DATA));
MTEE_SESSION_LOCK_INIT();
return sess_data;
}
static void mtee_destroy_session_data(struct MTEE_SESSION_DATA *sess_data)
{
if (VALID(sess_data))
mld_kfree(sess_data);
}
static int mtee_session_open(void **peer_data, void *dev_desc)
{
int ret = 0;
struct MTEE_SESSION_DATA *sess_data;
struct tmem_device_description *mtee_dev_desc =
(struct tmem_device_description *)dev_desc;
struct mtee_peer_ops_data *ops_data = &mtee_dev_desc->u_ops_data.mtee;
UNUSED(dev_desc);
sess_data = mtee_create_session_data(mtee_dev_desc->kern_tmem_type);
if (INVALID(sess_data)) {
pr_info("[%d] Create session data failed: out of memory!\n",
mtee_dev_desc->kern_tmem_type);
return TMEM_MTEE_CREATE_SESSION_FAILED;
}
MTEE_SESSION_LOCK();
if (unlikely(ops_data->service_name))
ret = KREE_CreateSession(ops_data->service_name,
&sess_data->session_handle);
else
ret = KREE_CreateSession(mem_srv_name,
&sess_data->session_handle);
if (ret != 0) {
pr_info("[%d] MTEE open session failed:%d (srv=%s)\n",
mtee_dev_desc->kern_tmem_type, ret,
(ops_data->service_name ? ops_data->service_name
: mem_srv_name));
MTEE_SESSION_UNLOCK();
return TMEM_MTEE_CREATE_SESSION_FAILED;
}
*peer_data = (void *)sess_data;
MTEE_SESSION_UNLOCK();
return TMEM_OK;
}
static int mtee_session_close(void *peer_data, void *dev_desc)
{
int ret;
struct MTEE_SESSION_DATA *sess_data =
(struct MTEE_SESSION_DATA *)peer_data;
struct tmem_device_description *mtee_dev_desc =
(struct tmem_device_description *)dev_desc;
struct mtee_peer_ops_data *ops_data = &mtee_dev_desc->u_ops_data.mtee;
UNUSED(ops_data);
MTEE_SESSION_LOCK();
ret = KREE_CloseSession(sess_data->session_handle);
if (ret != 0) {
pr_info("[%d] MTEE close session failed:%d\n",
mtee_dev_desc->kern_tmem_type, ret);
MTEE_SESSION_UNLOCK();
return TMEM_MTEE_CLOSE_SESSION_FAILED;
}
MTEE_SESSION_UNLOCK();
mtee_destroy_session_data(sess_data);
return TMEM_OK;
}
static int mtee_alloc(u32 alignment, u32 size, u32 *refcount, u64 *sec_handle,
u8 *owner, u32 id, u32 clean, void *peer_data,
void *dev_desc)
{
int ret;
struct MTEE_SESSION_DATA *sess_data =
(struct MTEE_SESSION_DATA *)peer_data;
struct tmem_device_description *mtee_dev_desc =
(struct tmem_device_description *)dev_desc;
struct mtee_peer_ops_data *ops_data = &mtee_dev_desc->u_ops_data.mtee;
if (is_ffa_enabled()) {
ret = tmem_ffa_region_alloc(mtee_dev_desc->mtee_chunks_id,
size, alignment, sec_handle);
if (*sec_handle == 0) {
pr_info("tmem_ffa_region_alloc, out of memory, ret=%d!\n", ret);
return -ENOMEM;
} else if (ret != 0) {
pr_info("[%d] tmem_ffa_region_alloc failed:%d\n",
mtee_dev_desc->kern_tmem_type, ret);
return TMEM_KPOOL_ALLOC_CHUNK_FAILED;
}
*refcount = 1;
} else {
UNUSED(ops_data);
MTEE_SESSION_LOCK();
if (clean) {
ret = KREE_ION_ZallocChunkmem(sess_data->session_handle,
sess_data->append_mem_handle,
(u32 *)sec_handle, alignment, size);
} else {
ret = KREE_ION_AllocChunkmem(sess_data->session_handle,
sess_data->append_mem_handle,
(u32 *)sec_handle, alignment, size);
}
if (*sec_handle == 0) {
pr_info("%s:%d out of memory, ret=%d!\n", __func__, __LINE__, ret);
MTEE_SESSION_UNLOCK();
return -ENOMEM;
} else if (ret != 0) {
pr_info("[%d] MTEE alloc chunk memory failed:%d\n",
mtee_dev_desc->kern_tmem_type, ret);
MTEE_SESSION_UNLOCK();
return TMEM_MTEE_ALLOC_CHUNK_FAILED;
}
*refcount = 1;
MTEE_SESSION_UNLOCK();
}
return TMEM_OK;
}
static int mtee_free(u64 sec_handle, u8 *owner, u32 id, void *peer_data,
void *dev_desc)
{
int ret;
struct MTEE_SESSION_DATA *sess_data =
(struct MTEE_SESSION_DATA *)peer_data;
struct tmem_device_description *mtee_dev_desc =
(struct tmem_device_description *)dev_desc;
struct mtee_peer_ops_data *ops_data = &mtee_dev_desc->u_ops_data.mtee;
if (is_ffa_enabled()) {
ret = tmem_ffa_region_free(mtee_dev_desc->mtee_chunks_id, sec_handle);
if (ret != 0) {
pr_info("[%d] tmem_ffa_region_free failed:%d\n",
mtee_dev_desc->kern_tmem_type, ret);
return TMEM_KPOOL_ALLOC_CHUNK_FAILED;
}
} else {
UNUSED(ops_data);
MTEE_SESSION_LOCK();
ret = KREE_ION_UnreferenceChunkmem(sess_data->session_handle,
(u32) sec_handle);
if (ret != 0) {
pr_info("[%d] MTEE free chunk memory failed:%d\n",
mtee_dev_desc->kern_tmem_type, ret);
MTEE_SESSION_UNLOCK();
return TMEM_MTEE_FREE_CHUNK_FAILED;
}
MTEE_SESSION_UNLOCK();
}
return TMEM_OK;
}
static int mtee_mem_reg_add(u64 pa, u32 size, void *peer_data, void *dev_desc)
{
int ret;
struct MTEE_SESSION_DATA *sess_data =
(struct MTEE_SESSION_DATA *)peer_data;
struct tmem_device_description *mtee_dev_desc =
(struct tmem_device_description *)dev_desc;
struct mtee_peer_ops_data *ops_data = &mtee_dev_desc->u_ops_data.mtee;
KREE_SHAREDMEM_PARAM mem_param;
mem_param.buffer = (void *)pa;
mem_param.size = size;
mem_param.mapAry = NULL;
mem_param.region_id = mtee_dev_desc->mtee_chunks_id;
UNUSED(ops_data);
MTEE_SESSION_LOCK();
ret = KREE_AppendSecureMultichunkmem(sess_data->session_handle,
&sess_data->append_mem_handle,
&mem_param);
if (ret != 0) {
pr_info("[%d] MTEE append reg mem failed:%d\n",
mtee_dev_desc->kern_tmem_type, ret);
MTEE_SESSION_UNLOCK();
return TMEM_MTEE_APPEND_MEMORY_FAILED;
}
pr_info("[%d] MTEE append reg mem PASS: PA=0x%lx, size=0x%lx\n",
mtee_dev_desc->kern_tmem_type, pa, size);
if (mtee_dev_desc->notify_remote && mtee_dev_desc->notify_remote_fn) {
ret = mtee_dev_desc->notify_remote_fn(
pa, size, mtee_dev_desc->tee_smem_type);
if (ret != 0) {
pr_info("[%d] MTEE notify reg mem add to TEE failed:%d\n",
mtee_dev_desc->tee_smem_type, ret);
// MTEE_SESSION_UNLOCK();
// return TMEM_MTEE_NOTIFY_MEM_ADD_CFG_TO_TEE_FAILED;
}
}
if (is_ffa_enabled()) {
ret = tmem_carveout_create(mtee_dev_desc->mtee_chunks_id, pa, size);
if (ret != 0) {
pr_info("[%d] tmem_carveout_create failed:%d\n",
mtee_dev_desc->kern_tmem_type, ret);
MTEE_SESSION_UNLOCK();
return TMEM_KPOOL_APPEND_MEMORY_FAILED;
}
pr_info("[%d] tmem_carveout_heap[%d] created PASS: PA=0x%lx, size=0x%lx\n",
mtee_dev_desc->kern_tmem_type, mtee_dev_desc->mtee_chunks_id,
pa, size);
}
MTEE_SESSION_UNLOCK();
return TMEM_OK;
}
static int mtee_mem_reg_remove(void *peer_data, void *dev_desc)
{
int ret;
struct MTEE_SESSION_DATA *sess_data =
(struct MTEE_SESSION_DATA *)peer_data;
struct tmem_device_description *mtee_dev_desc =
(struct tmem_device_description *)dev_desc;
struct mtee_peer_ops_data *ops_data = &mtee_dev_desc->u_ops_data.mtee;
UNUSED(ops_data);
MTEE_SESSION_LOCK();
ret = KREE_ReleaseSecureMultichunkmem(sess_data->session_handle,
sess_data->append_mem_handle);
if (ret != 0) {
pr_info("[%d] MTEE release reg mem failed:%d\n",
mtee_dev_desc->kern_tmem_type, ret);
MTEE_SESSION_UNLOCK();
return TMEM_MTEE_RELEASE_MEMORY_FAILED;
}
if (mtee_dev_desc->notify_remote && mtee_dev_desc->notify_remote_fn) {
ret = mtee_dev_desc->notify_remote_fn(
0x0ULL, 0x0, mtee_dev_desc->tee_smem_type);
if (ret != 0) {
pr_info("[%d] MTEE notify reg mem remove to TEE failed:%d\n",
mtee_dev_desc->tee_smem_type, ret);
// MTEE_SESSION_UNLOCK();
// return TMEM_MTEE_NOTIFY_MEM_REMOVE_CFG_TO_TEE_FAILED;
}
}
if (is_ffa_enabled()) {
ret = tmem_carveout_destroy(mtee_dev_desc->mtee_chunks_id);
if (ret != 0) {
pr_info("[%d] tmem_carveout_destroy failed:%d\n",
mtee_dev_desc->kern_tmem_type, ret);
MTEE_SESSION_UNLOCK();
return TMEM_KPOOL_APPEND_MEMORY_FAILED;
}
pr_info("[%d] tmem_carveout_heap[%d] destroy PASS\n",
mtee_dev_desc->kern_tmem_type, mtee_dev_desc->mtee_chunks_id);
}
MTEE_SESSION_UNLOCK();
return TMEM_OK;
}
static int mtee_drv_execute(KREE_SESSION_HANDLE session_handle, u32 cmd,
struct mtee_driver_params *drv_params)
{
union MTEEC_PARAM svc_call_param[4];
svc_call_param[0].mem.buffer = drv_params;
svc_call_param[0].mem.size = sizeof(struct mtee_driver_params);
return KREE_TeeServiceCall(session_handle, cmd,
TZ_ParamTypes1(TZPT_MEM_INOUT),
svc_call_param);
}
static int mtee_mem_srv_execute(KREE_SESSION_HANDLE session_handle, u32 cmd,
struct mtee_driver_params *drv_params)
{
int ret = TMEM_OK;
switch (cmd) {
case TZCMD_MEM_CONFIG_CHUNKMEM_INFO_ION:
ret = KREE_ConfigSecureMultiChunkMemInfo(
session_handle, drv_params->param0, drv_params->param1,
drv_params->param2);
break;
default:
pr_info("%s:%d operation is not implemented yet!\n", __func__,
__LINE__);
ret = TMEM_OPERATION_NOT_IMPLEMENTED;
break;
}
return ret;
}
static int mtee_invoke_command(struct trusted_driver_cmd_params *invoke_params,
void *peer_data, void *dev_desc)
{
int ret = TMEM_OK;
struct MTEE_SESSION_DATA *sess_data =
(struct MTEE_SESSION_DATA *)peer_data;
struct tmem_device_description *mtee_dev_desc =
(struct tmem_device_description *)dev_desc;
struct mtee_peer_ops_data *ops_data = &mtee_dev_desc->u_ops_data.mtee;
struct mtee_driver_params drv_params = {0};
if (INVALID(invoke_params))
return TMEM_PARAMETER_ERROR;
drv_params.param0 = invoke_params->param0;
drv_params.param1 = invoke_params->param1;
drv_params.param2 = invoke_params->param2;
drv_params.param3 = invoke_params->param3;
if (unlikely(ops_data->service_name)) {
ret = mtee_drv_execute(sess_data->session_handle,
invoke_params->cmd, &drv_params);
if (ret) {
pr_info("%s:%d invoke failed! cmd:%d, ret:0x%x\n",
__func__, __LINE__, invoke_params->cmd, ret);
return TMEM_MTEE_INVOKE_COMMAND_FAILED;
}
} else {
ret = mtee_mem_srv_execute(sess_data->session_handle,
invoke_params->cmd, &drv_params);
if (ret) {
pr_info("%s:%d invoke failed! cmd:%d, ret:0x%x\n",
__func__, __LINE__, invoke_params->cmd, ret);
return TMEM_MTEE_INVOKE_COMMAND_FAILED;
}
}
invoke_params->param0 = drv_params.param0;
invoke_params->param1 = drv_params.param1;
invoke_params->param2 = drv_params.param2;
invoke_params->param3 = drv_params.param3;
return TMEM_OK;
}
static struct trusted_driver_operations mtee_peer_ops = {
.session_open = mtee_session_open,
.session_close = mtee_session_close,
.memory_alloc = mtee_alloc,
.memory_free = mtee_free,
.memory_grant = mtee_mem_reg_add,
.memory_reclaim = mtee_mem_reg_remove,
.invoke_cmd = mtee_invoke_command,
};
void get_mtee_peer_ops(struct trusted_driver_operations **ops)
{
pr_info("MTEE_OPS set\n");
*ops = &mtee_peer_ops;
}