kernel-brax3-ubuntu-touch/drivers/tee/teei/500/tz_driver/teei_client_main.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

1285 lines
28 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015-2019, MICROTRUST Incorporated
* All Rights Reserved.
*
*/
#define IMSG_TAG "[tz_driver]"
#include <imsg_log.h>
#include <linux/vmalloc.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <asm/cputype.h>
#include <linux/cpu.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/sched.h>
#define TEEI_SWITCH_BIG_CORE
#ifdef TEEI_FIND_PREFER_CORE_AUTO
#include <kernel/sched/sched.h>
#endif
#include <uapi/linux/sched/types.h>
#include <teei_client_main.h>
#include <teei_id.h>
#include <switch_queue.h>
#include <teei_task_link.h>
#include <teei_secure_api.h>
#include <utdriver_macro.h>
#include <notify_queue.h>
#include <nt_smc_call.h>
#include <fdrv.h>
#include <backward_driver.h>
#include <teei_fp.h>
#include "tz_log.h"
#include <utos_version.h>
#include <sysfs.h>
#include <teei_keymaster.h>
#include <irq_register.h>
#include <../teei_fp/fp_func.h>
#if IS_ENABLED(CONFIG_MICROTRUST_TZ_DRIVER_MTK_BOOTPROF) && IS_ENABLED(CONFIG_MTPROF)
#define TEEI_BOOT_FOOTPRINT(str) bootprof_log_boot(str)
#else
#define TEEI_BOOT_FOOTPRINT(str) IMSG_PRINTK("%s\n", str)
#endif
#define DECLARE_SEMA(name, init_value) \
struct semaphore name = __SEMAPHORE_INITIALIZER(name, init_value)
#define DECLARE_RW_SEMA(name) \
struct rw_semaphore name = __RWSEM_INITIALIZER(name)
DECLARE_RW_SEMA(teei_cpus_lock);
DECLARE_SEMA(boot_sema, 0);
DECLARE_SEMA(pm_sema, 0);
DECLARE_COMPLETION(boot_decryto_lock);
#if !IS_ENABLED(CONFIG_MICROTRUST_DYNAMIC_CORE)
#define TZ_PREFER_BIND_CORE (6)
#endif
#define TEEI_RT_POLICY (0x01)
#define TEEI_NORMAL_POLICY (0x02)
/* ARMv8.2 for CA55, CA75 etc */
static int teei_cpu_id_arm82[] = {
0x81000000, 0x81000100, 0x81000200, 0x81000300,
0x81000400, 0x81000500, 0x81000600, 0x81000700,
0x81000800, 0x81000900, 0x81000a00, 0x81000b00};
/* ARMv8 */
static int teei_cpu_id_arm80[] = {
0x0000, 0x0001, 0x0002, 0x0003,
0x0100, 0x0101, 0x0102, 0x0103,
0x0200, 0x0201, 0x0202, 0x0203};
static int *teei_cpu_id;
enum {
TEEI_BOOT_OK = 0,
TEEI_BOOT_ERROR_CREATE_TLOG_BUF = 1,
TEEI_BOOT_ERROR_CREATE_TLOG_THREAD = 2,
TEEI_BOOT_ERROR_CREATE_VFS_ADDR = 3,
TEEI_BOOT_ERROR_LOAD_SOTER_FAILED = 4,
TEEI_BOOT_ERROR_INIT_CMD_BUFF_FAILED = 5,
TEEI_BOOT_ERROR_INIT_UTGATE_FAILED = 6,
TEEI_BOOT_ERROR_INIT_SERVICE1_FAILED = 7,
TEEI_BOOT_ERROR_INIT_CAPI_FAILED = 8,
TEEI_BOOT_ERROR_INIT_SERVICE2_FAILED = 9,
TEEI_BOOT_ERROR_LOAD_TA_FAILED = 10,
};
struct teei_boot_error_item {
unsigned int id;
char *str;
};
struct teei_boot_error_item teei_boot_error_items[] = {
{ TEEI_BOOT_OK, "TEEI_BOOT_OK"},
{ TEEI_BOOT_ERROR_CREATE_TLOG_BUF,
"TEEI_BOOT_ERROR_CREATE_TLOG_BUF" },
{ TEEI_BOOT_ERROR_CREATE_TLOG_THREAD,
"TEEI_BOOT_ERROR_CREATE_TLOG_THREAD" },
{ TEEI_BOOT_ERROR_CREATE_VFS_ADDR,
"TEEI_BOOT_ERROR_CREATE_VFS_ADDR" },
{ TEEI_BOOT_ERROR_LOAD_SOTER_FAILED,
"TEEI_BOOT_ERROR_LOAD_SOTER_FAILED" },
{ TEEI_BOOT_ERROR_INIT_CMD_BUFF_FAILED,
"TEEI_BOOT_ERROR_INIT_CMD_BUFF_FAILED" },
{ TEEI_BOOT_ERROR_INIT_UTGATE_FAILED,
"TEEI_BOOT_ERROR_INIT_UTGATE_FAILED" },
{ TEEI_BOOT_ERROR_INIT_SERVICE1_FAILED,
"TEEI_BOOT_ERROR_INIT_SERVICE1_FAILED" },
{ TEEI_BOOT_ERROR_INIT_CAPI_FAILED,
"TEEI_BOOT_ERROR_INIT_CAPI_FAILED" },
{ TEEI_BOOT_ERROR_INIT_SERVICE2_FAILED,
"TEEI_BOOT_ERROR_INIT_SERVICE2_FAILED" },
{ TEEI_BOOT_ERROR_LOAD_TA_FAILED,
"TEEI_BOOT_ERROR_LOAD_TA_FAILED" }
};
char *teei_boot_error_to_string(uint32_t id)
{
int i = 0;
for (i = 0; i < (sizeof(teei_boot_error_items)
/ sizeof(struct teei_boot_error_item)); i++) {
if (id == teei_boot_error_items[i].id)
return teei_boot_error_items[i].str;
}
return "TEEI_BOOT_ERROR_NDEFINED";
}
struct workqueue_struct *secure_wq;
#if !IS_ENABLED(CONFIG_MICROTRUST_DYNAMIC_CORE)
static int current_cpu_id;
#endif
unsigned long teei_config_flag;
unsigned int soter_error_flag;
unsigned long boot_vfs_addr;
unsigned long boot_soter_flag;
unsigned long device_file_cnt;
struct list_head g_block_link;
/* For keymaster */
unsigned long teei_capi_ready;
static unsigned int teei_flags;
static dev_t teei_config_device_no;
static struct cdev teei_config_cdev;
static struct class *config_driver_class;
struct task_struct *teei_switch_task;
struct task_struct *teei_bdrv_task;
struct task_struct *teei_log_task;
#if !IS_ENABLED(CONFIG_MICROTRUST_DYNAMIC_CORE)
static struct cpumask mask = { CPU_BITS_NONE };
#endif
static struct class *driver_class;
static dev_t teei_client_device_no;
static struct cdev teei_client_cdev;
DEFINE_KTHREAD_WORKER(ut_fastcall_worker);
static struct tz_driver_state *tz_drv_state;
static void *teei_cpu_write_owner;
static struct platform_device *g_teei_pdev;
int teei_set_switch_pri(unsigned long policy)
{
#ifdef DYNAMIC_SET_PRIORITY
int retVal = 0;
if (policy == TEEI_RT_POLICY) {
if (teei_switch_task != NULL) {
set_user_nice(teei_switch_task, MIN_NICE);
return 0;
} else
return -EINVAL;
} else if (policy == TEEI_NORMAL_POLICY) {
if (teei_switch_task != NULL) {
set_user_nice(teei_switch_task, 0);
return 0;
} else
return -EINVAL;
} else {
IMSG_PRINTK("TEEI: %s invalid Param (%lx)\n",
__func__, policy);
retVal = -EINVAL;
}
return retVal;
#else
return 0;
#endif
}
void teei_cpus_read_lock(void)
{
if (current != teei_cpu_write_owner)
cpus_read_lock();
}
void teei_cpus_read_unlock(void)
{
if (current != teei_cpu_write_owner)
cpus_read_unlock();
}
void teei_cpus_write_lock(void)
{
#ifdef ISEE_FP_SINGLE_CHANNEL
cpus_write_lock();
teei_cpu_write_owner = current;
#endif
}
void teei_cpus_write_unlock(void)
{
#ifdef ISEE_FP_SINGLE_CHANNEL
teei_cpu_write_owner = NULL;
cpus_write_unlock();
#endif
}
struct tz_driver_state *get_tz_drv_state(void)
{
return tz_drv_state;
}
void *tz_malloc(size_t size, int flags)
{
void *ptr = kmalloc(size, flags | GFP_ATOMIC);
return ptr;
}
void *tz_malloc_shared_mem(size_t size, int flags)
{
#ifdef UT_DMA_ZONE
return (void *) __get_free_pages(flags | GFP_DMA,
get_order(ROUND_UP(size, SZ_4K)));
#else
return (void *) __get_free_pages(flags,
get_order(ROUND_UP(size, SZ_4K)));
#endif
}
void tz_free_shared_mem(void *addr, size_t size)
{
free_pages((unsigned long)addr, get_order(ROUND_UP(size, SZ_4K)));
}
int teei_move_cpu_context(int target_cpu_id, int original_cpu_id)
{
teei_secure_call(N_SWITCH_CORE, teei_cpu_id[target_cpu_id],
teei_cpu_id[original_cpu_id], 0);
return 0;
}
#if !IS_ENABLED(CONFIG_MICROTRUST_DYNAMIC_CORE)
int get_current_cpuid(void)
{
return current_cpu_id;
}
static bool is_prefer_core(int cpu)
{
/* bind to a specific core */
if (cpu == TZ_PREFER_BIND_CORE)
return true;
return false;
}
static int find_prefer_core(int excluded_cpu)
{
int i = 0;
int prefer_core = -1;
/* search for prefer cpu firstly */
for_each_online_cpu(i) {
if (i == excluded_cpu)
continue;
if (is_prefer_core(i)) {
prefer_core = i;
break;
}
}
/* if prefer is found, return directly */
if (prefer_core != -1)
return prefer_core;
/* if not found, then search for other online cpu */
for_each_online_cpu(i) {
if (i == excluded_cpu)
continue;
prefer_core = i;
/* break when next active cpu has been selected */
break;
}
return prefer_core;
}
static bool is_prefer_core_binded(void)
{
unsigned int curr = get_current_cpuid();
if (is_prefer_core(curr))
return true;
return false;
}
static bool is_prefer_core_onlined(void)
{
int i = 0;
for_each_online_cpu(i) {
if (is_prefer_core(i))
return true;
}
return false;
}
int handle_switch_core(int cpu)
{
int switch_to_cpu_id = 0;
switch_to_cpu_id = find_prefer_core(cpu);
IMSG_PRINTK("[%s][%d]before cpumask set cpu, find %d\n",
__func__, __LINE__, switch_to_cpu_id);
set_cpus_allowed_ptr(teei_switch_task, cpumask_of(switch_to_cpu_id));
teei_secure_call(N_SWITCH_CORE,
teei_cpu_id[switch_to_cpu_id], teei_cpu_id[cpu], 0);
current_cpu_id = switch_to_cpu_id;
IMSG_PRINTK("change cpu id from %d(0x%lx) to %d(0x%lx)\n",
cpu, teei_cpu_id[cpu],
switch_to_cpu_id, teei_cpu_id[switch_to_cpu_id]);
up(&pm_sema);
return 0;
}
static int nq_cpu_up_prep(unsigned int cpu)
{
#ifdef TEEI_SWITCH_BIG_CORE
int retVal = 0;
unsigned int sched_cpu = get_current_cpuid();
IMSG_DEBUG("current_cpu_id = %d power on %d\n",
sched_cpu, cpu);
if (cpu == TZ_PREFER_BIND_CORE) {
IMSG_DEBUG("cpu up : prepare for changing %d to %d\n",
sched_cpu, cpu);
retVal = add_work_entry(SWITCH_CORE_TYPE,
(unsigned long)sched_cpu, 0, 0, 0);
teei_notify_switch_fn();
down(&pm_sema);
}
return retVal;
#else
return 0;
#endif
}
static int nq_cpu_down_prep(unsigned int cpu)
{
int retVal = 0;
unsigned int sched_cpu = get_current_cpuid();
if (cpu == sched_cpu) {
IMSG_PRINTK("cpu down prepare for %d.\n", cpu);
retVal = add_work_entry(SWITCH_CORE_TYPE, (unsigned long)cpu,
0, 0, 0);
teei_notify_switch_fn();
down(&pm_sema);
} else if (is_prefer_core(cpu))
IMSG_DEBUG("cpu down prepare for prefer %d.\n", cpu);
else if (!is_prefer_core_binded()
&& is_prefer_core_onlined()) {
IMSG_PRINTK("cpu down prepare for changing %d %d.\n",
sched_cpu, cpu);
retVal = add_work_entry(SWITCH_CORE_TYPE,
(unsigned long)sched_cpu, 0, 0, 0);
teei_notify_switch_fn();
down(&pm_sema);
}
return retVal;
}
#endif /* CONFIG_MICROTRUST_DYNAMIC_CORE */
int t_os_load_image(void)
{
int retVal = 0;
retVal = add_work_entry(SMC_CALL_TYPE, N_INVOKE_T_NQ, 0, 0, 0);
if (retVal != 0) {
IMSG_ERROR("[%s][%d] Failed to call the add_work_entry!\n",
__func__, __LINE__);
}
retVal = add_nq_entry(TEEI_LOAD_TEE, 0,
(unsigned long long)(&boot_sema),
0, 0, 0);
if (retVal != 0) {
IMSG_ERROR("[%s][%d] Failed to call the add_nq_entry!\n",
__func__, __LINE__);
}
teei_notify_switch_fn();
down(&boot_sema);
return retVal;
}
static void boot_stage1(unsigned long vfs_addr, unsigned long tlog_addr)
{
int retVal = 0;
switch_input_index = ((unsigned long)switch_input_index + 1) % 10000;
retVal = add_work_entry(SMC_CALL_TYPE, N_INIT_T_BOOT_STAGE1,
vfs_addr, tlog_addr, 0);
if (retVal != 0) {
IMSG_ERROR("[%s][%d] TEEI: Failed to call add_work_entry!\n",
__func__, __LINE__);
return;
}
teei_notify_switch_fn();
down(&(boot_sema));
}
long teei_create_drv_shm(void)
{
long retVal = 0;
retVal = create_all_fdrv();
if (retVal < 0) {
IMSG_ERROR("[%s][%d] create_all_fdrv failed!\n",
__func__, __LINE__);
return -1;
}
if (soter_error_flag == 1)
return -1;
/**
* init service handler
*/
retVal = init_all_service_handlers();
if (retVal < 0) {
IMSG_ERROR("[%s][%d] init_all_service_handlers failed!\n",
__func__, __LINE__);
return -1;
}
if (soter_error_flag == 1)
return -1;
return 0;
}
long teei_service_init_second(void)
{
IMSG_DEBUG("[%s][%d] begin to create fp buffer!\n",
__func__, __LINE__);
if (soter_error_flag == 1)
return -1;
return 0;
}
/**
* @brief init TEEI Framework
* init Soter OS
* init Global Schedule
* init Forward Call Service
* init CallBack Service
* @return
*/
struct notifier_block ut_smc_nb;
static int init_teei_framework(void)
{
long retVal = 0;
struct tz_log_state *s = dev_get_platdata(
&tz_drv_state->tz_log_pdev->dev);
phys_addr_t tz_log_buf_pa = page_to_phys(s->log_pages);
boot_soter_flag = START_STATUS;
secure_wq = create_workqueue("Secure Call");
TEEI_BOOT_FOOTPRINT("TEEI WorkQueue Created");
#ifdef UT_DMA_ZONE
boot_vfs_addr = (unsigned long)__get_free_pages(GFP_KERNEL | GFP_DMA,
get_order(ROUND_UP(VFS_SIZE, SZ_4K)));
#else
boot_vfs_addr = (unsigned long) __get_free_pages(GFP_KERNEL,
get_order(ROUND_UP(VFS_SIZE, SZ_4K)));
#endif
if ((unsigned char *)boot_vfs_addr == NULL)
return TEEI_BOOT_ERROR_CREATE_VFS_ADDR;
TEEI_BOOT_FOOTPRINT("TEEI VFS Buffer Created");
teei_cpus_read_lock();
TEEI_BOOT_FOOTPRINT("TEEI BOOT STAGE1 GOT CPU READ LOCK");
boot_stage1((unsigned long)virt_to_phys((void *)boot_vfs_addr),
(unsigned long)tz_log_buf_pa);
TEEI_BOOT_FOOTPRINT("TEEI BOOT STAGE1 RETURN FROM TEE");
teei_cpus_read_unlock();
TEEI_BOOT_FOOTPRINT("TEEI BOOT Stage1 Completed");
free_pages(boot_vfs_addr, get_order(ROUND_UP(VFS_SIZE, SZ_4K)));
boot_soter_flag = END_STATUS;
if (soter_error_flag == 1)
return TEEI_BOOT_ERROR_LOAD_SOTER_FAILED;
teei_cpus_read_lock();
retVal = create_nq_buffer();
teei_cpus_read_unlock();
if (retVal < 0)
return TEEI_BOOT_ERROR_INIT_CMD_BUFF_FAILED;
TEEI_BOOT_FOOTPRINT("TEEI BOOT CREATE NQ DONE");
teei_cpus_read_lock();
retVal = teei_create_drv_shm();
teei_cpus_read_unlock();
if (retVal == -1)
return TEEI_BOOT_ERROR_INIT_SERVICE1_FAILED;
TEEI_BOOT_FOOTPRINT("TEEI BOOT CREATE DRV SHM DONE");
retVal = teei_new_capi_init();
if (retVal < 0)
return TEEI_BOOT_ERROR_INIT_CAPI_FAILED;
TEEI_BOOT_FOOTPRINT("TEEI NEW CAPI Inited");
/* waiting for keymaster shm ready and anable the keymaster IOCTL */
teei_capi_ready = 1;
up(&keymaster_api_lock);
TEEI_BOOT_FOOTPRINT("TEEI BOOT Keymaster Unlocked");
/* android notify the uTdriver that the TAs is ready !*/
wait_for_completion(&boot_decryto_lock);
TEEI_BOOT_FOOTPRINT("TEEI BOOT Decrypt Unlocked");
teei_cpus_read_lock();
retVal = teei_service_init_second();
teei_cpus_read_unlock();
TEEI_BOOT_FOOTPRINT("TEEI BOOT Service2 Inited");
if (retVal == -1)
return TEEI_BOOT_ERROR_INIT_SERVICE2_FAILED;
teei_cpus_read_lock();
t_os_load_image();
teei_cpus_read_unlock();
TEEI_BOOT_FOOTPRINT("TEEI BOOT Load TEES Completed");
if (soter_error_flag == 1)
return TEEI_BOOT_ERROR_LOAD_TA_FAILED;
teei_config_flag = 1;
#if IS_ENABLED(CONFIG_MICROTRUST_FP_DRIVER)
wake_up(&__fp_open_wq);
#endif
TEEI_BOOT_FOOTPRINT("TEEI BOOT All Completed");
return TEEI_BOOT_OK;
}
/**
* @brief
*
* @param file
* @param cmd
* @param arg
*
* @return
*/
int is_teei_ready(void)
{
return teei_flags;
}
EXPORT_SYMBOL(is_teei_ready);
#ifdef TEEI_FIND_PREFER_CORE_AUTO
int teei_get_max_freq(int cpu_index)
{
return arch_max_cpu_freq(NULL, cpu_index);
}
#endif
static long teei_config_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int retVal = 0;
struct init_param param;
unsigned int teei_ta_flags;
switch (cmd) {
case TEEI_CONFIG_IOCTL_INIT_TEEI:
if (teei_flags != 1) {
long res;
int i;
if (arg == 0) {
IMSG_ERROR("arg is null\n");
return -EINVAL;
}
res = copy_from_user(&param, (void *)arg,
sizeof(struct init_param));
if (res) {
IMSG_ERROR("failed to copy from user\n");
retVal = -EINVAL;
goto err;
}
retVal = init_teei_framework();
TEEI_BOOT_FOOTPRINT(
teei_boot_error_to_string(retVal));
teei_flags = 1;
TEEI_BOOT_FOOTPRINT("TEEI start to load driver TAs");
if (param.uuid_count > MAX_DRV_UUIDS) {
IMSG_ERROR("TEEI uuid_count is invalid(%u)!\n",
(unsigned int)(param.uuid_count));
return -EINVAL;
}
teei_ta_flags = param.flag;
for (i = 0; i < param.uuid_count; i++) {
param.uuids[i][UUID_LEN] = 0;
if ((teei_ta_flags >> i) & (0x01))
tz_load_ta_by_str(param.uuids[i]);
else
tz_load_drv_by_str(param.uuids[i]);
}
param.flag = teei_flags;
TEEI_BOOT_FOOTPRINT("TEEI end of load driver TAs");
res = copy_to_user((void *)arg, &param,
sizeof(struct init_param));
if (res)
IMSG_ERROR("failed to copy to user\n");
}
break;
case TEEI_CONFIG_IOCTL_UNLOCK:
complete(&boot_decryto_lock);
break;
default:
retVal = -EINVAL;
}
err:
return retVal;
}
/**
* @brief The open operation of /dev/teei_config device node.
*
* @param inode
* @param file
*
* @return ENOMEM: no enough memory in the linux kernel
* 0: on success
*/
static int teei_config_open(struct inode *inode, struct file *file)
{
return 0;
}
/**
* @brief The release operation of /dev/teei_config device node.
*
* @param inode: device inode structure
* @param file: struct file
*
* @return 0: on success
*/
static int teei_config_release(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t teei_config_read(struct file *filp,
char __user *buf, size_t size, loff_t *ppos)
{
char *file_context = NULL;
int retVal = 0;
file_context = kmalloc(size, GFP_KERNEL);
if (file_context == NULL)
return -ENOMEM;
retVal = tz_driver_read_logs(file_context, (unsigned long)size);
if (retVal < 0) {
IMSG_ERROR("Failed to call the %s! retVal = %d\n",
__func__, retVal);
kfree(file_context);
return (ssize_t)retVal;
}
if (copy_to_user(buf, file_context, retVal)) {
IMSG_ERROR("copy to user failed.\n");
kfree(file_context);
return -EFAULT;
}
kfree(file_context);
return (ssize_t)retVal;
}
/**
* @brief
*/
static const struct file_operations teei_config_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = teei_config_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = teei_config_ioctl,
#endif
.open = teei_config_open,
.read = teei_config_read,
.release = teei_config_release
};
/**
* @brief TEEI Agent Driver initialization
* initialize Microtrust Tee environment
* @return
**/
static int teei_config_init(void)
{
int retVal = 0;
struct device *class_dev = NULL;
retVal = alloc_chrdev_region(&teei_config_device_no,
0, 1, TEEI_CONFIG_DEV);
if (retVal < 0) {
IMSG_ERROR("alloc_chrdev_region failed %x.\n", retVal);
return retVal;
}
config_driver_class = class_create(THIS_MODULE, TEEI_CONFIG_DEV);
if (IS_ERR(config_driver_class)) {
retVal = -ENOMEM;
IMSG_ERROR("class_create failed %x\n", retVal);
goto unregister_chrdev_region;
}
class_dev = device_create(config_driver_class, NULL,
teei_config_device_no, NULL, TEEI_CONFIG_DEV);
if (class_dev == NULL) {
IMSG_ERROR("class_device_create failed %x\n", retVal);
retVal = -ENOMEM;
goto class_destroy;
}
cdev_init(&teei_config_cdev, &teei_config_fops);
teei_config_cdev.owner = THIS_MODULE;
retVal = cdev_add(&teei_config_cdev,
MKDEV(MAJOR(teei_config_device_no), 0), 1);
if (retVal < 0) {
IMSG_ERROR("cdev_add failed %x\n", retVal);
goto class_device_destroy;
}
goto return_fn;
class_device_destroy:
device_destroy(driver_class, teei_config_device_no);
class_destroy:
class_destroy(driver_class);
unregister_chrdev_region:
unregister_chrdev_region(teei_config_device_no, 1);
return_fn:
return retVal;
}
/**
* @brief The open operation of /dev/teei_client device node.
*
* @param inode
* @param file
*
* @return ENOMEM: no enough memory in the linux kernel
* 0: on success
*/
static int teei_client_open(struct inode *inode, struct file *file)
{
return 0;
}
void show_utdriver_lock_status(void)
{
int retVal = 0;
IMSG_PRINTK("[%s][%d] how_utdriver_lock_status begin.\n",
__func__, __LINE__);
#if IS_ENABLED(CONFIG_MICROTRUST_FP_DRIVER)
retVal = down_trylock(&fp_api_lock);
if (retVal == 1)
IMSG_PRINTK("[%s][%d] fp_api_lock is down\n",
__func__, __LINE__);
else {
IMSG_PRINTK("[%s][%d] fp_api_lock is up\n",
__func__, __LINE__);
up(&fp_api_lock);
}
#endif
retVal = down_trylock(&keymaster_api_lock);
if (retVal == 1)
IMSG_PRINTK("[%s][%d] keymaster_api_lock is down\n",
__func__, __LINE__);
else {
IMSG_PRINTK("[%s][%d] keymaster_api_lock is up\n",
__func__, __LINE__);
up(&keymaster_api_lock);
}
IMSG_PRINTK("[%s][%d] how_utdriver_lock_status end.\n",
__func__, __LINE__);
return;
}
static ssize_t teei_client_dump(struct file *filp,
char __user *buf, size_t size, loff_t *ppos)
{
IMSG_PRINTK("[%s][%d] begin.....\n", __func__, __LINE__);
show_utdriver_lock_status();
IMSG_PRINTK("[%s][%d] finished.....\n", __func__, __LINE__);
return 0;
}
/**
* @brief The release operation of /dev/teei_client device node.
*
* @param inode: device inode structure
* @param file: struct file
*
* @return 0: on success
*/
static int teei_client_release(struct inode *inode, struct file *file)
{
return 0;
}
/**
* @brief
*/
static const struct file_operations teei_client_fops = {
.owner = THIS_MODULE,
.open = teei_client_open,
.read = teei_client_dump,
.release = teei_client_release
};
static int teei_probe(struct platform_device *pdev)
{
int ut_irq = 0;
ut_irq = platform_get_irq(pdev, 0);
IMSG_INFO("teei device ut_irq is %d\n", ut_irq);
if (register_ut_irq_handler(ut_irq) < 0) {
IMSG_ERROR("teei_device can't register irq %d\n", ut_irq);
return -1;
}
g_teei_pdev = pdev;
return 0;
}
static int teei_remove(struct platform_device *pdev)
{
remove_sysfs(pdev);
return 0;
}
static const struct of_device_id teei_of_ids[] = {
{ .compatible = "microtrust,utos", },
{}
};
static struct platform_driver teei_driver = {
.probe = teei_probe,
.remove = teei_remove,
.suspend = NULL,
.resume = NULL,
.driver = {
.name = "utos",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = teei_of_ids,
#endif
},
};
/**
* @brief TEEI Agent Driver initialization
* initialize service framework
* @return
*/
static int teei_client_init(void)
{
int ret = 0;
int ret_code = 0;
struct device *class_dev = NULL;
struct device_node *np = NULL;
struct sched_param param = {.sched_priority = 50 };
/* IMSG_DEBUG("TEEI Agent Driver Module Init ...\n"); */
IMSG_DEBUG("=====================================================\n\n");
IMSG_DEBUG("~~~~~~~uTos version [%s]~~~~~~~\n", UTOS_VERSION);
IMSG_DEBUG("=====================================================\n\n");
ret_code = alloc_chrdev_region(&teei_client_device_no,
0, 1, TEEI_CLIENT_DEV);
if (ret_code < 0) {
IMSG_ERROR("alloc_chrdev_region failed %x\n", ret_code);
return ret_code;
}
ret_code = platform_driver_register(&teei_driver);
if (ret_code) {
IMSG_ERROR("unable to register teei driver(%d)\n", ret_code);
return ret_code;
}
tz_drv_state = kzalloc(sizeof(struct tz_driver_state), GFP_KERNEL);
if (!tz_drv_state)
return -ENOMEM;
mutex_init(&tz_drv_state->smc_lock);
ATOMIC_INIT_NOTIFIER_HEAD(&tz_drv_state->notifier);
tz_drv_state->tz_log_pdev = platform_device_alloc("tz_log", 0);
if (!tz_drv_state->tz_log_pdev)
goto failed_alloc_dev;
platform_device_add(tz_drv_state->tz_log_pdev);
ret_code = tz_log_probe(tz_drv_state->tz_log_pdev);
if (ret_code) {
IMSG_ERROR("failed to initial tz_log driver (%d)\n", ret_code);
goto del_pdev;
}
driver_class = class_create(THIS_MODULE, TEEI_CLIENT_DEV);
if (IS_ERR(driver_class)) {
ret_code = -ENOMEM;
IMSG_ERROR("class_create failed %x\n", ret_code);
goto unregister_chrdev_region;
}
class_dev = device_create(driver_class, NULL,
teei_client_device_no, NULL, TEEI_CLIENT_DEV);
if (class_dev == NULL) {
IMSG_ERROR("class_device_create failed %x\n", ret_code);
ret_code = -ENOMEM;
goto class_destroy;
}
cdev_init(&teei_client_cdev, &teei_client_fops);
teei_client_cdev.owner = THIS_MODULE;
ret_code = cdev_add(&teei_client_cdev,
MKDEV(MAJOR(teei_client_device_no), 0), 1);
if (ret_code < 0) {
IMSG_ERROR("cdev_add failed %x\n", ret_code);
goto class_device_destroy;
}
if (g_teei_pdev != NULL) {
np = g_teei_pdev->dev.of_node;
ret = of_property_read_u32(np, "microtrust,real-drv", &ret_code);
if (ret || !ret_code) {
IMSG_PRINTK("MICROTRUST device is NOT enable,dummy driver\n");
ret_code = 0;
goto class_device_destroy;
}
} else {
IMSG_ERROR("teei_probe NOT get the pdev.\n");
ret_code = 0;
goto class_device_destroy;
}
init_teei_switch_comp();
teei_init_task_link();
if (read_cpuid_mpidr() & MPIDR_MT_BITMASK)
teei_cpu_id = teei_cpu_id_arm82;
else
teei_cpu_id = teei_cpu_id_arm80;
IMSG_DEBUG("begin to create sub_thread.\n");
/* create the switch thread */
teei_switch_task = kthread_create(teei_switch_fn,
NULL, "teei_switch_thread");
if (IS_ERR(teei_switch_task)) {
IMSG_ERROR("create switch thread failed: %ld\n",
PTR_ERR(teei_switch_task));
teei_switch_task = NULL;
goto class_device_destroy;
}
#if !IS_ENABLED(CONFIG_MICROTRUST_DYNAMIC_CORE)
teei_cpus_write_lock();
#ifdef TEEI_SWITCH_BIG_CORE
if (cpu_online(TZ_PREFER_BIND_CORE)) {
current_cpu_id = TZ_PREFER_BIND_CORE;
teei_move_cpu_context(current_cpu_id, 0);
}
#endif
cpumask_set_cpu(get_current_cpuid(), &mask);
set_cpus_allowed_ptr(teei_switch_task, &mask);
teei_cpus_write_unlock();
#endif
set_user_nice(teei_switch_task, MIN_NICE);
wake_up_process(teei_switch_task);
#if !IS_ENABLED(CONFIG_MICROTRUST_DYNAMIC_CORE)
cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
"tee/teei:online",
nq_cpu_up_prep, nq_cpu_down_prep);
#endif /* CONFIG_MICROTRUST_DYNAMIC_CORE */
init_bdrv_comp_fn();
/* create the backward handler thread */
teei_bdrv_task = kthread_create(teei_bdrv_fn,
NULL, "teei_bdrv_thread");
if (IS_ERR(teei_bdrv_task)) {
IMSG_ERROR("create bdrv thread failed: %ld\n",
PTR_ERR(teei_bdrv_task));
teei_bdrv_task = NULL;
goto teei_switch_destroy;
}
param.sched_priority = 51;
sched_setscheduler_nocheck(teei_bdrv_task, SCHED_FIFO, &param);
wake_up_process(teei_bdrv_task);
init_tlog_comp_fn();
/* create the teei log thread */
teei_log_task = kthread_create(teei_log_fn, NULL, "teei_log_thread");
if (IS_ERR(teei_log_task)) {
IMSG_ERROR("create teei log thread failed: %ld\n",
PTR_ERR(teei_log_task));
teei_log_task = NULL;
goto teei_bdrv_destroy;
}
wake_up_process(teei_log_task);
IMSG_DEBUG("create the sub_thread successfully!\n");
ret_code = teei_vfs_init();
if (ret_code != 0) {
IMSG_ERROR("Can NOT init the teei_vfs %d!\n", ret_code);
goto teei_log_destroy;
}
ret_code = teei_tee_init();
if (ret_code != 0) {
IMSG_ERROR("Can NOT init the teei_tee %d!\n", ret_code);
goto uninit_teei_vfs;
}
ret_code = soter_driver_init();
if (ret_code != 0) {
IMSG_ERROR("Can NOT init the soter_driver %d!\n", ret_code);
goto uninit_teei_tee;
}
ret_code = teei_keymaster_init();
if (ret_code != 0) {
IMSG_ERROR("Can NOT init the teei_keymaster %d!\n", ret_code);
goto uninit_soter_driver;
}
ret_code = teei_fp_init();
if (ret_code != 0) {
IMSG_ERROR("Can NOT init the teei_fp %d!\n", ret_code);
goto uninit_teei_keymaster;
}
ret_code = teei_config_init();
if (ret_code != 0) {
IMSG_ERROR("Can NOT init the teei_config %d!\n", ret_code);
goto uninit_teei_fp;
}
ret_code = init_sysfs(g_teei_pdev);
if (ret_code < 0) {
IMSG_ERROR("failed to init tz_driver sysfs %d!\n", ret_code);
goto uninit_teei_fp;
}
goto return_fn;
uninit_teei_fp:
teei_fp_exit();
uninit_teei_keymaster:
teei_keymaster_exit();
uninit_soter_driver:
soter_driver_exit();
uninit_teei_tee:
teei_tee_exit();
uninit_teei_vfs:
teei_vfs_exit();
teei_log_destroy:
kthread_stop(teei_log_task);
teei_bdrv_destroy:
kthread_stop(teei_bdrv_task);
teei_switch_destroy:
kthread_stop(teei_switch_task);
class_device_destroy:
device_destroy(driver_class, teei_client_device_no);
class_destroy:
class_destroy(driver_class);
unregister_chrdev_region:
unregister_chrdev_region(teei_client_device_no, 1);
tz_log_remove(tz_drv_state->tz_log_pdev);
del_pdev:
platform_device_del(tz_drv_state->tz_log_pdev);
failed_alloc_dev:
//platform_device_put(tz_drv_state->tz_log_pdev);
mutex_destroy(&tz_drv_state->smc_lock);
kfree(tz_drv_state);
return_fn:
return ret_code;
}
/**
* @brief
*/
static void teei_client_exit(void)
{
IMSG_INFO("teei_client exit");
teei_fp_exit();
teei_keymaster_exit();
soter_driver_exit();
soter_driver_exit();
teei_vfs_exit();
kthread_stop(teei_log_task);
kthread_stop(teei_bdrv_task);
kthread_stop(teei_switch_task);
device_destroy(driver_class, teei_client_device_no);
class_destroy(driver_class);
unregister_chrdev_region(teei_client_device_no, 1);
platform_driver_unregister(&teei_driver);
if (tz_drv_state) {
tz_log_remove(tz_drv_state->tz_log_pdev);
platform_device_del(tz_drv_state->tz_log_pdev);
//platform_device_put(tz_drv_state->tz_log_pdev);
mutex_destroy(&tz_drv_state->smc_lock);
kfree(tz_drv_state);
}
}
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("TEEI <www.microtrust.com>");
MODULE_DESCRIPTION("TEEI Agent");
MODULE_VERSION("1.00");
module_init(teei_client_init);
module_exit(teei_client_exit);