6db4831e98
Android 14
1148 lines
26 KiB
C
1148 lines
26 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
/*
|
|
* GenieZone (hypervisor-based seucrity platform) enables hardware protected
|
|
* and isolated security execution environment, includes
|
|
* 1. GZ hypervisor
|
|
* 2. Hypervisor-TEE OS (built-in Trusty OS)
|
|
* 3. Drivers (ex: debug, communication and interrupt) for GZ and
|
|
* hypervisor-TEE OS
|
|
* 4. GZ and hypervisor-TEE and GZ framework (supporting multiple TEE
|
|
* ecosystem, ex: M-TEE, Trusty, GlobalPlatform, ...)
|
|
*/
|
|
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/pm_wakeup.h>
|
|
#include <gz-trusty/smcall.h>
|
|
#include <gz-trusty/trusty.h>
|
|
#include <gz-trusty/trusty_ipc.h>
|
|
#include <kree/mem.h>
|
|
#include <kree/system.h>
|
|
#include <kree/tz_mod.h>
|
|
#include <tz_cross/ta_system.h>
|
|
#include <tz_cross/ta_test.h>
|
|
#include <tz_cross/trustzone.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include "gz_main.h"
|
|
#include "mtee_ut/gz_ut.h"
|
|
#include "mtee_ut/gz_shmem_ut.h"
|
|
#include "mtee_ut/gz_chmem_ut.h"
|
|
#include "mtee_ut/gz_vreg_ut.h"
|
|
#include "unittest.h"
|
|
|
|
#define enable_code 0 /*replace #if 0*/
|
|
|
|
#if enable_code
|
|
/*devapc related function is not supported in Kernel-4.19*/
|
|
#if IS_ENABLED(CONFIG_MTK_DEVAPC) && !IS_ENABLED(CONFIG_DEVAPC_LEGACY)
|
|
#include <mt-plat/devapc_public.h>
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/* FIXME: MTK_PPM_SUPPORT is disabled temporarily */
|
|
#ifdef MTK_PPM_SUPPORT
|
|
#if IS_ENABLED(CONFIG_MACH_MT6758)
|
|
#include "legacy_controller.h"
|
|
#else
|
|
#include "mtk_ppm_platform.h"
|
|
#endif
|
|
#endif
|
|
|
|
//#define KREE_DEBUG(fmt...) pr_debug("[KREE]" fmt)
|
|
#define KREE_DEBUG(fmt...) pr_info("[KREE]" fmt)
|
|
#define KREE_INFO(fmt...) pr_info("[KREE]" fmt)
|
|
#define KREE_ERR(fmt...) pr_info("[KREE][ERR]" fmt)
|
|
|
|
static const struct file_operations fops = {.owner = THIS_MODULE,
|
|
.open = gz_dev_open,
|
|
.release = gz_dev_release,
|
|
.unlocked_ioctl = gz_ioctl,
|
|
#if IS_ENABLED(CONFIG_COMPAT)
|
|
.compat_ioctl = gz_compat_ioctl,
|
|
#endif
|
|
};
|
|
|
|
static struct miscdevice gz_device = {.minor = MISC_DYNAMIC_MINOR,
|
|
.name = "gz_kree",
|
|
.fops = &fops
|
|
};
|
|
|
|
static int get_gz_version(void *args);
|
|
|
|
static const char *cases =
|
|
" 0: GZ Version\n 1: TIPC\n 2.General Function\n"
|
|
" 3: Shared Memory\n 4: GZ abort 5: Chunk Memory\n"
|
|
" C: Secure Storage\n";
|
|
|
|
/************* sysfs operations ****************/
|
|
static ssize_t gz_test_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
return scnprintf(buf, PAGE_SIZE, "%s\n", cases);
|
|
}
|
|
|
|
static ssize_t gz_test_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf,
|
|
size_t n)
|
|
{
|
|
char tmp[50];
|
|
char c;
|
|
struct task_struct *th;
|
|
|
|
if (n <= 0 || n > 50) {
|
|
KREE_DEBUG("err: n > 50\n");
|
|
return n;
|
|
}
|
|
|
|
strncpy(tmp, buf, 1);
|
|
tmp[n - 1] = '\0';
|
|
c = tmp[0];
|
|
|
|
KREE_DEBUG("GZ KREE test: %c\n", c);
|
|
switch (c) {
|
|
case '0':
|
|
KREE_DEBUG("get gz version\n");
|
|
th = kthread_run(get_gz_version, NULL, "GZ version");
|
|
break;
|
|
case '1':
|
|
KREE_DEBUG("test simple ut\n");
|
|
th = kthread_run(simple_ut, NULL, "Simple test");
|
|
break;
|
|
case '2':
|
|
KREE_DEBUG("test_gz_syscall\n"); /*ReeServiceCall*/
|
|
th = kthread_run(test_gz_syscall, NULL, "test_gz_syscall");
|
|
break;
|
|
case '3':
|
|
KREE_DEBUG("gz_test_shm\n");
|
|
th = kthread_run(gz_test_shm, NULL, "test_shm");
|
|
break;
|
|
case '4':
|
|
KREE_DEBUG("gz_test_chm\n");
|
|
th = kthread_run(gz_test_chm, NULL, "test_chm");
|
|
break;
|
|
case '5':
|
|
KREE_DEBUG("gz_test_vreg\n");
|
|
th = kthread_run(gz_test_vreg, NULL, "test_vreg");
|
|
break;
|
|
default:
|
|
KREE_DEBUG("err: unknown test case\n");
|
|
|
|
break;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
|
|
DEVICE_ATTR_RW(gz_test);
|
|
|
|
|
|
static int create_files(void)
|
|
{
|
|
int res;
|
|
|
|
res = misc_register(&gz_device);
|
|
|
|
if (res != 0) {
|
|
KREE_DEBUG("ERR: misc register failed.");
|
|
return res;
|
|
}
|
|
res = device_create_file(gz_device.this_device, &dev_attr_gz_test);
|
|
if (res != 0) {
|
|
KREE_DEBUG("ERR: create sysfs do_info failed.");
|
|
return res;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*********** test case implementations *************/
|
|
static const char echo_srv_name[] = "com.mediatek.geniezone.srv.echo";
|
|
#define APP_NAME2 "com.mediatek.gz.srv.sync-ut"
|
|
|
|
static int get_gz_version(void *args)
|
|
{
|
|
int ret;
|
|
int i;
|
|
int version_str_len;
|
|
char *version_str;
|
|
struct device *trusty_dev;
|
|
|
|
if (IS_ERR_OR_NULL(tz_system_dev)) {
|
|
KREE_ERR("GZ kree is not initialized\n");
|
|
return TZ_RESULT_ERROR_NO_DATA;
|
|
}
|
|
|
|
trusty_dev = tz_system_dev->dev.parent;
|
|
|
|
ret = trusty_fast_call32(trusty_dev,
|
|
MTEE_SMCNR(SMCF_FC_GET_VERSION_STR, trusty_dev),
|
|
-1, 0, 0);
|
|
if (ret <= 0) {
|
|
KREE_ERR("failed to get version: %d\n", ret);
|
|
return TZ_RESULT_ERROR_GENERIC;
|
|
}
|
|
|
|
version_str_len = ret;
|
|
|
|
version_str = kmalloc(version_str_len + 1, GFP_KERNEL);
|
|
if (!version_str)
|
|
return TZ_RESULT_ERROR_OUT_OF_MEMORY;
|
|
|
|
for (i = 0; i < version_str_len; i++) {
|
|
ret = trusty_fast_call32(trusty_dev,
|
|
MTEE_SMCNR(SMCF_FC_GET_VERSION_STR, trusty_dev),
|
|
i, 0, 0);
|
|
if (ret < 0)
|
|
goto err_get_char;
|
|
version_str[i] = ret;
|
|
}
|
|
version_str[i] = '\0';
|
|
|
|
dev_info(gz_device.this_device, "GZ version: %s\n", version_str);
|
|
KREE_DEBUG("GZ version is : %s.....\n", version_str);
|
|
|
|
err_get_char:
|
|
kfree(version_str);
|
|
version_str = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/************* kernel module file ops (dummy) ****************/
|
|
struct UREE_SHAREDMEM_PARAM_US {
|
|
uint64_t buffer; /* FIXME: userspace void* is 32-bit */
|
|
uint32_t size;
|
|
uint32_t region_id;
|
|
};
|
|
|
|
struct user_shm_param {
|
|
uint32_t session;
|
|
uint32_t shm_handle;
|
|
struct UREE_SHAREDMEM_PARAM_US param;
|
|
};
|
|
|
|
/************ to close session while driver is cancelled *************/
|
|
struct session_info {
|
|
int handle_num; /*num of session handles */
|
|
KREE_SESSION_HANDLE *handles; /*session handles */
|
|
struct mutex mux;
|
|
};
|
|
|
|
#define queue_SessionNum 32
|
|
#define non_SessionID (0xffffffff)
|
|
|
|
static int _init_session_info(struct file *fp)
|
|
{
|
|
struct session_info *info;
|
|
int i;
|
|
|
|
info = kmalloc(sizeof(struct session_info), GFP_KERNEL);
|
|
if (!info)
|
|
return TZ_RESULT_ERROR_GENERIC;
|
|
|
|
info->handles = kmalloc_array(queue_SessionNum,
|
|
sizeof(KREE_SESSION_HANDLE), GFP_KERNEL);
|
|
if (!info->handles) {
|
|
kfree(info);
|
|
KREE_ERR("info->handles malloc fail. stop!\n");
|
|
return TZ_RESULT_ERROR_GENERIC;
|
|
}
|
|
info->handle_num = queue_SessionNum;
|
|
for (i = 0; i < info->handle_num; i++)
|
|
info->handles[i] = non_SessionID;
|
|
|
|
mutex_init(&info->mux);
|
|
fp->private_data = info;
|
|
return TZ_RESULT_SUCCESS;
|
|
}
|
|
|
|
static int _free_session_info(struct file *fp)
|
|
{
|
|
struct session_info *info;
|
|
int i, num;
|
|
|
|
KREE_DEBUG("====> [%d] [start] %s is running.\n", __LINE__, __func__);
|
|
|
|
info = (struct session_info *)fp->private_data;
|
|
|
|
/* lock */
|
|
mutex_lock(&info->mux);
|
|
|
|
num = info->handle_num;
|
|
for (i = 0; i < num; i++) {
|
|
|
|
if (info->handles[i] == non_SessionID)
|
|
continue;
|
|
KREE_CloseSession(info->handles[i]);
|
|
KREE_DEBUG("=====> session handle[%d] =%d is closed.\n", i,
|
|
info->handles[i]);
|
|
|
|
info->handles[i] = (KREE_SESSION_HANDLE) non_SessionID;
|
|
}
|
|
|
|
/* unlock */
|
|
fp->private_data = 0;
|
|
mutex_unlock(&info->mux);
|
|
|
|
kfree(info->handles);
|
|
kfree(info);
|
|
|
|
KREE_DEBUG("====> [%d] end of %s().\n", __LINE__, __func__);
|
|
|
|
return TZ_RESULT_SUCCESS;
|
|
}
|
|
|
|
|
|
static int _register_session_info(struct file *fp, KREE_SESSION_HANDLE handle)
|
|
{
|
|
struct session_info *info;
|
|
int i, num, nspace, ret = -1;
|
|
void *ptr;
|
|
|
|
KREE_DEBUG("[%s][%d] in_handle=0x%x\n", __func__, __LINE__, handle);
|
|
if (handle < 0)
|
|
return TZ_RESULT_ERROR_BAD_PARAMETERS;
|
|
|
|
info = (struct session_info *)fp->private_data;
|
|
|
|
/* lock */
|
|
mutex_lock(&info->mux);
|
|
|
|
/* find empty space. */
|
|
num = info->handle_num;
|
|
for (i = 0; i < num; i++) {
|
|
if (info->handles[i] == non_SessionID) {
|
|
ret = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Try grow the space */
|
|
if (ret == -1) {
|
|
|
|
nspace = num * 2;
|
|
ptr = krealloc(info->handles,
|
|
nspace * sizeof(KREE_SESSION_HANDLE),
|
|
GFP_KERNEL);
|
|
if (!ptr) {
|
|
mutex_unlock(&info->mux);
|
|
return TZ_RESULT_ERROR_GENERIC;
|
|
}
|
|
|
|
ret = num;
|
|
info->handle_num = nspace;
|
|
info->handles = (int *)ptr;
|
|
memset(&info->handles[num], (KREE_SESSION_HANDLE) non_SessionID,
|
|
(nspace - num) * sizeof(KREE_SESSION_HANDLE));
|
|
}
|
|
|
|
if (ret >= 0)
|
|
info->handles[ret] = handle;
|
|
|
|
KREE_DEBUG("[%s][%d] reg. session handle[%d]=0x%x\n",
|
|
__func__, __LINE__, ret, handle);
|
|
|
|
/* unlock */
|
|
mutex_unlock(&info->mux);
|
|
|
|
return TZ_RESULT_SUCCESS;
|
|
}
|
|
|
|
|
|
static int _unregister_session_info(struct file *fp,
|
|
KREE_SESSION_HANDLE in_handleID)
|
|
{
|
|
struct session_info *info;
|
|
int ret = TZ_RESULT_ERROR_GENERIC;
|
|
int i;
|
|
|
|
KREE_DEBUG("[%s][%d] in_handleID=0x%x\n", __func__, __LINE__,
|
|
in_handleID);
|
|
if (in_handleID < 0)
|
|
return TZ_RESULT_ERROR_BAD_PARAMETERS;
|
|
|
|
info = (struct session_info *)fp->private_data;
|
|
|
|
/* lock */
|
|
mutex_lock(&info->mux);
|
|
|
|
for (i = 0; i < info->handle_num; i++) {
|
|
if (info->handles[i] == in_handleID) {
|
|
info->handles[i] = (KREE_SESSION_HANDLE) non_SessionID;
|
|
KREE_DEBUG
|
|
("[%s][%d]session handle[%d]=0x%x is unreg.\n",
|
|
__func__, __LINE__, i, in_handleID);
|
|
ret = TZ_RESULT_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
/* unlock */
|
|
mutex_unlock(&info->mux);
|
|
KREE_DEBUG("[%d][%s] done. ret=%d\n", __LINE__, __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
int mtee_sdsp_enable(u32 on)
|
|
{
|
|
if (IS_ERR_OR_NULL(tz_system_dev)) {
|
|
KREE_ERR("GZ kree is not initialized\n");
|
|
return TZ_RESULT_ERROR_NO_DATA;
|
|
}
|
|
|
|
return trusty_std_call32(tz_system_dev->dev.parent,
|
|
MTEE_SMCNR(MT_SMCF_SC_VPU, tz_system_dev->dev.parent),
|
|
on, 0, 0);
|
|
}
|
|
|
|
int gz_get_cpuinfo_thread(void *data)
|
|
{
|
|
#ifdef MTK_PPM_SUPPORT
|
|
struct cpufreq_policy curr_policy;
|
|
#endif
|
|
|
|
if (platform_driver_register(&tz_system_driver))
|
|
KREE_ERR("%s driver register fail\n", __func__);
|
|
|
|
KREE_DEBUG("%s driver register done\n", __func__);
|
|
|
|
#if IS_ENABLED(CONFIG_MACH_MT6758)
|
|
msleep(3000);
|
|
#else
|
|
msleep(1000);
|
|
#endif
|
|
|
|
#ifdef MTK_PPM_SUPPORT
|
|
cpufreq_get_policy(&curr_policy, 0);
|
|
cpus_cluster_freq[0].max_freq = curr_policy.cpuinfo.max_freq;
|
|
cpus_cluster_freq[0].min_freq = curr_policy.cpuinfo.min_freq;
|
|
cpufreq_get_policy(&curr_policy, 4);
|
|
cpus_cluster_freq[1].max_freq = curr_policy.cpuinfo.max_freq;
|
|
cpus_cluster_freq[1].min_freq = curr_policy.cpuinfo.min_freq;
|
|
KREE_INFO("%s, cluster [0]=%u-%u, [1]=%u-%u\n", __func__,
|
|
cpus_cluster_freq[0].max_freq, cpus_cluster_freq[0].min_freq,
|
|
cpus_cluster_freq[1].max_freq, cpus_cluster_freq[1].min_freq);
|
|
#endif
|
|
|
|
perf_boost_cnt = 0;
|
|
mutex_init(&perf_boost_lock);
|
|
|
|
#if IS_ENABLED(CONFIG_PM_SLEEP)
|
|
/*kernel-4.14*/
|
|
//wakeup_source_init(&TeeServiceCall_wake_lock, "KREE_TeeServiceCall");
|
|
|
|
/*kernel-4.19*/
|
|
if (IS_ERR_OR_NULL(tz_system_dev))
|
|
return TZ_RESULT_ERROR_GENERIC;
|
|
|
|
TeeServiceCall_wake_lock =
|
|
wakeup_source_register(
|
|
tz_system_dev->dev.parent, "KREE_TeeServiceCall");
|
|
if (!TeeServiceCall_wake_lock) {
|
|
KREE_ERR("TeeServiceCall_wake_lock null\n");
|
|
return TZ_RESULT_ERROR_GENERIC;
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gz_dev_open(struct inode *inode, struct file *filp)
|
|
{
|
|
return _init_session_info(filp);
|
|
}
|
|
|
|
static int gz_dev_release(struct inode *inode, struct file *filp)
|
|
{
|
|
return _free_session_info(filp);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* DEV DRIVER IOCTL
|
|
* Ported from trustzone driver
|
|
**************************************************************************/
|
|
static long tz_client_open_session(struct file *filep, void __user *arg)
|
|
{
|
|
struct kree_session_cmd_param param;
|
|
unsigned long cret;
|
|
char uuid[MAX_UUID_LEN];
|
|
long len;
|
|
TZ_RESULT ret;
|
|
KREE_SESSION_HANDLE handle = 0;
|
|
|
|
cret = copy_from_user(¶m, arg, sizeof(param));
|
|
if (cret)
|
|
return -EFAULT;
|
|
|
|
/* Check if can we access UUID string. 10 for min uuid len. */
|
|
if (!access_ok(VERIFY_READ, (void *)param.data, 10))
|
|
return -EFAULT;
|
|
|
|
KREE_DEBUG("%s: uuid addr = 0x%llx\n", __func__, param.data);
|
|
len = strncpy_from_user(uuid, (void *)param.data,
|
|
sizeof(uuid));
|
|
if (len <= 0)
|
|
return -EFAULT;
|
|
|
|
uuid[sizeof(uuid) - 1] = 0;
|
|
ret = KREE_CreateSession(uuid, &handle);
|
|
if (ret != TZ_RESULT_SUCCESS) {
|
|
KREE_DEBUG("%s: kree crt session fail(0x%x)\n", __func__, ret);
|
|
goto tz_client_open_session_end;
|
|
}
|
|
|
|
KREE_DEBUG("===> %s: handle =%d\n", __func__, handle);
|
|
|
|
_register_session_info(filep, handle);
|
|
|
|
tz_client_open_session_end:
|
|
param.ret = ret;
|
|
param.handle = handle;
|
|
cret = copy_to_user(arg, ¶m, sizeof(param));
|
|
if (cret)
|
|
return cret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static long tz_client_close_session(struct file *filep, void __user *arg)
|
|
{
|
|
struct kree_session_cmd_param param;
|
|
unsigned long cret;
|
|
TZ_RESULT ret;
|
|
|
|
cret = copy_from_user(¶m, arg, sizeof(param));
|
|
if (cret)
|
|
return -EFAULT;
|
|
|
|
if (param.handle < 0 || param.handle >= KREE_SESSION_HANDLE_MAX_SIZE)
|
|
return TZ_RESULT_ERROR_INVALID_HANDLE;
|
|
|
|
ret = KREE_CloseSession(param.handle);
|
|
if (ret != TZ_RESULT_SUCCESS) {
|
|
KREE_DEBUG("%s: fail(0x%x)\n", __func__, ret);
|
|
goto _tz_client_close_session_end;
|
|
}
|
|
|
|
_unregister_session_info(filep, param.handle);
|
|
|
|
_tz_client_close_session_end:
|
|
param.ret = ret;
|
|
cret = copy_to_user(arg, ¶m, sizeof(param));
|
|
if (cret)
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static long tz_client_tee_service(struct file *file, void __user *arg,
|
|
unsigned int compat)
|
|
{
|
|
struct kree_tee_service_cmd_param cparam = { 0 };
|
|
unsigned long cret;
|
|
uint32_t tmpTypes;
|
|
union MTEEC_PARAM param[4], oparam[4];
|
|
uint i;
|
|
TZ_RESULT ret;
|
|
KREE_SESSION_HANDLE handle;
|
|
void __user *ubuf;
|
|
uint32_t ubuf_sz;
|
|
|
|
cret = copy_from_user(&cparam, arg, sizeof(cparam));
|
|
if (cret) {
|
|
KREE_ERR("%s: copy_from_user(msg) failed\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (cparam.paramTypes != TZPT_NONE || cparam.param) {
|
|
if (!access_ok(VERIFY_READ, (void *)cparam.param,
|
|
sizeof(oparam)))
|
|
return -EFAULT;
|
|
|
|
cret = copy_from_user(oparam,
|
|
(void *)(unsigned long)cparam.param,
|
|
sizeof(oparam));
|
|
if (cret) {
|
|
KREE_ERR("%s: copy_from_user(param) failed\n",
|
|
__func__);
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
|
|
handle = (KREE_SESSION_HANDLE) cparam.handle;
|
|
KREE_DEBUG("%s: session handle = %u\n", __func__, handle);
|
|
|
|
/* Parameter processing. */
|
|
memset(param, 0, sizeof(param));
|
|
tmpTypes = cparam.paramTypes;
|
|
for (i = 0; tmpTypes; i++) {
|
|
enum TZ_PARAM_TYPES type = tmpTypes & 0xff;
|
|
|
|
tmpTypes >>= 8;
|
|
switch (type) {
|
|
case TZPT_VALUE_INPUT:
|
|
case TZPT_VALUE_INOUT:
|
|
param[i] = oparam[i];
|
|
break;
|
|
|
|
case TZPT_VALUE_OUTPUT:
|
|
case TZPT_NONE:
|
|
break;
|
|
|
|
case TZPT_MEM_INPUT:
|
|
case TZPT_MEM_OUTPUT:
|
|
case TZPT_MEM_INOUT:
|
|
#if IS_ENABLED(CONFIG_COMPAT)
|
|
if (compat) {
|
|
ubuf = compat_ptr(oparam[i].mem32.buffer);
|
|
ubuf_sz = oparam[i].mem32.size;
|
|
} else
|
|
#endif
|
|
{
|
|
ubuf = oparam[i].mem.buffer;
|
|
ubuf_sz = oparam[i].mem.size;
|
|
}
|
|
|
|
KREE_DEBUG("%s: ubuf = %p, ubuf_sz = %u\n", __func__,
|
|
ubuf, ubuf_sz);
|
|
|
|
if (type != TZPT_MEM_OUTPUT) {
|
|
if (!access_ok(VERIFY_READ, ubuf, ubuf_sz)) {
|
|
KREE_ERR("%s: cannnot read mem\n",
|
|
__func__);
|
|
cret = -EFAULT;
|
|
goto error;
|
|
}
|
|
}
|
|
if (type != TZPT_MEM_INPUT) {
|
|
if (!access_ok(VERIFY_WRITE, ubuf, ubuf_sz)) {
|
|
KREE_ERR("%s: cannnot write mem\n",
|
|
__func__);
|
|
cret = -EFAULT;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
if (ubuf_sz > GP_MEM_MAX_LEN) {
|
|
KREE_ERR("%s: ubuf_sz larger than max(%d)\n",
|
|
__func__, GP_MEM_MAX_LEN);
|
|
cret = -ENOMEM;
|
|
goto error;
|
|
}
|
|
|
|
param[i].mem.size = ubuf_sz;
|
|
param[i].mem.buffer =
|
|
kmalloc(param[i].mem.size, GFP_KERNEL);
|
|
if (!param[i].mem.buffer) {
|
|
KREE_ERR("%s: kmalloc failed\n", __func__);
|
|
cret = -ENOMEM;
|
|
goto error;
|
|
}
|
|
|
|
if (type != TZPT_MEM_OUTPUT) {
|
|
cret = copy_from_user(param[i].mem.buffer, ubuf,
|
|
param[i].mem.size);
|
|
if (cret) {
|
|
KREE_ERR("%s: copy_from_user failed\n",
|
|
__func__);
|
|
cret = -EFAULT;
|
|
goto error;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TZPT_MEMREF_INPUT:
|
|
case TZPT_MEMREF_OUTPUT:
|
|
case TZPT_MEMREF_INOUT:
|
|
param[i] = oparam[i];
|
|
break;
|
|
|
|
default:
|
|
ret = TZ_RESULT_ERROR_BAD_FORMAT;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
ret = KREE_TeeServiceCallPlus(handle, cparam.command, cparam.paramTypes,
|
|
param, cparam.cpumask);
|
|
|
|
cparam.ret = ret;
|
|
tmpTypes = cparam.paramTypes;
|
|
for (i = 0; tmpTypes; i++) {
|
|
enum TZ_PARAM_TYPES type = tmpTypes & 0xff;
|
|
|
|
tmpTypes >>= 8;
|
|
switch (type) {
|
|
case TZPT_VALUE_OUTPUT:
|
|
case TZPT_VALUE_INOUT:
|
|
oparam[i] = param[i];
|
|
break;
|
|
|
|
default:
|
|
case TZPT_MEMREF_INPUT:
|
|
case TZPT_MEMREF_OUTPUT:
|
|
case TZPT_MEMREF_INOUT:
|
|
case TZPT_VALUE_INPUT:
|
|
case TZPT_NONE:
|
|
break;
|
|
|
|
case TZPT_MEM_INPUT:
|
|
case TZPT_MEM_OUTPUT:
|
|
case TZPT_MEM_INOUT:
|
|
#if IS_ENABLED(CONFIG_COMPAT)
|
|
if (compat)
|
|
ubuf = compat_ptr(oparam[i].mem32.buffer);
|
|
else
|
|
#endif
|
|
ubuf = oparam[i].mem.buffer;
|
|
|
|
if (type != TZPT_MEM_INPUT) {
|
|
cret = copy_to_user(ubuf, param[i].mem.buffer,
|
|
param[i].mem.size);
|
|
if (cret) {
|
|
cret = -EFAULT;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
kfree(param[i].mem.buffer);
|
|
param[i].mem.buffer = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Copy data back. */
|
|
if (cparam.paramTypes != TZPT_NONE) {
|
|
cret = copy_to_user((void *)(unsigned long)cparam.param, oparam,
|
|
sizeof(oparam));
|
|
if (cret) {
|
|
KREE_ERR("%s: copy_to_user(param) failed\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
|
|
|
|
cret = copy_to_user(arg, &cparam, sizeof(cparam));
|
|
if (cret) {
|
|
KREE_ERR("%s: copy_to_user(msg) failed\n", __func__);
|
|
return -EFAULT;
|
|
}
|
|
return 0;
|
|
|
|
error:
|
|
tmpTypes = cparam.paramTypes;
|
|
for (i = 0; tmpTypes; i++) {
|
|
enum TZ_PARAM_TYPES type = tmpTypes & 0xff;
|
|
|
|
tmpTypes >>= 8;
|
|
switch (type) {
|
|
case TZPT_MEM_INPUT:
|
|
case TZPT_MEM_OUTPUT:
|
|
case TZPT_MEM_INOUT:
|
|
kfree(param[i].mem.buffer);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return cret;
|
|
}
|
|
|
|
#define SZ_32KB (32*1024)
|
|
static TZ_RESULT _reg_shmem_from_userspace(
|
|
uint32_t session, uint32_t region_id,
|
|
struct user_shm_param *shm_data,
|
|
uint32_t *shm_handle)
|
|
{
|
|
unsigned long cret;
|
|
struct page **page;
|
|
int i;
|
|
uint64_t map_p_sz, pin_sz;
|
|
unsigned long *pfns;
|
|
struct page **delpages;
|
|
|
|
struct MTIOMMU_PIN_RANGE_T *pin = NULL;
|
|
uint64_t *map_p = NULL;
|
|
int numOfPA = 0;
|
|
KREE_SHAREDMEM_PARAM shm_param = {0};
|
|
|
|
KREE_DEBUG("[%s][%d] runs.\n", __func__, __LINE__);
|
|
if (((*shm_data).param.size <= 0) || (!(*shm_data).param.buffer)) {
|
|
KREE_DEBUG("[%s] [fail] size <= 0 OR !buffer\n", __func__);
|
|
return TZ_RESULT_ERROR_BAD_PARAMETERS;
|
|
}
|
|
|
|
KREE_DEBUG("session: %u, shm_handle: %u, size: %u, buffer: 0x%llx\n",
|
|
(*shm_data).session, (*shm_data).shm_handle,
|
|
(*shm_data).param.size, (*shm_data).param.buffer);
|
|
|
|
/*init value */
|
|
pin = NULL;
|
|
map_p = NULL;
|
|
|
|
shm_param.buffer = NULL;
|
|
shm_param.size = 0;
|
|
shm_param.mapAry = NULL;
|
|
shm_param.region_id = region_id;
|
|
*shm_handle = 0;
|
|
|
|
cret = TZ_RESULT_SUCCESS;
|
|
/*
|
|
* map pages
|
|
*/
|
|
/*
|
|
* 1. get user pages
|
|
* note: 'pin' resource need to keep for unregister.
|
|
* It will be freed after unregisted.
|
|
*/
|
|
/*check alloc size if <= 32KB*/
|
|
pin_sz = sizeof(struct MTIOMMU_PIN_RANGE_T);
|
|
if (pin_sz >= SZ_32KB) {
|
|
KREE_INFO("[%s]alloc pin sz(0x%llx)>=32KB\n",
|
|
__func__, pin_sz);
|
|
//return TZ_RESULT_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
/*pin = kzalloc(sizeof(struct MTIOMMU_PIN_RANGE_T), GFP_KERNEL);*/
|
|
/*pin = vmalloc(pin_sz);*/
|
|
pin = kvmalloc(pin_sz, GFP_KERNEL);
|
|
if (!pin) {
|
|
KREE_DEBUG("[%s]zalloc fail: pin is null.\n", __func__);
|
|
cret = TZ_RESULT_ERROR_OUT_OF_MEMORY;
|
|
goto us_map_fail;
|
|
}
|
|
|
|
pin->pageArray = NULL;
|
|
cret = _map_user_pages(pin,
|
|
untagged_addr((unsigned long)(*shm_data).param.buffer),
|
|
(*shm_data).param.size, 0);
|
|
if (cret) {
|
|
pin->pageArray = NULL;
|
|
KREE_DEBUG("[%s]_map_user_pages fail. map user pages = 0x%x\n",
|
|
__func__, (uint32_t) cret);
|
|
cret = TZ_RESULT_ERROR_INVALID_HANDLE;
|
|
goto us_map_fail;
|
|
}
|
|
|
|
if (!pin->pageArray) {
|
|
KREE_ERR("[%s]pin->pageArray is null. fail.\n", __func__);
|
|
cret = TZ_RESULT_ERROR_GENERIC;
|
|
goto us_map_fail;
|
|
}
|
|
|
|
/* 2. build PA table */
|
|
/*check alloc size if <= 32KB*/
|
|
map_p_sz = sizeof(uint64_t) * (pin->nrPages + 1);
|
|
if (map_p_sz >= SZ_32KB) {
|
|
KREE_INFO("[%s]alloc map_p sz(0x%llx)>=32KB\n",
|
|
__func__, map_p_sz);
|
|
//cret = TZ_RESULT_ERROR_OUT_OF_MEMORY;
|
|
//goto us_map_fail;
|
|
}
|
|
|
|
/*map_p = kzalloc(map_p_sz, GFP_KERNEL);*/
|
|
/*map_p = vmalloc(map_p_sz);*/
|
|
map_p = kvmalloc(map_p_sz, GFP_KERNEL);
|
|
if (!map_p) {
|
|
KREE_DEBUG("[%s]alloc fail: map_p is null.\n", __func__);
|
|
cret = TZ_RESULT_ERROR_OUT_OF_MEMORY;
|
|
goto us_map_fail;
|
|
}
|
|
map_p[0] = pin->nrPages;
|
|
if (pin->isPage) {
|
|
page = (struct page **)pin->pageArray;
|
|
for (i = 0; i < pin->nrPages; i++) /* PA */
|
|
map_p[1 + i] =
|
|
(uint64_t) PFN_PHYS(page_to_pfn(page[i]));
|
|
} else { /* pfn */
|
|
pfns = (unsigned long *)pin->pageArray;
|
|
for (i = 0; i < pin->nrPages; i++) /* get PA */
|
|
map_p[1 + i] = (uint64_t) PFN_PHYS(pfns[i]);
|
|
}
|
|
|
|
/* init register shared mem params */
|
|
shm_param.buffer = NULL;
|
|
shm_param.size = 0;
|
|
shm_param.mapAry = (void *)map_p;
|
|
|
|
numOfPA = pin->nrPages;
|
|
//KREE_DEBUG("[%s]numOfPA=0x%x\n", __func__, numOfPA);
|
|
|
|
cret = KREE_RegisterSharedmem(session, shm_handle, &shm_param);
|
|
KREE_DEBUG("[%s]reg shmem ret hd=0x%x\n", __func__, *shm_handle);
|
|
if ((cret != TZ_RESULT_SUCCESS) || (*shm_handle == 0)) {
|
|
KREE_ERR("[%s]RegisterSharedmem fail\n", __func__);
|
|
KREE_ERR("ret=0x%lx, shm_hd=0x%x)\n", cret, *shm_handle);
|
|
}
|
|
|
|
/*after reg. shmem, free PA list array*/
|
|
if (map_p != NULL)
|
|
kvfree(map_p);
|
|
//vfree(map_p);
|
|
/*kfree(map_p);*/
|
|
|
|
us_map_fail:
|
|
if (pin) {
|
|
if (pin->pageArray) {
|
|
delpages = (struct page **)pin->pageArray;
|
|
if (pin->isPage) {
|
|
for (i = 0; i < pin->nrPages; i++)
|
|
put_page(delpages[i]);
|
|
}
|
|
kfree(pin->pageArray);
|
|
}
|
|
/*kfree(pin);*/
|
|
//vfree(pin);
|
|
kvfree(pin);
|
|
}
|
|
|
|
return cret;
|
|
}
|
|
|
|
int gz_adjust_task_attr(struct trusty_task_attr *manual_task_attr)
|
|
{
|
|
if (IS_ERR_OR_NULL(tz_system_dev)) {
|
|
KREE_ERR("GZ KREE is still not initialized!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
return trusty_adjust_task_attr(tz_system_dev->dev.parent, manual_task_attr);
|
|
}
|
|
|
|
TZ_RESULT gz_manual_adjust_trusty_wq_attr(void __user *user_req)
|
|
{
|
|
int err;
|
|
char str[32];
|
|
struct trusty_task_attr manual_task_attr;
|
|
|
|
err = copy_from_user(&str, user_req, sizeof(str));
|
|
if (err) {
|
|
KREE_ERR("[%s]copy_from_user fail(0x%x)\n", __func__,
|
|
err);
|
|
return err;
|
|
}
|
|
str[31] = '\0';
|
|
KREE_DEBUG("%s cmd=%s\n", __func__, str);
|
|
|
|
memset(&manual_task_attr, 0, sizeof(manual_task_attr));
|
|
err = sscanf(str, "0x%x %d 0x%x %d",
|
|
&manual_task_attr.mask[TRUSTY_TASK_KICK_ID],
|
|
&manual_task_attr.pri[TRUSTY_TASK_KICK_ID],
|
|
&manual_task_attr.mask[TRUSTY_TASK_CHK_ID],
|
|
&manual_task_attr.pri[TRUSTY_TASK_CHK_ID]);
|
|
if (err != 4)
|
|
return -EINVAL;
|
|
|
|
KREE_DEBUG("%s 0x%x %d 0x%x %d\n", __func__,
|
|
manual_task_attr.mask[TRUSTY_TASK_KICK_ID],
|
|
manual_task_attr.pri[TRUSTY_TASK_KICK_ID],
|
|
manual_task_attr.mask[TRUSTY_TASK_CHK_ID],
|
|
manual_task_attr.pri[TRUSTY_TASK_CHK_ID]);
|
|
|
|
tipc_set_default_cpumask(manual_task_attr.mask[TRUSTY_TASK_KICK_ID]);
|
|
|
|
return gz_adjust_task_attr(&manual_task_attr);
|
|
}
|
|
|
|
static long _gz_ioctl(struct file *filep, unsigned int cmd, void __user *arg,
|
|
unsigned int compat)
|
|
{
|
|
int err;
|
|
TZ_RESULT ret = 0;
|
|
struct user_shm_param shm_data;
|
|
KREE_SHAREDMEM_HANDLE shm_handle = 0;
|
|
|
|
if (_IOC_TYPE(cmd) != MTEE_IOC_MAGIC)
|
|
return -EINVAL;
|
|
|
|
switch (cmd) {
|
|
case MTEE_CMD_SHM_REG:
|
|
KREE_DEBUG("[%s]cmd=MTEE_CMD_SHM_REG(0x%x)\n", __func__, cmd);
|
|
/* copy param from user */
|
|
err = copy_from_user(&shm_data, arg, sizeof(shm_data));
|
|
if (err) {
|
|
KREE_ERR("[%s]copy_from_user fail(0x%x)\n", __func__,
|
|
err);
|
|
return err;
|
|
}
|
|
|
|
if ((shm_data.param.size <= 0) || (!shm_data.param.buffer)) {
|
|
KREE_DEBUG("[%s]bad param:size=%x or !param.buffer\n",
|
|
__func__, shm_data.param.size);
|
|
return TZ_RESULT_ERROR_BAD_PARAMETERS;
|
|
}
|
|
|
|
ret = _reg_shmem_from_userspace(shm_data.session,
|
|
shm_data.param.region_id, &shm_data, &shm_handle);
|
|
if (ret != TZ_RESULT_SUCCESS) {
|
|
KREE_ERR("[%s] _reg_userspace_shmem ret fail(%d)\n",
|
|
__func__, ret);
|
|
}
|
|
|
|
shm_data.shm_handle = shm_handle;
|
|
|
|
/* copy result back to user */
|
|
shm_data.session = ret;
|
|
err = copy_to_user(arg, &shm_data, sizeof(shm_data));
|
|
if (err) {
|
|
KREE_ERR("[%s]copy_to_user fail(0x%x)\n", __func__,
|
|
err);
|
|
return err;
|
|
}
|
|
break;
|
|
|
|
case MTEE_CMD_OPEN_SESSION:
|
|
KREE_DEBUG("[%s]cmd=MTEE_CMD_OPEN_SESSION(0x%x)\n", __func__,
|
|
cmd);
|
|
ret = tz_client_open_session(filep, arg);
|
|
if (ret != TZ_RESULT_SUCCESS) {
|
|
KREE_ERR("[%s]tz_client_open_session() fail\n",
|
|
__func__);
|
|
return ret;
|
|
}
|
|
break;
|
|
|
|
case MTEE_CMD_CLOSE_SESSION:
|
|
KREE_DEBUG("[%s]cmd=MTEE_CMD_CLOSE_SESSION(0x%x)\n", __func__,
|
|
cmd);
|
|
ret = tz_client_close_session(filep, arg);
|
|
if (ret != TZ_RESULT_SUCCESS) {
|
|
KREE_ERR("[%s]tz_client_close_session() fail\n",
|
|
__func__);
|
|
return ret;
|
|
}
|
|
break;
|
|
|
|
case MTEE_CMD_TEE_SERVICE:
|
|
KREE_DEBUG("[%s]cmd=MTEE_CMD_TEE_SERVICE(0x%x)\n", __func__,
|
|
cmd);
|
|
return tz_client_tee_service(filep, arg, compat);
|
|
|
|
#ifndef CONFIG_MTK_GZ_SUPPORT_SDSP
|
|
case MTEE_CMD_FOD_TEE_SHM_ON:
|
|
KREE_DEBUG("====> MTEE_CMD_FOD_TEE_SHM_ON ====\n");
|
|
ret = mtee_sdsp_enable(1);
|
|
break;
|
|
|
|
case MTEE_CMD_FOD_TEE_SHM_OFF:
|
|
KREE_DEBUG("====> MTEE_CMD_FOD_TEE_SHM_OFF ====\n");
|
|
ret = mtee_sdsp_enable(0);
|
|
break;
|
|
#endif
|
|
|
|
case MTEE_CMD_ADJUST_WQ_ATTR:
|
|
ret = gz_manual_adjust_trusty_wq_attr(arg);
|
|
break;
|
|
|
|
default:
|
|
KREE_ERR("[%s] undefined ioctl cmd 0x%x\n", __func__, cmd);
|
|
ret = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static long gz_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
|
|
{
|
|
long ret;
|
|
void __user *user_req = (void __user *)arg;
|
|
|
|
ret = _gz_ioctl(filep, cmd, user_req, 0);
|
|
return ret;
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_COMPAT)
|
|
static long gz_compat_ioctl(struct file *filep, unsigned int cmd,
|
|
unsigned long arg)
|
|
{
|
|
long ret;
|
|
void __user *user_req = (void __user *)compat_ptr(arg);
|
|
|
|
ret = _gz_ioctl(filep, cmd, user_req, 1);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if enable_code
|
|
|
|
#if IS_ENABLED(CONFIG_MTK_DEVAPC) && !IS_ENABLED(CONFIG_DEVAPC_LEGACY)
|
|
static void gz_devapc_vio_dump(void)
|
|
{
|
|
pr_debug("%s:%d GZ devapc is triggered!\n", __func__, __LINE__);
|
|
|
|
if (IS_ERR_OR_NULL(tz_system_dev)) {
|
|
KREE_ERR("GZ KREE is still not initialized!\n");
|
|
return;
|
|
}
|
|
|
|
trusty_fast_call32(tz_system_dev->dev.parent,
|
|
MTEE_SMCNR(MT_SMCF_FC_DEVAPC_VIO, tz_system_dev->dev.parent),
|
|
0, 0, 0);
|
|
}
|
|
|
|
static struct devapc_vio_callbacks gz_devapc_vio_handle = {
|
|
.id = INFRA_SUBSYS_GZ,
|
|
.debug_dump = gz_devapc_vio_dump,
|
|
};
|
|
#endif
|
|
|
|
#endif
|
|
/************ kernel module init entry ***************/
|
|
static int __init gz_init(void)
|
|
{
|
|
int res;
|
|
|
|
tz_system_dev = NULL;
|
|
|
|
res = create_files();
|
|
if (res) {
|
|
KREE_DEBUG("create sysfs failed: %d\n", res);
|
|
} else {
|
|
struct task_struct *gz_get_cpuinfo_task;
|
|
|
|
gz_get_cpuinfo_task =
|
|
kthread_create(gz_get_cpuinfo_thread, NULL,
|
|
"gz_get_cpuinfo_task");
|
|
if (IS_ERR(gz_get_cpuinfo_task)) {
|
|
KREE_ERR("Unable to start kernel thread %s\n",
|
|
__func__);
|
|
res = PTR_ERR(gz_get_cpuinfo_task);
|
|
} else
|
|
wake_up_process(gz_get_cpuinfo_task);
|
|
}
|
|
|
|
#if enable_code
|
|
|
|
#if IS_ENABLED(CONFIG_MTK_DEVAPC) && !IS_ENABLED(CONFIG_DEVAPC_LEGACY)
|
|
register_devapc_vio_callback(&gz_devapc_vio_handle);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
return res;
|
|
}
|
|
|
|
/************ kernel module exit entry ***************/
|
|
static void __exit gz_exit(void)
|
|
{
|
|
KREE_DEBUG("gz driver exit\n");
|
|
}
|
|
|
|
|
|
module_init(gz_init);
|
|
module_exit(gz_exit);
|