// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015-2019, MICROTRUST Incorporated * All Rights Reserved. * */ #define IMSG_TAG "[tz_driver]" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TEEI_SWITCH_BIG_CORE #ifdef TEEI_FIND_PREFER_CORE_AUTO #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "tz_log.h" #include #include #include #include #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(¶m, (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, ¶m, 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, ¶m); 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 "); MODULE_DESCRIPTION("TEEI Agent"); MODULE_VERSION("1.00"); module_init(teei_client_init); module_exit(teei_client_exit);