From bfafccac8628c0245a355aa9129ecb1a4c123620 Mon Sep 17 00:00:00 2001 From: wangxing45 Date: Mon, 3 Jul 2023 15:06:38 +0800 Subject: [PATCH] update tzdriver to itrustee 7.3.0 --- Makefile | 29 +- auth/auth_base_impl.c | 38 +- auth/auth_base_impl.h | 33 ++ auth/client_hash_auth.c | 29 +- core/agent.c | 304 ++++++++++------ core/agent.h | 27 +- core/amc_abi.h | 20 ++ core/amc_call.h | 39 ++ core/cmdmonitor.c | 72 +++- core/cmdmonitor.h | 14 +- core/gp_ops.c | 84 +---- core/gp_ops.h | 7 - core/mailbox_mempool.c | 441 +++++++++++++++-------- core/mailbox_mempool.h | 5 + core/reserved_mempool.c | 10 +- core/session_manager.c | 141 ++++++-- core/session_manager.h | 2 +- core/shared_mem.c | 142 +++++++- core/shared_mem.h | 15 + core/smc_abi.c | 91 +++++ core/smc_smp.c | 498 ++++++++++---------------- core/smc_smp.h | 33 +- core/tc_client_driver.c | 210 ++++++++--- core/tc_client_driver.h | 13 +- core/tc_cvm_driver.c | 139 +++++++ core/tee_compat_check.c | 56 ++- core/tee_compat_check.h | 8 +- core/tee_info.c | 41 +++ core/tee_info.h | 22 ++ core/tee_portal.c | 267 ++++++++++++++ core/tee_portal.h | 22 ++ core/tz_pm.c | 110 +----- core/tz_spi_notify.c | 13 +- core/tz_spi_notify.h | 1 - tzdriver_internal/tee_reboot/reboot.c | 433 ++++++++++++++++++++++ tzdriver_internal/tee_reboot/reboot.h | 81 +++++ 36 files changed, 2586 insertions(+), 904 deletions(-) create mode 100644 core/amc_abi.h create mode 100644 core/amc_call.h create mode 100644 core/smc_abi.c create mode 100644 core/tc_cvm_driver.c create mode 100644 core/tee_info.c create mode 100644 core/tee_info.h create mode 100644 core/tee_portal.c create mode 100644 core/tee_portal.h create mode 100644 tzdriver_internal/tee_reboot/reboot.c create mode 100644 tzdriver_internal/tee_reboot/reboot.h diff --git a/Makefile b/Makefile index acbcc68..030b138 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,29 @@ # when compile ko, you need to rename this file as Makefile, cos scripts of linux only recognize Makefile obj-m := tzdriver.o +CONFIG_FFA_SUPPORT := 0 +CONFIG_TEE_TELEPORT_SUPPORT := y +CONFIG_CONFIDENTIAL_CONTAINER ?= y tzdriver-objs := core/smc_smp.o core/tc_client_driver.o core/session_manager.o core/mailbox_mempool.o core/teek_app_load.o -tzdriver-objs += core/agent.o core/gp_ops.o core/mem.o core/cmdmonitor.o core/tz_spi_notify.o core/tz_pm.o core/tee_compat_check.o +tzdriver-objs += core/agent.o core/gp_ops.o core/mem.o core/cmdmonitor.o core/tzdebug.o core/tz_spi_notify.o core/tz_pm.o core/tee_compat_check.o tzdriver-objs += auth/auth_base_impl.o auth/client_hash_auth.o tlogger/tlogger.o tlogger/log_pages_cfg.o ko_adapt.o tzdriver-objs += core/reserved_mempool.o tzdriver_internal/tee_trace_event/tee_trace_event.o tzdriver_internal/tee_trace_event/tee_trace_interrupt.o -tzdriver-objs += core/shared_mem.o +tzdriver-objs += core/shared_mem.o core/smc_abi.o +tzdriver-objs += core/tee_info.o +tzdriver-objs += tzdriver_internal/tee_reboot/reboot.o + +ifeq ($(CONFIG_TEE_TELEPORT_SUPPORT), y) +tzdriver-objs += core/tee_portal.o +EXTRA_CFLAGS += -DCONFIG_TEE_TELEPORT_SUPPORT -DCONFIG_TEE_TELEPORT_AUTH +EXTRA_CFLAGS += -DTEE_TELEPORT_PATH_UID_AUTH_CTX=\"/usr/bin/tee_teleport:0\" +tzdriver-objs += core/tc_cvm_driver.o +endif + +ifeq ($(CONFIG_CONFIDENTIAL_CONTAINER), y) +EXTRA_CFLAGS += -DCONFIG_CONFIDENTIAL_CONTAINER -DCONFIG_TEE_AGENTD_AUTH +EXTRA_CFLAGS += -DTEE_AGENTD_PATH_UID_AUTH_CTX=\"/usr/bin/agentd:0\" +tzdriver-objs += core/tc_cvm_driver.o +endif RESULT := $(shell cat /proc/kallsyms | grep vsnprintf_s) @@ -25,11 +43,14 @@ EXTRA_CFLAGS += -isystem /usr/lib/gcc/aarch64-linux-gnu/10.3.1/include EXTRA_CFLAGS += -fstack-protector-strong -DCONFIG_TEELOG -DCONFIG_TZDRIVER_MODULE -DCONFIG_TEECD_AUTH -DCONFIG_PAGES_MEM=y -DCONFIG_CLOUDSERVER_TEECD_AUTH EXTRA_CFLAGS += -I$(PWD)/libboundscheck/include/ -I$(PWD) -I$(PWD)/auth -I$(PWD)/core -I$(PWD)/tzdriver_internal/tee_trace_event EXTRA_CFLAGS += -I$(PWD)/tlogger -I$(PWD)/tzdriver_internal/kthread_affinity -I$(PWD)/tzdriver_internal/include -EXTRA_CFLAGS += -DCONFIG_CPU_AFF_NR=0 -DCONFIG_BIG_SESSION=1000 -DCONFIG_NOTIFY_PAGE_ORDER=4 -DCONFIG_512K_LOG_PAGES_MEM -DCONFIG_TEE_TRACE +EXTRA_CFLAGS += -DCONFIG_CPU_AFF_NR=0 -DCONFIG_BIG_SESSION=100 -DCONFIG_NOTIFY_PAGE_ORDER=4 -DCONFIG_512K_LOG_PAGES_MEM -DCONFIG_TEE_TRACE EXTRA_CFLAGS += -DCONFIG_TEE_LOG_ACHIVE_PATH=\"/var/log/tee/last_teemsg\" -EXTRA_CFLAGS += -DNOT_TRIGGER_AP_RESET -DLAST_TEE_MSG_ROOT_GID -DCONFIG_NOCOPY_SHAREDMEM +EXTRA_CFLAGS += -DNOT_TRIGGER_AP_RESET -DLAST_TEE_MSG_ROOT_GID -DCONFIG_NOCOPY_SHAREDMEM -DCONFIG_TA_AFFINITY=y -DCONFIG_TA_AFFINITY_CPU_NUMS=128 EXTRA_CFLAGS += -DTEECD_PATH_UID_AUTH_CTX=\"/usr/bin/teecd:0\" EXTRA_CFLAGS += -DCONFIG_AUTH_SUPPORT_UNAME -DCONFIG_AUTH_HASH -std=gnu99 +EXTRA_CFLAGS += -DCONFIG_TEE_UPGRADE -DCONFIG_TEE_REBOOT -DCONFIG_CONFIDENTIAL_TEE +EXTRA_CFLAGS += -I$(PWD)/tzdriver_internal/tee_reboot +EXTRA_CFLAGS += -DMAILBOX_POOL_COUNT=8 all: make -C $(KDIR) M=$(PWD) modules clean: diff --git a/auth/auth_base_impl.c b/auth/auth_base_impl.c index 9c93851..f3479e0 100644 --- a/auth/auth_base_impl.c +++ b/auth/auth_base_impl.c @@ -213,10 +213,12 @@ int calc_task_hash(unsigned char *digest, uint32_t dig_len, if (!mm) { if (memset_s(digest, dig_len, 0, MAX_SHA_256_SZ)) return -EFAULT; + tlogi("kernel proc need not check\n"); return EOK; } if (pub_key_len != sizeof(uint32_t)) { + tloge("apk need not check\n"); mmput(mm); return EOK; } @@ -279,6 +281,7 @@ static int check_proc_uid_path(const char *auth_ctx) pro_dpath = get_proc_dpath(k_path, MAX_PATH_SIZE); if (IS_ERR_OR_NULL(pro_dpath)) { kfree(k_path); + tloge("dpath is null\n"); return CHECK_ACCESS_FAIL; } @@ -297,7 +300,7 @@ static int check_proc_uid_path(const char *auth_ctx) goto clean; } - if (strncmp(str_path_uid, auth_ctx, auth_ctx_len) != 0) + if (strnlen(str_path_uid, MAX_PATH_SIZE) != auth_ctx_len || strncmp(str_path_uid, auth_ctx, auth_ctx_len) != 0) ret = ENTER_BYPASS_CHANNEL; else ret = CHECK_ACCESS_SUCC; @@ -309,6 +312,15 @@ clean: return ret; } +int check_hidl_auth(void) +{ + int ret = check_proc_uid_path(CA_HIDL_PATH_UID_AUTH_CTX); + if (ret != CHECK_ACCESS_SUCC) + return ret; + + return CHECK_ACCESS_SUCC; +} + #ifdef CONFIG_TEECD_AUTH int check_teecd_auth(void) { @@ -326,3 +338,27 @@ int check_teecd_auth(void) return 0; } #endif + +#ifdef CONFIG_TEE_TELEPORT_AUTH +int check_tee_teleport_auth(void) +{ + int ret = check_proc_uid_path(TEE_TELEPORT_PATH_UID_AUTH_CTX); + if (ret != 0) { + tlogd("check tee_teleport path failed, ret %d\n", ret); + return ret; + } + return CHECK_ACCESS_SUCC; +} +#endif + +#ifdef CONFIG_TEE_AGENTD_AUTH +int check_tee_agentd_auth(void) +{ + int ret = check_proc_uid_path(TEE_AGENTD_PATH_UID_AUTH_CTX); + if (ret != 0) { + tloge("check agentd path failed, ret %d\n", ret); + return ret; + } + return CHECK_ACCESS_SUCC; +} +#endif diff --git a/auth/auth_base_impl.h b/auth/auth_base_impl.h index 3d8d8ae..fe8da14 100644 --- a/auth/auth_base_impl.h +++ b/auth/auth_base_impl.h @@ -18,10 +18,34 @@ #ifndef AUTH_BASE_IMPL_H #define AUTH_BASE_IMPL_H +#ifndef SELINUX_CA_HIDL_LABEL +#define SELINUX_CA_HIDL_LABEL "" +#endif + +#ifndef SELINUX_TEECD_LABEL +#define SELINUX_TEECD_LABEL "" +#endif + +#ifndef SELINUX_TEE_TELEPORT_LABEL +#define SELINUX_TEE_TELEPORT_LABEL "" +#endif + +#ifndef SELINUX_TEE_AGENTD_LABEL +#define SELINUX_TEE_AGENTD_LABEL "" +#endif + +#ifndef CA_HIDL_PATH_UID_AUTH_CTX +#define CA_HIDL_PATH_UID_AUTH_CTX "" +#endif + #ifndef TEECD_PATH_UID_AUTH_CTX #define TEECD_PATH_UID_AUTH_CTX "" #endif +#ifndef CADAEMON_PATH_UID_AUTH_CTX +#define CADAEMON_PATH_UID_AUTH_CTX "" +#endif + #if ((defined CONFIG_CLIENT_AUTH) || (defined CONFIG_TEECD_AUTH)) #include #if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE) @@ -58,6 +82,7 @@ struct crypto_shash *get_shash_handle(void); void init_crypto_hash_lock(void); void mutex_crypto_hash_lock(void); void mutex_crypto_hash_unlock(void); +int check_hidl_auth(void); int check_teecd_auth(void); #else @@ -78,4 +103,12 @@ int check_teecd_auth(void) #endif /* CLIENT_AUTH || TEECD_AUTH */ +#ifdef CONFIG_TEE_TELEPORT_AUTH +int check_tee_teleport_auth(void); +#endif + +#ifdef CONFIG_TEE_AGENTD_AUTH +int check_tee_agentd_auth(void); +#endif + #endif diff --git a/auth/client_hash_auth.c b/auth/client_hash_auth.c index a407eb4..d46e46a 100644 --- a/auth/client_hash_auth.c +++ b/auth/client_hash_auth.c @@ -54,7 +54,10 @@ struct sdesc_hash { #define DEFAULT_TEXT_OFF 0 #define LIBTEEC_NAME_MAX_LEN 50 -const char g_libso[KIND_OF_SO][LIBTEEC_NAME_MAX_LEN] = {"libteec_vendor.so"}; +const char g_libso[KIND_OF_SO][LIBTEEC_NAME_MAX_LEN] = { + "libteec_vendor.so", + "libteec.huawei.so", +}; static int find_lib_code_area(struct mm_struct *mm, struct vm_area_struct **lib_code_area, int so_index) @@ -295,7 +298,7 @@ static struct sdesc_hash *init_sdesc(struct crypto_shash *alg) size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); sdesc = kmalloc(size, GFP_KERNEL); - if (sdesc == NULL) + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)(sdesc))) return ERR_PTR(-ENOMEM); sdesc->shash.tfm = alg; return sdesc; @@ -428,7 +431,7 @@ static int uid_compare(uint32_t uid, const char* uid_str, uint32_t uid_len) } /* "username:[encrypted password]:uid:gid:[comments]:home directory:login shell" */ -static uint32_t parse_uname(uint32_t uid, char *username, int buffer_len) +static int32_t parse_uname(uint32_t uid, char *username, int buffer_len) { char *str = username; char *token = strsep(&str, ":"); @@ -448,24 +451,16 @@ static uint32_t parse_uname(uint32_t uid, char *username, int buffer_len) } static int read_line(char *buf, int buf_len, struct file *fp, loff_t *offset) { - ssize_t ret; - ssize_t i; if (offset == NULL) { tloge("offset is null while read file\n"); return -1; } - ret = kernel_read(fp, buf, buf_len, offset); + ssize_t ret = kernel_read(fp, buf, buf_len, offset); if (ret < 0) return -1; - i = 0; + ssize_t i = 0; /* read buf_len, need to find first '\n' */ - while(i < ret) { - if (i >= buf_len) - break; - if (buf[i] == '\n') - break; - i++; - } + while(buf[i++] != '\n' && i < ret); if (i < ret) *offset -= (loff_t)(ret - i); if (i < buf_len) @@ -480,19 +475,19 @@ static int read_line(char *buf, int buf_len, struct file *fp, loff_t *offset) */ int tc_ns_get_uname(uint32_t uid, char *username, int buffer_len, uint32_t *out_len) { - struct file *f = NULL; - loff_t offset = 0; if (username == NULL || out_len == NULL || buffer_len != FIXED_PKG_NAME_LENGTH) { tloge("params is null\n"); return -1; } + struct file *f = NULL; + loff_t offset = 0; f = filp_open(PASSWD_FILE, O_RDONLY, 0); if (IS_ERR(f)) { tloge("kernel open passwd file failed\n"); return -1; } while (read_line(username, buffer_len, f, &offset) == 0) { - uint32_t ret = parse_uname(uid, username, buffer_len); + int32_t ret = parse_uname(uid, username, buffer_len); if (ret >= 0) { *out_len = ret; filp_close(f, NULL); diff --git a/core/agent.c b/core/agent.c index b5d0f37..8d0408b 100644 --- a/core/agent.c +++ b/core/agent.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE) @@ -69,8 +70,14 @@ struct agent_control { struct list_head agent_list; }; +struct agent_pair { + uint32_t agent_id; + uint32_t nsid; +}; + static struct agent_control g_agent_control; +static void process_send_event_response(struct smc_event_data *event_data); int __attribute__((weak)) is_allowed_agent_ca(const struct ca_info *ca, bool check_agent_id) { @@ -129,6 +136,7 @@ char *get_proc_dpath(char *path, int path_len) path_get(&base_path); dpath = d_path(&base_path, path, MAX_PATH_SIZE); path_put(&base_path); + fput(exe_file); mmput(mm); return dpath; @@ -248,7 +256,7 @@ int tc_ns_set_native_hash(unsigned long arg, unsigned int cmd_id) ret = check_teecd_auth(); if (ret != 0) { - tloge("teecd auth failed, ret %d\n", ret); + tloge("teecd or cadaemon auth failed, ret %d\n", ret); return -EACCES; } @@ -315,12 +323,14 @@ int tc_ns_late_init(unsigned long arg) return ret; } -void send_event_response_single(const struct tc_ns_dev_file *dev_file) +void send_crashed_event_response_single(const struct tc_ns_dev_file *dev_file) { struct smc_event_data *event_data = NULL; struct smc_event_data *tmp = NULL; unsigned long flags; unsigned int agent_id = 0; + unsigned int nsid = PROC_PID_INIT_INO; + bool need_unreg = false; if (!dev_file) return; @@ -330,15 +340,23 @@ void send_event_response_single(const struct tc_ns_dev_file *dev_file) head) { if (event_data->owner == dev_file) { agent_id = event_data->agent_id; + nsid = event_data->nsid; + event_data->agent_buff_user = NULL; + need_unreg = !(atomic_read(&event_data->agent_ready) == AGENT_PENDING) && + !(atomic_read(&event_data->agent_ready) == AGENT_UNREGISTERED); break; } } spin_unlock_irqrestore(&g_agent_control.lock, flags); - send_event_response(agent_id); + + if (nsid != PROC_PID_INIT_INO && need_unreg) + (void)tc_ns_unregister_agent(agent_id, nsid); + + send_event_response(agent_id, nsid); return; } -struct smc_event_data *find_event_control(unsigned int agent_id) +struct smc_event_data *find_event_control(unsigned int agent_id, unsigned int nsid) { struct smc_event_data *event_data = NULL; struct smc_event_data *tmp_data = NULL; @@ -346,7 +364,7 @@ struct smc_event_data *find_event_control(unsigned int agent_id) spin_lock_irqsave(&g_agent_control.lock, flags); list_for_each_entry(event_data, &g_agent_control.agent_list, head) { - if (event_data->agent_id == agent_id) { + if (event_data->agent_id == agent_id && event_data->nsid == nsid) { tmp_data = event_data; get_agent_event(event_data); break; @@ -374,43 +392,38 @@ static void unmap_agent_buffer(struct smc_event_data *event_data) event_data->agent_buff_user = NULL; } -static void free_event_control(unsigned int agent_id) +static void free_event_control(struct smc_event_data *event_data) { - struct smc_event_data *event_data = NULL; - struct smc_event_data *tmp_event = NULL; unsigned long flags; - bool find = false; + if (event_data == NULL) + return; spin_lock_irqsave(&g_agent_control.lock, flags); - list_for_each_entry_safe(event_data, tmp_event, - &g_agent_control.agent_list, head) { - if (event_data->agent_id == agent_id) { - list_del(&event_data->head); - find = true; - break; - } - } + list_del(&event_data->head); spin_unlock_irqrestore(&g_agent_control.lock, flags); - if (!find) - return; - - unmap_agent_buffer(event_data); mailbox_free(event_data->agent_buff_kernel); event_data->agent_buff_kernel = NULL; + atomic_set(&event_data->agent_ready, AGENT_UNREGISTERED); put_agent_event(event_data); } static int init_agent_context(unsigned int agent_id, + unsigned int nsid, const struct tc_ns_smc_cmd *smc_cmd, struct smc_event_data **event_data) { - *event_data = find_event_control(agent_id); + *event_data = find_event_control(agent_id, nsid); if (!(*event_data)) { - tloge("agent %u not exist\n", agent_id); + tloge("agent 0x%x nsid 0x%x not exist\n", agent_id, nsid); return -EINVAL; } - tlogd("agent-0x%x: returning client command", agent_id); + tlogd("agent-0x%x nsid 0x%x: returning client command", agent_id, nsid); + + if (is_tui_agent(agent_id)) { + tloge("TEE_TUI_AGENT_ID: pid-%d", current->pid); + set_tui_caller_info(smc_cmd->dev_file_id, current->pid); + } isb(); wmb(); @@ -482,7 +495,7 @@ wait agent response\n"); } int agent_process_work(const struct tc_ns_smc_cmd *smc_cmd, - unsigned int agent_id) + unsigned int agent_id, unsigned int nsid) { struct smc_event_data *event_data = NULL; int ret; @@ -492,24 +505,38 @@ int agent_process_work(const struct tc_ns_smc_cmd *smc_cmd, return -EINVAL; } - if (init_agent_context(agent_id, smc_cmd, &event_data)) + if (init_agent_context(agent_id, nsid, smc_cmd, &event_data)) return -EINVAL; - if (atomic_read(&event_data->agent_ready) == AGENT_CRASHED) { - tloge("agent 0x%x is killed and restarting\n", agent_id); + if (atomic_read(&event_data->agent_ready) == AGENT_CRASHED || + atomic_read(&event_data->agent_ready) == AGENT_UNREGISTERED) { + tloge("agent 0x%x nsid 0x%x is killed and restarting\n", agent_id, nsid); put_agent_event(event_data); return -EFAULT; } + + if (smc_cmd->cmd_type == CMD_TYPE_RELEASE_AGENT && + atomic_read(&event_data->agent_ready) == AGENT_PENDING) { + tlogi("agent 0x%x nsid 0x%x is ready to release\n", agent_id, nsid); + + free_event_control(event_data); + put_agent_event(event_data); + ret = 0; + goto reset_context; + } + event_data->ret_flag = 1; /* Wake up the agent that will process the command */ tlogd("agent process work: wakeup the agent"); wake_up(&event_data->wait_event_wq); - tlogd("agent 0x%x request, goto sleep, pe->run=%d\n", - agent_id, atomic_read(&event_data->ca_run)); + tlogd("agent 0x%x nsid 0x%x request, goto sleep, pe->run=%d\n", + agent_id, nsid, atomic_read(&event_data->ca_run)); ret = wait_agent_response(event_data); atomic_set(&event_data->ca_run, 0); put_agent_event(event_data); + +reset_context: /* * when agent work is done, reset cmd monitor time * add agent call count, cause it's a new smc cmd. @@ -518,12 +545,18 @@ int agent_process_work(const struct tc_ns_smc_cmd *smc_cmd, return ret; } -int is_agent_alive(unsigned int agent_id) +int is_agent_alive(unsigned int agent_id, unsigned int nsid) { struct smc_event_data *event_data = NULL; - event_data = find_event_control(agent_id); + event_data = find_event_control(agent_id, nsid); if (event_data) { + if (atomic_read(&event_data->agent_ready) == AGENT_CRASHED || + atomic_read(&event_data->agent_ready) == AGENT_PENDING || + atomic_read(&event_data->agent_ready) == AGENT_UNREGISTERED) { + put_agent_event(event_data); + return AGENT_DEAD; + } put_agent_event(event_data); return AGENT_ALIVE; } @@ -531,22 +564,30 @@ int is_agent_alive(unsigned int agent_id) return AGENT_DEAD; } -int tc_ns_wait_event(unsigned int agent_id) +int tc_ns_wait_event(unsigned int agent_id, unsigned int nsid) { int ret = -EINVAL; struct smc_event_data *event_data = NULL; - tlogd("agent %u waits for command\n", agent_id); + tlogd("agent 0x%x nsid 0x%x waits for command\n", agent_id, nsid); - event_data = find_event_control(agent_id); - if (event_data) { - /* only when agent wait event, it's in ready state to work */ - atomic_set(&(event_data->agent_ready), AGENT_READY); - ret = wait_event_interruptible(event_data->wait_event_wq, - event_data->ret_flag); + event_data = find_event_control(agent_id, nsid); + if (!event_data) + return ret; + + if (atomic_read(&event_data->agent_ready) != AGENT_READY) { + tlogd("agent 0x%x nsid 0x%x is not in registered status\n", agent_id, nsid); put_agent_event(event_data); + return ret; } + ret = wait_event_interruptible(event_data->wait_event_wq, + event_data->ret_flag); + put_agent_event(event_data); + + if (is_tee_rebooting()) + ret = -EINVAL; + return ret; } @@ -625,17 +666,6 @@ void sync_system_time_from_kernel(void) return; } -static struct smc_event_data *check_response_access(unsigned int agent_id) -{ - struct smc_event_data *event_data = find_event_control(agent_id); - - if (!event_data) { - tloge("Can't get event_data\n"); - return NULL; - } - return event_data; -} - static void process_send_event_response(struct smc_event_data *event_data) { if (event_data->ret_flag == 0) @@ -649,33 +679,44 @@ static void process_send_event_response(struct smc_event_data *event_data) wake_up(&event_data->ca_pending_wq); } -int tc_ns_send_event_response(unsigned int agent_id) +int tc_ns_send_event_response(unsigned int agent_id, unsigned int nsid) { struct smc_event_data *event_data = NULL; - event_data = check_response_access(agent_id); + event_data = find_event_control(agent_id, nsid); if (!event_data) { - tlogd("agent %u pre-check failed\n", agent_id); + tlogd("agent 0x%x nsid 0x%x pre-check failed\n", agent_id, nsid); return -EINVAL; } - tlogd("agent %u sends answer back\n", agent_id); + if (atomic_read(&event_data->agent_ready) != AGENT_READY) { + tlogd("agent 0x%x nsid 0x%x is not in registered status\n", agent_id, nsid); + put_agent_event(event_data); + return -EINVAL; + } + + tlogd("agent 0x%x nsid 0x%x sends answer back\n", agent_id, nsid); process_send_event_response(event_data); put_agent_event(event_data); return 0; } -void send_event_response(unsigned int agent_id) +void send_event_response(unsigned int agent_id, unsigned int nsid) { - struct smc_event_data *event_data = find_event_control(agent_id); + struct smc_event_data *event_data = find_event_control(agent_id, nsid); if (!event_data) { - tloge("Can't get event_data\n"); + tlogd("Can't get event_data\n"); return; } - tlogi("agent 0x%x sends answer back\n", agent_id); + if (atomic_read(&event_data->agent_ready) == AGENT_PENDING) { + put_agent_event(event_data); + return; + } + + tlogi("agent 0x%x nsid 0x%x sends answer back\n", agent_id, nsid); atomic_set(&event_data->agent_ready, AGENT_CRASHED); process_send_event_response(event_data); put_agent_event(event_data); @@ -687,7 +728,6 @@ static void init_restart_agent_node(struct tc_ns_dev_file *dev_file, tlogi("agent: 0x%x restarting\n", event_data->agent_id); event_data->ret_flag = 0; event_data->owner = dev_file; - atomic_set(&event_data->agent_ready, AGENT_REGISTERED); init_waitqueue_head(&(event_data->wait_event_wq)); init_waitqueue_head(&(event_data->send_response_wq)); init_waitqueue_head(&(event_data->ca_pending_wq)); @@ -695,7 +735,7 @@ static void init_restart_agent_node(struct tc_ns_dev_file *dev_file, } static int create_new_agent_node(struct tc_ns_dev_file *dev_file, - struct smc_event_data **event_data, unsigned int agent_id, + struct smc_event_data **event_data, struct agent_pair *agent_pair, void **agent_buff, uint32_t agent_buff_size) { *agent_buff = mailbox_alloc(agent_buff_size, MB_FLAG_ZERO); @@ -711,12 +751,12 @@ static int create_new_agent_node(struct tc_ns_dev_file *dev_file, tloge("alloc event data failed\n"); return -ENOMEM; } - (*event_data)->agent_id = agent_id; + (*event_data)->agent_id = agent_pair->agent_id; + (*event_data)->nsid = agent_pair->nsid; (*event_data)->ret_flag = 0; (*event_data)->agent_buff_kernel = *agent_buff; (*event_data)->agent_buff_size = agent_buff_size; (*event_data)->owner = dev_file; - atomic_set(&(*event_data)->agent_ready, AGENT_REGISTERED); init_waitqueue_head(&(*event_data)->wait_event_wq); init_waitqueue_head(&(*event_data)->send_response_wq); INIT_LIST_HEAD(&(*event_data)->head); @@ -775,22 +815,26 @@ static bool is_valid_agent(unsigned int agent_id, return true; } -static int is_agent_already_exist(unsigned int agent_id, - struct smc_event_data **event_data, struct tc_ns_dev_file *dev_file, bool *find_flag) +static int is_agent_already_exist(unsigned int agent_id, unsigned int nsid, + struct smc_event_data **event_data, struct tc_ns_dev_file *dev_file, uint32_t *find_flag) { unsigned long flags; - bool flag = false; + uint32_t flag = AGENT_NO_EXIST; struct smc_event_data *agent_node = NULL; spin_lock_irqsave(&g_agent_control.lock, flags); list_for_each_entry(agent_node, &g_agent_control.agent_list, head) { - if (agent_node->agent_id == agent_id) { - if (atomic_read(&agent_node->agent_ready) != AGENT_CRASHED) { + if (agent_node->agent_id == agent_id && agent_node->nsid == nsid) { + if (atomic_read(&agent_node->agent_ready) != AGENT_CRASHED && + atomic_read(&agent_node->agent_ready) != AGENT_PENDING) { tloge("no allow agent proc to reg twice\n"); spin_unlock_irqrestore(&g_agent_control.lock, flags); return -EINVAL; } - flag = true; + if (atomic_read(&agent_node->agent_ready) == AGENT_CRASHED) + flag = AGENT_HAS_CRASHED; + else + flag = AGENT_READY_TO_UNREG; get_agent_event(agent_node); /* * We find the agent event_data aready in agent_list, it indicate agent @@ -802,7 +846,7 @@ static int is_agent_already_exist(unsigned int agent_id, } spin_unlock_irqrestore(&g_agent_control.lock, flags); *find_flag = flag; - if (flag) + if (flag != AGENT_NO_EXIST) *event_data = agent_node; return 0; } @@ -817,8 +861,8 @@ static void add_event_node_to_list(struct smc_event_data *event_data) spin_unlock_irqrestore(&g_agent_control.lock, flags); } -static int register_agent_to_tee(unsigned int agent_id, const void *agent_buff, - uint32_t agent_buff_size) +static int register_agent_to_tee(unsigned int agent_id, unsigned int nsid, + const void *agent_buff, uint32_t agent_buff_size) { int ret = 0; struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; @@ -843,6 +887,7 @@ static int register_agent_to_tee(unsigned int agent_id, const void *agent_buff, smc_cmd.operation_h_phys = (uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM; smc_cmd.agent_id = agent_id; + smc_cmd.nsid = nsid; if (tc_ns_smc(&smc_cmd)) { ret = -EPERM; @@ -880,9 +925,10 @@ int tc_ns_register_agent(struct tc_ns_dev_file *dev_file, { struct smc_event_data *event_data = NULL; int ret = -EINVAL; - bool find_flag = false; + uint32_t find_flag = AGENT_NO_EXIST; void *agent_buff = NULL; uint32_t size_align; + uint32_t nsid = PROC_PID_INIT_INO; /* dev can be null */ if (!buffer) @@ -892,12 +938,18 @@ int tc_ns_register_agent(struct tc_ns_dev_file *dev_file, return ret; size_align = ALIGN(buffer_size, SZ_4K); +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + nsid = task_active_pid_ns(current)->ns.inum; + if (dev_file != NULL && dev_file->nsid == 0) + dev_file->nsid = nsid; +#endif - if (is_agent_already_exist(agent_id, &event_data, dev_file, &find_flag)) + if (is_agent_already_exist(agent_id, nsid, &event_data, dev_file, &find_flag)) return ret; - if (!find_flag) { + if (find_flag == AGENT_NO_EXIST) { + struct agent_pair agent_pair = { agent_id, nsid }; ret = create_new_agent_node(dev_file, &event_data, - agent_id, &agent_buff, size_align); + &agent_pair, &agent_buff, size_align); if (ret != 0) return ret; } @@ -906,24 +958,26 @@ int tc_ns_register_agent(struct tc_ns_dev_file *dev_file, goto release_rsrc; /* find_flag is false means it's a new agent register */ - if (!find_flag) { + if (find_flag == AGENT_NO_EXIST || find_flag == AGENT_READY_TO_UNREG) { /* * Obtain share memory which is released * in tc_ns_unregister_agent */ - ret = register_agent_to_tee(agent_id, agent_buff, size_align); + ret = register_agent_to_tee(agent_id, nsid, event_data->agent_buff_kernel, size_align); if (ret != 0) { unmap_agent_buffer(event_data); goto release_rsrc; } - add_event_node_to_list(event_data); + if (find_flag == AGENT_NO_EXIST) + add_event_node_to_list(event_data); } - if (find_flag) + atomic_set(&(event_data->agent_ready), AGENT_READY); + if (find_flag != AGENT_NO_EXIST) put_agent_event(event_data); /* match get action */ return 0; release_rsrc: - if (find_flag) + if (find_flag != AGENT_NO_EXIST) put_agent_event(event_data); /* match get action */ else kfree(event_data); /* here event_data can never be NULL */ @@ -933,14 +987,14 @@ release_rsrc: return ret; } -int tc_ns_unregister_agent(unsigned int agent_id) +int tc_ns_unregister_agent(unsigned int agent_id, unsigned int nsid) { struct smc_event_data *event_data = NULL; int ret = 0; struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; struct mb_cmd_pack *mb_pack = NULL; - event_data = find_event_control(agent_id); + event_data = find_event_control(agent_id, nsid); if (!event_data || !event_data->agent_buff_kernel) { tloge("agent is not found or kaddr is not allocated\n"); return -EINVAL; @@ -965,13 +1019,24 @@ int tc_ns_unregister_agent(unsigned int agent_id) smc_cmd.operation_h_phys = (uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM; smc_cmd.agent_id = agent_id; - tlogd("unregistering agent 0x%x\n", agent_id); + smc_cmd.nsid = nsid; - if (tc_ns_smc(&smc_cmd) == 0) { - free_event_control(agent_id); + ret = tc_ns_smc(&smc_cmd); + if (ret == 0) { + unmap_agent_buffer(event_data); + free_event_control(event_data); + tlogi("unregister agent(0x%x, 0x%x) success, and agent buffer is not used in tee\n", + agent_id, nsid); + } else if (ret == TEEC_ERROR_BUSY) { + ret = -EBUSY; + atomic_set(&(event_data->agent_ready), AGENT_PENDING); + unmap_agent_buffer(event_data); + process_send_event_response(event_data); + tlogi("unregister agent(0x%x, 0x%x) success, but agent buffer is used in tee\n", + agent_id, nsid); } else { ret = -EPERM; - tloge("unregister agent failed\n"); + tloge("unregister agent(0x%x, 0x%x) failed\n", agent_id, nsid); } put_agent_event(event_data); mailbox_free(mb_pack); @@ -1006,6 +1071,8 @@ void send_crashed_event_response_all(const struct tc_ns_dev_file *dev_file) struct smc_event_data *event_data = NULL; struct smc_event_data *tmp = NULL; unsigned int agent_id[AGENT_MAX] = {0}; + unsigned int nsids[AGENT_MAX] = {0}; + bool need_unregs[AGENT_MAX] = {false}; unsigned int i = 0; unsigned long flags; @@ -1015,14 +1082,22 @@ void send_crashed_event_response_all(const struct tc_ns_dev_file *dev_file) spin_lock_irqsave(&g_agent_control.lock, flags); list_for_each_entry_safe(event_data, tmp, &g_agent_control.agent_list, head) { - if (event_data->owner == dev_file && i < AGENT_MAX) - agent_id[i++] = event_data->agent_id; + if (event_data->owner == dev_file && i < AGENT_MAX) { + nsids[i] = event_data->nsid; + agent_id[i] = event_data->agent_id; + event_data->agent_buff_user = NULL; + need_unregs[i++] = !(atomic_read(&event_data->agent_ready) == AGENT_PENDING) && + !(atomic_read(&event_data->agent_ready) == AGENT_UNREGISTERED); + } } spin_unlock_irqrestore(&g_agent_control.lock, flags); for (i = 0; i < AGENT_MAX; i++) { - if (agent_id[i] != 0) - send_event_response(agent_id[i]); + if (agent_id[i] == 0) + continue; + if (nsids[i] != PROC_PID_INIT_INO && need_unregs[i]) + (void)tc_ns_unregister_agent(agent_id[i], nsids[i]); + send_event_response(agent_id[i], nsids[i]); } return; @@ -1054,7 +1129,7 @@ static int def_tee_agent_work(void *instance) agent_instance = instance; while (!kthread_should_stop()) { tlogd("%s agent loop++++\n", agent_instance->agent_name); - ret = tc_ns_wait_event(agent_instance->agent_id); + ret = tc_ns_wait_event(agent_instance->agent_id, PROC_PID_INIT_INO); if (ret != 0) { tloge("%s wait event fail\n", agent_instance->agent_name); @@ -1066,7 +1141,7 @@ static int def_tee_agent_work(void *instance) tloge("%s agent work fail\n", agent_instance->agent_name); } - ret = tc_ns_send_event_response(agent_instance->agent_id); + ret = tc_ns_send_event_response(agent_instance->agent_id, PROC_PID_INIT_INO); if (ret != 0) { tloge("%s send event response fail\n", agent_instance->agent_name); @@ -1115,13 +1190,13 @@ static int def_tee_agent_stop(struct tee_agent_kernel_ops *agent_instance) { int ret; - if (tc_ns_send_event_response(agent_instance->agent_id) != 0) - tloge("failed to send response for agent %u\n", - agent_instance->agent_id); - ret = tc_ns_unregister_agent(agent_instance->agent_id); - if (ret != 0) - tloge("failed to unregister agent %u\n", - agent_instance->agent_id); + if (tc_ns_send_event_response(agent_instance->agent_id, PROC_PID_INIT_INO) != 0) + tloge("failed to send response for agent 0x%x nsid 0x%x\n", + agent_instance->agent_id, PROC_PID_INIT_INO); + ret = tc_ns_unregister_agent(agent_instance->agent_id, PROC_PID_INIT_INO); + if (ret == -EPERM) + tloge("failed to unregister agent 0x%x, nsid 0x%x\n", + agent_instance->agent_id, PROC_PID_INIT_INO); if (!IS_ERR_OR_NULL(agent_instance->agent_thread)) kthread_stop(agent_instance->agent_thread); @@ -1275,3 +1350,32 @@ void free_agent(void) } spin_unlock_irqrestore(&g_agent_control.lock, flags); } + +void free_agent_list(void) +{ + struct smc_event_data *event_data = NULL; + struct smc_event_data *tmp_event = NULL; + unsigned long flags; + + while (list_empty(&g_agent_control.agent_list) == 0) { + event_data = NULL; + spin_lock_irqsave(&g_agent_control.lock, flags); + list_for_each_entry_safe(event_data, tmp_event, + &g_agent_control.agent_list, head) { + list_del(&event_data->head); + break; + } + spin_unlock_irqrestore(&g_agent_control.lock, flags); + + if (event_data == NULL) + return; + + event_data->ret_flag = 1; + wake_up(&event_data->wait_event_wq); + + process_send_event_response(event_data); + mailbox_free(event_data->agent_buff_kernel); + event_data->agent_buff_kernel = NULL; + put_agent_event(event_data); + } +} diff --git a/core/agent.h b/core/agent.h index 1902097..1fc1ec8 100644 --- a/core/agent.h +++ b/core/agent.h @@ -37,16 +37,22 @@ enum agent_state_type { AGENT_CRASHED = 0, AGENT_REGISTERED, AGENT_READY, + AGENT_PENDING, + AGENT_UNREGISTERED, }; enum agent_status { - AGENT_ALIVE = 1, AGENT_DEAD = 0, + AGENT_ALIVE = 1, + AGENT_NO_EXIST = 2, + AGENT_HAS_CRASHED = 3, + AGENT_READY_TO_UNREG = 4, }; /* for secure agent */ struct smc_event_data { unsigned int agent_id; + unsigned int nsid; atomic_t agent_ready; wait_queue_head_t wait_event_wq; int ret_flag; /* indicate whether agent is returned from TEE */ @@ -106,19 +112,20 @@ int is_allowed_agent_ca(const struct ca_info *ca, bool check_agent_id); void agent_init(void); void free_agent(void); -struct smc_event_data *find_event_control(unsigned int agent_id); -void send_event_response(unsigned int agent_id); -int agent_process_work(const struct tc_ns_smc_cmd *smc_cmd, unsigned int agent_id); -int is_agent_alive(unsigned int agent_id); +struct smc_event_data *find_event_control(unsigned int agent_id, unsigned int nsid); +void send_event_response(unsigned int agent_id, unsigned int nsid); +int agent_process_work(const struct tc_ns_smc_cmd *smc_cmd, + unsigned int agent_id, unsigned int nsid); +int is_agent_alive(unsigned int agent_id, unsigned int nsid); int tc_ns_set_native_hash(unsigned long arg, unsigned int cmd_id); int tc_ns_late_init(unsigned long arg); int tc_ns_register_agent(struct tc_ns_dev_file *dev_file, unsigned int agent_id, unsigned int buffer_size, void **buffer, bool user_agent); -int tc_ns_unregister_agent(unsigned int agent_id); +int tc_ns_unregister_agent(unsigned int agent_id, unsigned int nsid); void send_crashed_event_response_all(const struct tc_ns_dev_file *dev_file); -int tc_ns_wait_event(unsigned int agent_id); -int tc_ns_send_event_response(unsigned int agent_id); -void send_event_response_single(const struct tc_ns_dev_file *dev_file); +int tc_ns_wait_event(unsigned int agent_id, unsigned int nsid); +int tc_ns_send_event_response(unsigned int agent_id, unsigned int nsid); +void send_crashed_event_response_single(const struct tc_ns_dev_file *dev_file); int sync_system_time_from_user(const struct tc_ns_client_time *user_time); void sync_system_time_from_kernel(void); int tee_agent_clear_work(struct tc_ns_client_context *context, @@ -128,4 +135,6 @@ bool is_system_agent(const struct tc_ns_dev_file *dev_file); void tee_agent_clear_dev_owner(const struct tc_ns_dev_file *dev_file); char *get_proc_dpath(char *path, int path_len); int check_ext_agent_access(uint32_t agent_id); +void free_agent_list(void); + #endif diff --git a/core/amc_abi.h b/core/amc_abi.h new file mode 100644 index 0000000..da4dbdf --- /dev/null +++ b/core/amc_abi.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef SMC_ABI_H +#define SMC_ABI_H + +#include "smc_call.h" +#define TEE_EXIT_REASON_CRASH 0x4 +void do_smc_transport(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait); +#endif diff --git a/core/amc_call.h b/core/amc_call.h new file mode 100644 index 0000000..4d2d1fa --- /dev/null +++ b/core/amc_call.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef SMC_CALL_H +#define SMC_CALL_H + +#include + +struct smc_in_params { + unsigned long x0; + unsigned long x1; + unsigned long x2; + unsigned long x3; + unsigned long x4; + unsigned long x5; + unsigned long x6; + unsigned long x7; +}; + +struct smc_out_params { + unsigned long ret; + unsigned long exit_reason; + unsigned long ta; + unsigned long target; +}; + +void smc_req(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait); + +#endif diff --git a/core/cmdmonitor.c b/core/cmdmonitor.c index aeb158f..431e379 100644 --- a/core/cmdmonitor.c +++ b/core/cmdmonitor.c @@ -41,7 +41,7 @@ static int g_cmd_need_archivelog; static LIST_HEAD(g_cmd_monitor_list); static int g_cmd_monitor_list_size; - +static const long long g_memstat_report_freq = 2 * 60 * 60 * 1000; #define MAX_CMD_MONITOR_LIST 200 #define MAX_AGENT_CALL_COUNT 250 static DEFINE_MUTEX(g_cmd_monitor_lock); @@ -51,6 +51,7 @@ static struct workqueue_struct *g_cmd_monitor_wq; static struct delayed_work g_cmd_monitor_work; static struct delayed_work g_cmd_monitor_work_archive; static int g_tee_detect_ta_crash; +static struct tc_uuid g_crashed_ta_uuid; void get_time_spec(struct time_spec *time) { @@ -76,14 +77,21 @@ static void tz_archivelog(void) { schedule_cmd_monitor_work(&g_cmd_monitor_work_archive, usecs_to_jiffies(0)); + flush_delayed_work(&g_cmd_monitor_work_archive); } -void cmd_monitor_ta_crash(int32_t type) +void cmd_monitor_ta_crash(int32_t type, const uint8_t *ta_uuid, uint32_t uuid_len) { - g_tee_detect_ta_crash = ((type == TYPE_CRASH_TEE) ? - TYPE_CRASH_TEE : TYPE_CRASH_TA); + g_tee_detect_ta_crash = type; + if (g_tee_detect_ta_crash != TYPE_CRASH_TEE && + ta_uuid != NULL && uuid_len == sizeof(struct tc_uuid)) { + if (memcpy_s(&g_crashed_ta_uuid, sizeof(g_crashed_ta_uuid), + ta_uuid, uuid_len) != EOK) + tloge("copy uuid failed when get ta crash\n"); + } tz_archivelog(); fault_monitor_start(type); + kbox_report(type, ta_uuid, uuid_len); } static int get_pid_name(pid_t pid, char *comm, size_t size) @@ -97,21 +105,21 @@ static int get_pid_name(pid_t pid, char *comm, size_t size) rcu_read_lock(); #ifndef CONFIG_TZDRIVER_MODULE - task = find_task_by_vpid(pid); + task = find_task_by_pid_ns(pid, &init_pid_ns); #else - task = pid_task(find_vpid(pid), PIDTYPE_PID); + task = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID); #endif if (task) get_task_struct(task); rcu_read_unlock(); if (!task) { - tloge("get task failed\n"); + tlogd("get task failed\n"); return -1; } sret = strncpy_s(comm, size, task->comm, strlen(task->comm)); if (sret != 0) - tloge("strncpy failed: errno = %d\n", sret); + tlogd("strncpy failed: errno = %d\n", sret); put_task_struct(task); return sret; @@ -124,7 +132,7 @@ bool is_thread_reported(pid_t tid) mutex_lock(&g_cmd_monitor_lock); list_for_each_entry(monitor, &g_cmd_monitor_list, list) { - if (monitor->tid == tid) { + if (monitor->tid == tid && !is_tui_in_use(monitor->tid)) { ret = (monitor->is_reported || monitor->agent_call_count > MAX_AGENT_CALL_COUNT); @@ -132,9 +140,28 @@ bool is_thread_reported(pid_t tid) } } mutex_unlock(&g_cmd_monitor_lock); + flush_delayed_work(&g_cmd_monitor_work); return ret; } +void memstat_report(void) +{ + int ret; + struct tee_mem *meminfo = NULL; + + meminfo = mailbox_alloc(sizeof(*meminfo), MB_FLAG_ZERO); + if (!meminfo) { + tloge("mailbox alloc failed\n"); + return; + } + + ret = get_tee_meminfo(meminfo); + if (ret != 0) + tlogd("get meminfo failed\n"); + + mailbox_free(meminfo); +} + void cmd_monitor_reset_context(void) { struct cmd_monitor *monitor = NULL; @@ -245,6 +272,7 @@ static void cmd_monitor_tickfn(struct work_struct *work) tz_log_write(); } +#define MAX_CRASH_INFO_LEN 100 static void cmd_monitor_archivefn(struct work_struct *work) { (void)(work); @@ -255,6 +283,8 @@ static void cmd_monitor_archivefn(struct work_struct *work) if (g_tee_detect_ta_crash == TYPE_CRASH_TEE) { tloge("detect teeos crash, panic\n"); report_log_system_panic(); + } else if (g_tee_detect_ta_crash == TYPE_CRASH_TA || + g_tee_detect_ta_crash == TYPE_KILLED_TA) { } g_tee_detect_ta_crash = 0; @@ -412,3 +442,27 @@ void free_cmd_monitor(void) g_cmd_monitor_wq = NULL; } } + +#ifdef CONFIG_CONFIDENTIAL_TEE +#define INSMOD_THREAD "insmod" +#define TEECD_THREAD "teecd" +bool check_running_ca(void) +{ + struct cmd_monitor *monitor = NULL; + bool has_running_ca = false; + mutex_lock(&g_cmd_monitor_lock); + list_for_each_entry(monitor, &g_cmd_monitor_list, list) { + char pname[TASK_COMM_LEN] = {0}; + if (get_pid_name(monitor->pid, pname, sizeof(pname)) != 0) { + continue; + } + if (strncmp(pname, INSMOD_THREAD, sizeof(INSMOD_THREAD)) != 0 && + strncmp(pname, TEECD_THREAD, sizeof(TEECD_THREAD)) != 0) { + tloge("detect running thread task:%s, please stop\n", pname); + has_running_ca = true; + } + } + mutex_unlock(&g_cmd_monitor_lock); + return has_running_ca; +} +#endif diff --git a/core/cmdmonitor.h b/core/cmdmonitor.h index a04a0f5..4146196 100644 --- a/core/cmdmonitor.h +++ b/core/cmdmonitor.h @@ -18,6 +18,7 @@ #ifndef CMD_MONITOR_H #define CMD_MONITOR_H +#include "tzdebug.h" #include "teek_ns_client.h" #include "smc_smp.h" #include @@ -27,8 +28,9 @@ #endif enum { - TYPE_CRASH_TA = 1, - TYPE_CRASH_TEE = 2, + TYPE_CRASH_TEE = 1, + TYPE_CRASH_TA = 2, + TYPE_KILLED_TA = 3, }; /* @@ -71,8 +73,10 @@ void init_cmd_monitor(void); void free_cmd_monitor(void); void do_cmd_need_archivelog(void); bool is_thread_reported(pid_t tid); -void tzdebug_archivelog(void); -void cmd_monitor_ta_crash(int32_t type); +void cmd_monitor_ta_crash(int32_t type, const uint8_t *ta_uuid, uint32_t uuid_len); +void memstat_report(void); void get_time_spec(struct time_spec *time); - +#ifdef CONFIG_CONFIDENTIAL_TEE +bool check_running_ca(void); +#endif #endif diff --git a/core/gp_ops.c b/core/gp_ops.c index 7484811..3889ad0 100644 --- a/core/gp_ops.c +++ b/core/gp_ops.c @@ -42,6 +42,7 @@ #include "smc_smp.h" #include "mem.h" #include "mailbox_mempool.h" +#include "shared_mem.h" #include "tc_client_driver.h" #include "internal_functions.h" #include "reserved_mempool.h" @@ -49,7 +50,7 @@ #define MAX_SHARED_SIZE 0x100000 /* 1 MiB */ -static void free_operation(const struct tc_call_params *call_params, +static void free_operation_params(const struct tc_call_params *call_params, struct tc_op_params *op_params); /* dir: 0-inclue input, 1-include output, 2-both */ @@ -544,54 +545,6 @@ static int alloc_for_ref_mem(const struct tc_call_params *call_params, } #ifdef CONFIG_NOCOPY_SHAREDMEM -static int fill_shared_mem_info(void *start_vaddr, uint32_t pages_no, - uint32_t offset, uint32_t buffer_size, void *buff) -{ - struct pagelist_info *page_info = NULL; - struct page **pages = NULL; - uint64_t *phys_addr = NULL; - uint32_t page_num; - uint32_t i; - - if (pages_no == 0) - return -EFAULT; - - pages = (struct page **)vmalloc(pages_no * sizeof(uint64_t)); - if (pages == NULL) - return -EFAULT; - - down_read(&mm_sem_lock(current->mm)); - page_num = get_user_pages((uintptr_t)start_vaddr, pages_no, FOLL_WRITE, pages, NULL); - up_read(&mm_sem_lock(current->mm)); - if (page_num != pages_no) { - tloge("get page phy addr failed\n"); - if (page_num > 0) - release_pages(pages, page_num); - vfree(pages); - return -EFAULT; - } - - page_info = buff; - page_info->page_num = pages_no; - page_info->page_size = PAGE_SIZE; - page_info->sharedmem_offset = offset; - page_info->sharedmem_size = buffer_size; - - phys_addr = (uint64_t *)buff + (sizeof(*page_info) / sizeof(uint64_t)); - for (i = 0; i < pages_no; i++) { - struct page *page = pages[i]; - if (page == NULL) { - release_pages(pages, page_num); - vfree(pages); - return -EFAULT; - } - phys_addr[i] = (uintptr_t)page_to_phys(page); - } - - vfree(pages); - return 0; -} - static int check_buffer_for_sharedmem(uint32_t *buffer_size, const union tc_ns_client_param *client_param, uint8_t kernel_params) { @@ -651,7 +604,7 @@ static int transfer_shared_mem(const struct tc_call_params *call_params, if (buff == NULL) return -EFAULT; - if (fill_shared_mem_info(start_vaddr, pages_no, offset, buffer_size, buff)) { + if (fill_shared_mem_info((uint64_t)start_vaddr, pages_no, offset, buffer_size, (uint64_t)buff)) { mailbox_free(buff); return -EFAULT; } @@ -768,7 +721,7 @@ static int alloc_operation(const struct tc_call_params *call_params, break; } if (ret != 0) { - free_operation(call_params, op_params); + free_operation_params(call_params, op_params); return ret; } op_params->mb_pack->operation.paramtypes = @@ -958,27 +911,7 @@ static int update_client_operation(const struct tc_call_params *call_params, return ret; } -#ifdef CONFIG_NOCOPY_SHAREDMEM -static void release_page(void *buf) -{ - uint32_t i; - uint64_t *phys_addr = NULL; - struct pagelist_info *page_info = NULL; - struct page *page = NULL; - - page_info = buf; - phys_addr = (uint64_t *)buf + (sizeof(*page_info) / sizeof(uint64_t)); - for (i = 0; i < page_info->page_num; i++) { - page = (struct page *)(uintptr_t)phys_to_page(phys_addr[i]); - if (page == NULL) - continue; - set_bit(PG_dirty, &page->flags); - put_page(page); - } -} -#endif - -static void free_operation(const struct tc_call_params *call_params, struct tc_op_params *op_params) +static void free_operation_params(const struct tc_call_params *call_params, struct tc_op_params *op_params) { uint32_t param_type; uint32_t index; @@ -1026,7 +959,7 @@ static void free_operation(const struct tc_call_params *call_params, struct tc_o #ifdef CONFIG_NOCOPY_SHAREDMEM temp_buf = local_tmpbuf[index].temp_buffer; if (temp_buf != NULL) { - release_page(temp_buf); + release_shared_mem_page(temp_buf, local_tmpbuf[index].size); mailbox_free(temp_buf); } #endif @@ -1089,6 +1022,9 @@ static int init_smc_cmd(const struct tc_call_params *call_params, } smc_cmd->cmd_id = context->cmd_id; smc_cmd->dev_file_id = call_params->dev->dev_file_id; +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + smc_cmd->nsid = call_params->dev->nsid; +#endif smc_cmd->context_id = context->session_id; smc_cmd->err_origin = context->returns.origin; smc_cmd->started = context->started; @@ -1215,7 +1151,7 @@ static void release_tc_call_resource(const struct tc_call_params *call_params, kill_ion_by_uuid((struct tc_uuid *)op_params->smc_cmd->uuid); if (op_params->op_inited) - free_operation(call_params, op_params); + free_operation_params(call_params, op_params); kfree(op_params->smc_cmd); mailbox_free(op_params->mb_pack); diff --git a/core/gp_ops.h b/core/gp_ops.h index 7144a0b..7ecb591 100644 --- a/core/gp_ops.h +++ b/core/gp_ops.h @@ -20,13 +20,6 @@ #include "tc_ns_client.h" #include "teek_ns_client.h" -struct pagelist_info { - uint64_t page_num; - uint64_t page_size; - uint64_t sharedmem_offset; - uint64_t sharedmem_size; -}; - int write_to_client(void __user *dest, size_t dest_size, const void *src, size_t size, uint8_t kernel_api); int read_from_client(void *dest, size_t dest_size, diff --git a/core/mailbox_mempool.c b/core/mailbox_mempool.c index e088e59..f44e01d 100644 --- a/core/mailbox_mempool.c +++ b/core/mailbox_mempool.c @@ -43,6 +43,11 @@ static int g_max_oder; #define OPT_MODE 0660U #define STATE_MODE 0440U +#ifndef MAILBOX_POOL_COUNT +#define MAILBOX_POOL_COUNT 1 +#endif +#define MAILBOX_POOL_MAX 32 + struct mb_page_t { struct list_head node; mailbox_page_t *page; @@ -61,41 +66,61 @@ struct mb_zone_t { struct mb_free_area_t free_areas[0]; }; -static struct mb_zone_t *g_m_zone; +static struct mb_zone_t **g_m_zone; +static uint32_t g_mb_count; static struct mutex g_mb_lock; +static bool check_zone(void) +{ + uint32_t i; + if (!g_m_zone) + return false; + + for (i = 0; i < g_mb_count; i++) { + if (!g_m_zone[i]) + return false; + } + return true; +} + static void mailbox_show_status(void) { - unsigned int i; + unsigned int i, j; struct mb_page_t *pos = NULL; struct list_head *head = NULL; unsigned int used = 0; - if (!g_m_zone) { + tloge("########################################\n"); + mutex_lock(&g_mb_lock); + + if (!check_zone()) { tloge("zone struct is NULL\n"); + mutex_unlock(&g_mb_lock); return; } - tloge("########################################\n"); - mutex_lock(&g_mb_lock); - for (i = 0; i < MAILBOX_PAGE_MAX; i++) { - if (g_m_zone->pages[i].count != 0) { - tloge("page[%02d], order=%02d, count=%d\n", - i, g_m_zone->pages[i].order, - g_m_zone->pages[i].count); - used += (1 << (uint32_t)g_m_zone->pages[i].order); + for (i = 0; i < g_mb_count; i++) { + for (j = 0; j < MAILBOX_PAGE_MAX; j++) { + if (g_m_zone[i]->pages[j].count != 0) { + tloge("zone[%03d], page[%02d], order=%02d, count=%d\n", + i, j, g_m_zone[i]->pages[j].order, + g_m_zone[i]->pages[j].count); + used += (1 << (uint32_t)g_m_zone[i]->pages[j].order); + } } } - tloge("total usage:%u/%u\n", used, MAILBOX_PAGE_MAX); + tloge("total usage:%u/%u\n", used, MAILBOX_PAGE_MAX * g_mb_count); tloge("----------------------------------------\n"); - for (i = 0; i < (unsigned int)g_max_oder; i++) { - head = &g_m_zone->free_areas[i].page_list; - if (list_empty(head) != 0) { - tloge("order[%02d] is empty\n", i); - } else { - list_for_each_entry(pos, head, node) - tloge("order[%02d]\n", i); + for (i = 0; i < g_mb_count; i++) { + for (j = 0; j < (unsigned int)g_max_oder; j++) { + head = &g_m_zone[i]->free_areas[j].page_list; + if (list_empty(head) != 0) { + tloge("zone[%03d], order[%02d] is empty\n", i, j); + } else { + list_for_each_entry(pos, head, node) + tloge("zone[%03d], order[%02d]\n", i, j); + } } } mutex_unlock(&g_mb_lock); @@ -107,94 +132,102 @@ static void mailbox_show_status(void) #define BITS_OF_BYTE 8 static void mailbox_show_details(void) { - unsigned int i; + unsigned int i, j; unsigned int used = 0; unsigned int left = 0; unsigned int order = 0; - if (!g_m_zone) { + tloge("----- show mailbox details -----"); + + mutex_lock(&g_mb_lock); + if (!check_zone()) { tloge("zone struct is NULL\n"); + mutex_unlock(&g_mb_lock); return; } - tloge("----- show mailbox details -----"); - mutex_lock(&g_mb_lock); - for (i = 0; i < MAILBOX_PAGE_MAX; i++) { - if (i % MB_SHOW_LINE == 0) { - tloge("\n"); - tloge("%04d-%04d:", i, i + MB_SHOW_LINE); - } + for (i = 0; i < g_mb_count; i++) { + for (j = 0; j < MAILBOX_PAGE_MAX; j++) { + if (j % MB_SHOW_LINE == 0) { + tloge("\n"); + tloge("%04d-%04d:", j, j + MB_SHOW_LINE); + } - if (g_m_zone->pages[i].count != 0) { - left = 1 << (uint32_t)g_m_zone->pages[i].order; - order = (uint32_t)g_m_zone->pages[i].order; - used += (1 << (uint32_t)g_m_zone->pages[i].order); - } + if (g_m_zone[i]->pages[j].count != 0) { + left = 1 << (uint32_t)g_m_zone[i]->pages[j].order; + order = (uint32_t)g_m_zone[i]->pages[j].order; + used += (1 << (uint32_t)g_m_zone[i]->pages[j].order); + } - if (left != 0) { - left--; - tloge("%01d", order); - } else { - tloge("X"); - } + if (left != 0) { + left--; + tloge("%01d", order); + } else { + tloge("X"); + } - if (i > 1 && (i + 1) % (MB_SHOW_LINE / BITS_OF_BYTE) == 0) - tloge(" "); + if (j > 1 && (j + 1) % (MB_SHOW_LINE / BITS_OF_BYTE) == 0) + tloge(" "); + } } - tloge("total usage:%u/%u\n", used, MAILBOX_PAGE_MAX); + tloge("total usage:%u/%u\n", used, MAILBOX_PAGE_MAX * g_mb_count); mutex_unlock(&g_mb_lock); } void *mailbox_alloc(size_t size, unsigned int flag) { - unsigned int i; + unsigned int i, j, k; struct mb_page_t *pos = (struct mb_page_t *)NULL; struct list_head *head = NULL; int order = get_order(ALIGN(size, SZ_4K)); void *addr = NULL; + bool tag = false; - if ((size == 0) || !g_m_zone) { - tlogw("alloc 0 size mailbox or zone struct is NULL\n"); + if (order > g_max_oder || order < 0) { + tloge("invalid order %d\n", order); return NULL; } + mutex_lock(&g_mb_lock); - if (order > g_max_oder || order < 0) { - tloge("invalid order %d\n", order); + if ((size == 0) || !check_zone()) { + tlogw("alloc 0 size mailbox or zone struct is NULL\n"); + mutex_unlock(&g_mb_lock); return NULL; } - mutex_lock(&g_mb_lock); - for (i = (unsigned int)order; i <= (unsigned int)g_max_oder; i++) { - unsigned int j; + for (k = 0; k < g_mb_count; k++) { + if (tag == true) break; + for (i = (unsigned int)order; i <= (unsigned int)g_max_oder; i++) { - head = &g_m_zone->free_areas[i].page_list; - if (list_empty(head) != 0) - continue; + head = &g_m_zone[k]->free_areas[i].page_list; + if (list_empty(head) != 0) + continue; - pos = list_first_entry(head, struct mb_page_t, node); + pos = list_first_entry(head, struct mb_page_t, node); - pos->count = 1; - pos->order = order; + pos->count = 1; + pos->order = order; - /* split and add free list */ - for (j = (unsigned int)order; j < i; j++) { - struct mb_page_t *new_page = NULL; + /* split and add free list */ + for (j = (unsigned int)order; j < i; j++) { + struct mb_page_t *new_page = NULL; - new_page = pos + (1 << j); - new_page->count = 0; - new_page->order = (int)j; - list_add_tail(&new_page->node, - &g_m_zone->free_areas[j].page_list); + new_page = pos + (1 << j); + new_page->count = 0; + new_page->order = (int)j; + list_add_tail(&new_page->node, + &g_m_zone[k]->free_areas[j].page_list); + } + list_del(&pos->node); + addr = (void *)mailbox_page_address(pos->page); + tag = true; + break; } - list_del(&pos->node); - addr = (void *)mailbox_page_address(pos->page); - break; } - mutex_unlock(&g_mb_lock); + mutex_unlock(&g_mb_lock); if (addr && ((flag & MB_FLAG_ZERO) != 0)) { - if (memset_s(addr, ALIGN(size, SZ_4K), - 0, ALIGN(size, SZ_4K)) != 0) { + if (memset_s(addr, ALIGN(size, SZ_4K), 0, ALIGN(size, SZ_4K)) != 0) { tloge("clean mailbox failed\n"); mailbox_free(addr); return NULL; @@ -203,34 +236,36 @@ void *mailbox_alloc(size_t size, unsigned int flag) return addr; } -static void add_max_order_block(unsigned int idex) +static void add_max_order_block(unsigned int order, unsigned int index) { struct mb_page_t *self = NULL; - if (idex != (unsigned int)g_max_oder || !g_m_zone) + if (order != (unsigned int)g_max_oder) return; /* - * when idex equal max order, no one use mailbox mem, + * when order equal max order, no one use mailbox mem, * we need to hang all pages in the last free area page list */ - self = &g_m_zone->pages[0]; + self = &g_m_zone[index]->pages[0]; list_add_tail(&self->node, - &g_m_zone->free_areas[g_max_oder].page_list); + &g_m_zone[index]->free_areas[g_max_oder].page_list); } -static bool is_ptr_valid(const mailbox_page_t *page) +static bool is_ptr_valid(const mailbox_page_t *page, unsigned int *index) { - if (!g_m_zone) - return false; + unsigned int i = 0; - if (page < g_m_zone->all_pages || - page >= (g_m_zone->all_pages + MAILBOX_PAGE_MAX)) { - tloge("invalid ptr to free in mailbox\n"); - return false; + for (; i < g_mb_count; i++) { + if (page >= g_m_zone[i]->all_pages && + page < (g_m_zone[i]->all_pages + MAILBOX_PAGE_MAX)) { + *index = i; + return true; + } } - return true; + tloge("invalid ptr to free in mailbox\n"); + return false; } void mailbox_free(const void *ptr) @@ -241,31 +276,31 @@ void mailbox_free(const void *ptr) struct mb_page_t *buddy = NULL; unsigned int self_idx; unsigned int buddy_idx; + unsigned int index = 0; - if (!ptr || !g_m_zone) { - tloge("invalid ptr\n"); - return; + mutex_lock(&g_mb_lock); + if (!ptr || !check_zone()) { + tloge("invalid ptr or zone struct is NULL\n"); + goto end; } page = mailbox_virt_to_page((uint64_t)(uintptr_t)ptr); - if (!is_ptr_valid(page)) - return; + if (!is_ptr_valid(page, &index)) + goto end; - mutex_lock(&g_mb_lock); - self_idx = page - g_m_zone->all_pages; - self = &g_m_zone->pages[self_idx]; + self_idx = page - g_m_zone[index]->all_pages; + self = &g_m_zone[index]->pages[self_idx]; if (self->count == 0) { tloge("already freed in mailbox\n"); - mutex_unlock(&g_mb_lock); - return; + goto end; } for (i = (unsigned int)self->order; i < (unsigned int)g_max_oder; i++) { - self_idx = page - g_m_zone->all_pages; + self_idx = page - g_m_zone[index]->all_pages; buddy_idx = self_idx ^ (uint32_t)(1 << i); - self = &g_m_zone->pages[self_idx]; - buddy = &g_m_zone->pages[buddy_idx]; + self = &g_m_zone[index]->pages[self_idx]; + buddy = &g_m_zone[index]->pages[buddy_idx]; self->count = 0; /* is buddy free */ if ((unsigned int)buddy->order == i && buddy->count == 0) { @@ -283,13 +318,13 @@ void mailbox_free(const void *ptr) } else { /* release self */ list_add_tail(&self->node, - &g_m_zone->free_areas[i].page_list); - mutex_unlock(&g_mb_lock); - return; + &g_m_zone[index]->free_areas[i].page_list); + goto end; } } - add_max_order_block(i); + add_max_order_block(i, index); +end: mutex_unlock(&g_mb_lock); } @@ -527,6 +562,7 @@ static int mailbox_register(const void *mb_pool, unsigned int size) tloge("alloc smc_cmd failed\n"); return -EIO; } + operation = (struct tc_ns_operation *)(uintptr_t)get_operation_vaddr(); if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)operation)) { tloge("alloc operation failed\n"); @@ -535,7 +571,7 @@ static int mailbox_register(const void *mb_pool, unsigned int size) } operation->paramtypes = TEE_PARAM_TYPE_VALUE_INPUT | - (TEE_PARAM_TYPE_VALUE_INPUT << TEE_PARAM_NUM); + (TEE_PARAM_TYPE_VALUE_INOUT << TEE_PARAM_NUM); operation->params[0].value.a = mailbox_virt_to_phys((uintptr_t)mb_pool); operation->params[0].value.b = (uint64_t)mailbox_virt_to_phys((uintptr_t)mb_pool) >> ADDR_TRANS_NUM; @@ -548,14 +584,19 @@ static int mailbox_register(const void *mb_pool, unsigned int size) (uint64_t)mailbox_virt_to_phys((uintptr_t)operation) >> ADDR_TRANS_NUM; if (is_tee_rebooting()) - ret = send_smc_cmd_rebooting(TSP_REQUEST, 0, 0, smc_cmd); + ret = send_smc_cmd_rebooting(TSP_REQUEST, smc_cmd); else ret= tc_ns_smc(smc_cmd); if (ret != 0) { tloge("resigter mailbox failed\n"); ret = -EIO; + } else { + if (operation->params[1].value.a <= g_mb_count || g_mb_count == 0) + g_mb_count = operation->params[1].value.a; + tlogi("wish to register %u mailbox, success %u\n", (uint32_t)MAILBOX_POOL_COUNT, g_mb_count); } + free_operation((uint64_t)(uintptr_t)operation); operation = NULL; @@ -571,84 +612,182 @@ static void mailbox_debug_init(void) int re_register_mailbox(void) { - if (!g_m_zone) + uint32_t i = 0; + int ret = 0; + struct mailbox_buffer *buffer = NULL; + + mutex_lock(&g_mb_lock); + if (!check_zone()) { + mutex_unlock(&g_mb_lock); return -EFAULT; - if (g_m_zone->all_pages != NULL) { - if (memset_s((void *)mailbox_page_address(g_m_zone->all_pages), - MAILBOX_POOL_SIZE, 0, MAILBOX_POOL_SIZE) != EOK) { - tloge("memset mailbox failed\n"); - return -EFAULT; - } + } - if (mailbox_register((const void *)mailbox_page_address(g_m_zone->all_pages), MAILBOX_POOL_SIZE) != 0) { - tloge("register mailbox failed\n"); - return -EIO; - } + buffer = (struct mailbox_buffer *)(uintptr_t)get_mailbox_buffer_vaddr(g_mb_count); + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)buffer)) { + mutex_unlock(&g_mb_lock); + return -ENOMEM; } - return 0; + for (; i < g_mb_count; i++) { + (void)memset_s((void *)mailbox_page_address(g_m_zone[i]->all_pages), + MAILBOX_POOL_SIZE, 0, MAILBOX_POOL_SIZE); + buffer[i].buffer = mailbox_virt_to_phys(mailbox_page_address(g_m_zone[i]->all_pages)); + buffer[i].size = MAILBOX_POOL_SIZE; + + } + mutex_unlock(&g_mb_lock); + + if (mailbox_register(buffer, sizeof(struct mailbox_buffer) * g_mb_count) != 0) { + tloge("register mailbox failed\n"); + ret = -EIO; + } + + free_mailbox_buffer((uint64_t)(uintptr_t)buffer); + return ret; } -int mailbox_mempool_init(void) +static int init_zone(mailbox_page_t **all_pages) { - int i; + uint32_t i, j; struct mb_page_t *mb_page = NULL; struct mb_free_area_t *area = NULL; - mailbox_page_t *all_pages = NULL; size_t zone_len; - g_max_oder = get_order(MAILBOX_POOL_SIZE); - tlogi("in this RE, mailbox max order is: %d\n", g_max_oder); - - /* zone len is fixed, will not overflow */ - zone_len = sizeof(*area) * (g_max_oder + 1) + sizeof(*g_m_zone); - g_m_zone = kzalloc(zone_len, GFP_KERNEL); + g_m_zone = kzalloc(sizeof(struct mb_zone_t **) * g_mb_count, GFP_KERNEL); if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)g_m_zone)) { - tloge("fail to alloc zone struct\n"); + tloge("fail to alloc g_m_zone\n"); return -ENOMEM; } - all_pages = mailbox_alloc_pages(g_max_oder); - if (!all_pages) { - tloge("fail to alloc mailbox mempool\n"); - kfree(g_m_zone); - g_m_zone = NULL; + zone_len = sizeof(*area) * (g_max_oder + 1) + sizeof(struct mb_zone_t); + for (i = 0; i < g_mb_count; i++) { + g_m_zone[i] = kzalloc(zone_len, GFP_KERNEL); + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)g_m_zone[i])) { + tloge("fail to alloc zone\n"); + goto clear; + } + for (j = 0; j < MAILBOX_PAGE_MAX; j++) { + g_m_zone[i]->pages[j].order = -1; + g_m_zone[i]->pages[j].count = 0; + g_m_zone[i]->pages[j].page = &all_pages[i][j]; + } + g_m_zone[i]->pages[0].order = g_max_oder; + + for (j = 0; j <= g_max_oder; j++) { + area = &g_m_zone[i]->free_areas[j]; + INIT_LIST_HEAD(&area->page_list); + area->order = j; + } + + mb_page = &g_m_zone[i]->pages[0]; + list_add_tail(&mb_page->node, &area->page_list); + g_m_zone[i]->all_pages = all_pages[i]; + } + return 0; +clear: + for (j = 0; j < i; j++) + kfree(g_m_zone[j]); + + kfree(g_m_zone); + return -ENOMEM; +} + +static int mailbox_init(uint32_t pool_count, mailbox_page_t **all_pages) +{ + uint32_t i; + int ret = 0; + struct mailbox_buffer *buffer = NULL; + + buffer = (struct mailbox_buffer *)(uintptr_t)get_mailbox_buffer_vaddr(pool_count); + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)buffer)) return -ENOMEM; + for (i = 0; i < pool_count; i++) { + buffer[i].buffer = mailbox_virt_to_phys(mailbox_page_address(all_pages[i])); + buffer[i].size = MAILBOX_POOL_SIZE; } - if (mailbox_register((const void *)mailbox_page_address(all_pages), MAILBOX_POOL_SIZE) != 0) { + if (mailbox_register(buffer, sizeof(struct mailbox_buffer) * pool_count) != 0) { tloge("register mailbox failed\n"); - mailbox_free_pages(all_pages, g_max_oder); - kfree(g_m_zone); - g_m_zone = NULL; - return -EIO; + ret = -EIO; + goto clear; } - for (i = 0; i < MAILBOX_PAGE_MAX; i++) { - g_m_zone->pages[i].order = -1; - g_m_zone->pages[i].count = 0; - g_m_zone->pages[i].page = &all_pages[i]; + if (init_zone(all_pages) != 0) { + tloge("mailbox init failed\n"); + ret = -ENOMEM; + goto clear; } - g_m_zone->pages[0].order = g_max_oder; + mutex_init(&g_mb_lock); + mailbox_debug_init(); +clear: + free_mailbox_buffer((uint64_t)(uintptr_t)buffer); + return ret; +} + +int mailbox_mempool_init(void) +{ + uint32_t pool_count, i; + mailbox_page_t **all_pages = NULL; + int ret = 0; - for (i = 0; i <= g_max_oder; i++) { - area = &g_m_zone->free_areas[i]; - INIT_LIST_HEAD(&area->page_list); - area->order = i; + if(MAILBOX_POOL_COUNT < 1 || MAILBOX_POOL_COUNT > MAILBOX_POOL_MAX) { + tloge("mailbox pool count invalid %d %d\n", MAILBOX_POOL_COUNT, MAILBOX_POOL_MAX); + return -EINVAL; } - mb_page = &g_m_zone->pages[0]; - list_add_tail(&mb_page->node, &area->page_list); - g_m_zone->all_pages = all_pages; - mutex_init(&g_mb_lock); - mailbox_debug_init(); - return 0; + g_max_oder = get_order(MAILBOX_POOL_SIZE); + tlogi("in this RE, mailbox max order is: %d\n", g_max_oder); + + all_pages = kzalloc(sizeof(mailbox_page_t **) * (uint32_t)MAILBOX_POOL_COUNT, GFP_KERNEL); + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)all_pages)) { + tloge("fail to alloc mailbox mempool\n"); + return -ENOMEM; + } + + for (pool_count = 0; pool_count < (uint32_t)MAILBOX_POOL_COUNT; pool_count++) { + all_pages[pool_count] = mailbox_alloc_pages(g_max_oder); + if(!all_pages[pool_count]) { + tloge("fail to alloc pages\n"); + break; + } + } + if (pool_count == 0) { + ret = -ENOMEM; + goto clear1; + } + + ret = mailbox_init(pool_count, all_pages); + if (ret != 0) { + tloge("mailbox init failed\n"); + goto clear2; + } + + for(i = g_mb_count; i < pool_count; i++) { + mailbox_free_pages(all_pages[i], g_max_oder); + all_pages[i] = NULL; + } + + return ret; +clear2: + for (i = 0; i < pool_count; i++) { + mailbox_free_pages(all_pages[i], g_max_oder); + all_pages[i] = NULL; + } + +clear1: + kfree(all_pages); + return ret; } void free_mailbox_mempool(void) { - mailbox_free_pages(g_m_zone->all_pages, g_max_oder); - g_m_zone->all_pages = NULL; + unsigned int i; + for (i = 0; i < g_mb_count; i++) { + mailbox_free_pages(g_m_zone[i]->all_pages, g_max_oder); + g_m_zone[i]->all_pages = NULL; + kfree(g_m_zone[i]); + g_m_zone[i] = NULL; + } kfree(g_m_zone); g_m_zone = NULL; diff --git a/core/mailbox_mempool.h b/core/mailbox_mempool.h index b27ad42..f74be20 100644 --- a/core/mailbox_mempool.h +++ b/core/mailbox_mempool.h @@ -26,6 +26,11 @@ #define MAILBOX_POOL_SIZE SZ_4M #endif +struct mailbox_buffer { + uint64_t buffer; + uint32_t size; +}; + /* alloc options */ #define MB_FLAG_ZERO 0x1 /* set 0 after alloc page */ #define GLOBAL_UUID_LEN 17 /* first char represent global cmd */ diff --git a/core/reserved_mempool.c b/core/reserved_mempool.c index 43d7731..b6f8a97 100644 --- a/core/reserved_mempool.c +++ b/core/reserved_mempool.c @@ -164,13 +164,13 @@ static int create_zone(void) zone_len = sizeof(struct reserved_free_area_t) * (g_res_max_order + 1) + sizeof(*g_res_zone); g_res_zone = kzalloc(zone_len, GFP_KERNEL); - if (g_res_zone == NULL) { + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)g_res_zone)) { tloge("fail to create zone\n"); return -ENOMEM; } g_res_zone->pages = kzalloc(sizeof(struct reserved_page_t) * get_res_page_size(), GFP_KERNEL); - if (g_res_zone->pages == NULL) { + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)g_res_zone->pages)) { tloge("failed to alloc zone pages\n"); kfree(g_res_zone); g_res_zone = NULL; @@ -185,7 +185,7 @@ static struct virt_page *create_virt_pages(void) struct virt_page *pages = NULL; pages = kzalloc(get_res_page_size() * sizeof(struct virt_page), GFP_KERNEL); - if (pages == NULL) { + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)pages)) { tloge("alloc pages failed\n"); return NULL; } @@ -444,8 +444,8 @@ static int get_virt_page_index(const void *ptr) static int buddy_merge(struct virt_page *vpage, int order, unsigned int *page_index) { int i; - unsigned int cur_idx = 0; - unsigned int buddy_idx = 0; + unsigned int cur_idx; + unsigned int buddy_idx; struct reserved_page_t *self = NULL; struct reserved_page_t *buddy = NULL; diff --git a/core/session_manager.c b/core/session_manager.c index 48e21c5..d7da215 100644 --- a/core/session_manager.c +++ b/core/session_manager.c @@ -41,6 +41,9 @@ #include #endif #include +#ifndef CONFIG_CONFIDENTIAL_CONTAINER +#include +#endif #include #include "smc_smp.h" #include "mem.h" @@ -60,6 +63,23 @@ static DEFINE_MUTEX(g_load_app_lock); struct list_head g_service_list; DEFINE_MUTEX(g_service_list_lock); +static int lock_interruptible(struct mutex *m) +{ + int ret; + + do { + ret = mutex_lock_interruptible(m); + if (ret != 0) { + if (sigkill_pending(current)) + return ret; + tloge("signal try relock ret %d", ret); + continue; + } + } while (0); + + return 0; +} + void init_srvc_list(void) { INIT_LIST_HEAD(&g_service_list); @@ -257,8 +277,8 @@ struct tc_ns_session *tc_find_session_by_uuid(unsigned int dev_file_id, return session; } -static int tc_ns_need_load_image(unsigned int file_id, - const unsigned char *uuid, unsigned int uuid_len) +static int tc_ns_need_load_image(const struct tc_ns_dev_file *dev_file, + const unsigned char *uuid, unsigned int uuid_len, struct tc_ns_client_return *tee_ret) { int ret; int smc_ret; @@ -266,10 +286,6 @@ static int tc_ns_need_load_image(unsigned int file_id, struct mb_cmd_pack *mb_pack = NULL; char *mb_param = NULL; - if (!uuid || uuid_len != UUID_LEN) { - tloge("invalid uuid\n"); - return -ENOMEM; - } mb_pack = mailbox_alloc_cmd_pack(); if (!mb_pack) { tloge("alloc mb pack failed\n"); @@ -289,7 +305,10 @@ static int tc_ns_need_load_image(unsigned int file_id, mb_pack->operation.params[0].memref.size = SZ_4K; smc_cmd.cmd_id = GLOBAL_CMD_ID_NEED_LOAD_APP; smc_cmd.cmd_type = CMD_TYPE_GLOBAL; - smc_cmd.dev_file_id = file_id; + smc_cmd.dev_file_id = dev_file->dev_file_id; +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + smc_cmd.nsid = dev_file->nsid; +#endif smc_cmd.context_id = 0; smc_cmd.operation_phys = mailbox_virt_to_phys((uintptr_t)&mb_pack->operation); smc_cmd.operation_h_phys = @@ -298,6 +317,10 @@ static int tc_ns_need_load_image(unsigned int file_id, smc_ret = tc_ns_smc(&smc_cmd); if (smc_ret != 0) { tloge("smc call returns error ret 0x%x\n", smc_ret); + if (smc_cmd.err_origin != TEEC_ORIGIN_COMMS && tee_ret != NULL) { + tee_ret->origin = smc_cmd.err_origin; + tee_ret->code = smc_ret; + } ret = -EFAULT; goto clean; } else { @@ -311,22 +334,47 @@ clean: return ret; } +static int init_ioctl_arg(struct tc_ns_dev_file *dev_file, const void __user *argp, + const struct load_secfile_ioctl_struct *k_argp, struct load_secfile_ioctl_struct *ioctl_arg) +{ + if (!dev_file) { + tloge("dev file is null\n"); + return -EINVAL; + } + if (dev_file->kernel_api != TEE_REQ_FROM_KERNEL_MODE) { + if (!argp) { + tloge("argp is null\n"); + return -EINVAL; + } + if (copy_from_user(ioctl_arg, argp, sizeof(*ioctl_arg))) { + tloge("copy from user failed\n"); + return -ENOMEM; + } + } else { + if (!k_argp) { + tloge("k_argp is null\n"); + return -EINVAL; + } + if (memcpy_s(ioctl_arg, sizeof(*ioctl_arg), k_argp, sizeof(*ioctl_arg)) != EOK) { + tloge("memcpy arg err\n"); + return -ENOMEM; + } + } + + return 0; +} + int tc_ns_load_secfile(struct tc_ns_dev_file *dev_file, - void __user *argp, bool is_from_client_node) + void __user *argp, const struct load_secfile_ioctl_struct *k_argp, bool is_from_client_node) { int ret; struct load_secfile_ioctl_struct ioctl_arg = { {0}, {0}, {NULL} }; bool load = true; void *file_addr = NULL; - if (!dev_file || !argp) { - tloge("Invalid params !\n"); - return -EINVAL; - } - - if (copy_from_user(&ioctl_arg, argp, sizeof(ioctl_arg)) != 0) { - tloge("copy from user failed\n"); - ret = -ENOMEM; + ret = init_ioctl_arg(dev_file, argp, k_argp, &ioctl_arg); + if (ret != 0) { + tloge("init ioctl args failed, ret %d\n", ret); return ret; } @@ -347,8 +395,7 @@ int tc_ns_load_secfile(struct tc_ns_dev_file *dev_file, } if (ioctl_arg.sec_file_info.secfile_type == LOAD_TA) { - ret = tc_ns_need_load_image(dev_file->dev_file_id, ioctl_arg.uuid, - (unsigned int)UUID_LEN); + ret = tc_ns_need_load_image(dev_file, ioctl_arg.uuid, (unsigned int)UUID_LEN, NULL); if (ret != 1) /* 1 means we need to load image */ load = false; } @@ -362,8 +409,10 @@ int tc_ns_load_secfile(struct tc_ns_dev_file *dev_file, ioctl_arg.sec_file_info.secfile_type, ret); } mutex_unlock(&g_load_app_lock); - if (copy_to_user(argp, &ioctl_arg, sizeof(ioctl_arg)) != 0) - tloge("copy to user failed\n"); + if (dev_file->kernel_api != TEE_REQ_FROM_KERNEL_MODE) { + if (copy_to_user(argp, &ioctl_arg, sizeof(ioctl_arg)) != 0) + tloge("copy to user failed\n"); + } return ret; } @@ -524,7 +573,7 @@ static int check_login_method(struct tc_ns_dev_file *dev_file, } static struct tc_ns_service *tc_ref_service_in_dev(struct tc_ns_dev_file *dev, - const unsigned char *uuid, int uuid_size, bool *is_full) + const unsigned char *uuid, int uuid_size, unsigned int nsid, bool *is_full) { uint32_t i; @@ -532,7 +581,7 @@ static struct tc_ns_service *tc_ref_service_in_dev(struct tc_ns_dev_file *dev, return NULL; for (i = 0; i < SERVICES_MAX_COUNT; i++) { - if (dev->services[i] != NULL && + if (dev->services[i] != NULL && dev->services[i]->nsid == nsid && memcmp(dev->services[i]->uuid, uuid, UUID_LEN) == 0) { if (dev->service_ref[i] == MAX_REF_COUNT) { *is_full = true; @@ -566,6 +615,11 @@ static int tc_ns_service_init(const unsigned char *uuid, uint32_t uuid_len, return -EFAULT; } +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + service->nsid = task_active_pid_ns(current)->ns.inum; +#else + service->nsid = PROC_PID_INIT_INO; +#endif INIT_LIST_HEAD(&service->session_list); mutex_init(&service->session_lock); list_add_tail(&service->head, &g_service_list); @@ -578,7 +632,7 @@ static int tc_ns_service_init(const unsigned char *uuid, uint32_t uuid_len, } static struct tc_ns_service *tc_find_service_from_all( - const unsigned char *uuid, uint32_t uuid_len) + const unsigned char *uuid, uint32_t uuid_len, uint32_t nsid) { struct tc_ns_service *service = NULL; @@ -586,7 +640,7 @@ static struct tc_ns_service *tc_find_service_from_all( return NULL; list_for_each_entry(service, &g_service_list, head) { - if (memcmp(service->uuid, uuid, sizeof(service->uuid)) == 0) + if (memcmp(service->uuid, uuid, sizeof(service->uuid)) == 0 && service->nsid == nsid) return service; } @@ -599,10 +653,15 @@ static struct tc_ns_service *find_service(struct tc_ns_dev_file *dev_file, int ret; struct tc_ns_service *service = NULL; bool is_full = false; +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + unsigned int nsid = task_active_pid_ns(current)->ns.inum; +#else + unsigned int nsid = PROC_PID_INIT_INO; +#endif mutex_lock(&dev_file->service_lock); service = tc_ref_service_in_dev(dev_file, context->uuid, - UUID_LEN, &is_full); + UUID_LEN, nsid, &is_full); /* if service has been opened in this dev or ref cnt is full */ if (service || is_full) { /* @@ -616,7 +675,7 @@ static struct tc_ns_service *find_service(struct tc_ns_dev_file *dev_file, return service; } mutex_lock(&g_service_list_lock); - service = tc_find_service_from_all(context->uuid, UUID_LEN); + service = tc_find_service_from_all(context->uuid, UUID_LEN, nsid); /* if service has been opened in other dev */ if (service) { get_service_struct(service); @@ -779,6 +838,9 @@ static int load_image_by_frame(struct load_img_params *params, unsigned int load params->mb_pack->operation.params[3].value.a = index; params->mb_pack->operation.params[1].value.a = sec_file_info->secfile_type; smc_cmd.dev_file_id = params->dev_file->dev_file_id; +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + smc_cmd.nsid = params->dev_file->nsid; +#endif smc_ret = tc_ns_smc(&smc_cmd); tlogd("configid=%u, ret=%d, load_flag=%d, index=%u\n", params->mb_pack->operation.params[1].value.a, smc_ret, @@ -903,8 +965,7 @@ static int load_ta_image(struct tc_ns_dev_file *dev_file, tee_ret.origin = TEEC_ORIGIN_COMMS; mutex_lock(&g_load_app_lock); - ret = tc_ns_need_load_image(dev_file->dev_file_id, context->uuid, - (unsigned int)UUID_LEN); + ret = tc_ns_need_load_image(dev_file, context->uuid, (unsigned int)UUID_LEN, &tee_ret); if (ret == 1) { /* 1 means we need to load image */ if (!context->file_buffer) { tloge("context's file_buffer is NULL"); @@ -927,6 +988,11 @@ static int load_ta_image(struct tc_ns_dev_file *dev_file, return ret; } } + if (ret != 0 && tee_ret.origin != TEEC_ORIGIN_COMMS) { + context->returns.code = tee_ret.code; + context->returns.origin = tee_ret.origin; + ret = EFAULT; + } mutex_unlock(&g_load_app_lock); return ret; @@ -958,7 +1024,8 @@ static int proc_open_session(struct tc_ns_dev_file *dev_file, dev_file, context, session, flags }; - mutex_lock(&service->operation_lock); + if (lock_interruptible(&service->operation_lock) != 0) + return -EINTR; ret = load_ta_image(dev_file, context); if (ret != 0) { tloge("load ta image failed\n"); @@ -1038,7 +1105,10 @@ int tc_ns_open_session(struct tc_ns_dev_file *dev_file, tloge("calc client auth hash failed\n"); goto err_free_rsrc; } - +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + if (dev_file->nsid == 0) + dev_file->nsid = task_active_pid_ns(current)->ns.inum; +#endif ret = proc_open_session(dev_file, context, service, session, flags); if (ret == 0) goto err_clear_param; @@ -1186,7 +1256,10 @@ void close_unclosed_session_in_kthread(struct tc_ns_dev_file *dev) /* when self recovery, release session in reboot interface */ if (is_tee_rebooting()) return; - +#ifndef CONFIG_TA_AFFINITY + close_session_thread_fn(dev); + (void)close_thread; +#else close_thread = kthread_create(close_session_thread_fn, dev, "close_fn_%6d", dev->dev_file_id); if (unlikely(IS_ERR_OR_NULL(close_thread))) { @@ -1198,6 +1271,7 @@ void close_unclosed_session_in_kthread(struct tc_ns_dev_file *dev) wake_up_process(close_thread); wait_for_completion(&dev->close_comp); tlogd("wait for completion success\n"); +#endif } int tc_ns_close_session(struct tc_ns_dev_file *dev_file, @@ -1227,7 +1301,10 @@ int tc_ns_close_session(struct tc_ns_dev_file *dev_file, * same session_id may appear in tzdriver, put session_list * add/del in service->operation_lock can avoid it. */ - mutex_lock(&service->operation_lock); + if (lock_interruptible(&service->operation_lock) != 0) { + put_service_struct(service); + return -EINTR; + } session = get_session(service, dev_file, context); if (session) { int ret2; diff --git a/core/session_manager.h b/core/session_manager.h index 4a08bf0..d6d0a1f 100644 --- a/core/session_manager.h +++ b/core/session_manager.h @@ -43,7 +43,7 @@ struct tc_ns_session *tc_find_session_withowner( const struct list_head *session_list, unsigned int session_id, const struct tc_ns_dev_file *dev_file); int tc_ns_load_secfile(struct tc_ns_dev_file *dev_file, - void __user *argp, bool is_from_client_node); + void __user *argp, const struct load_secfile_ioctl_struct *k_argp, bool is_from_client_node); int load_image(struct load_img_params *params, struct sec_file_info *sec_file_info, struct tc_ns_client_return *tee_ret); void get_service_struct(struct tc_ns_service *service); diff --git a/core/shared_mem.c b/core/shared_mem.c index 3e0b0d8..dd169be 100644 --- a/core/shared_mem.c +++ b/core/shared_mem.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "tc_ns_log.h" #include "tc_ns_client.h" @@ -27,11 +28,102 @@ #include "mailbox_mempool.h" #include "ko_adapt.h" +uint64_t get_reserved_cmd_vaddr_of(phys_addr_t cmd_phys, uint64_t cmd_size) +{ + uint64_t cmd_vaddr; + if (cmd_phys == 0 || cmd_size == 0) { + tloge("cmd phy or cmd size is error\n"); + return 0; + } + cmd_vaddr = (uint64_t)(uintptr_t)ioremap_cache(cmd_phys, cmd_size); + if (cmd_vaddr == 0) { + tloge("io remap for reserved cmd buffer failed\n"); + return 0; + } + (void)memset_s((void *)(uintptr_t)cmd_vaddr, cmd_size, 0, cmd_size); + return cmd_vaddr; +} + +#ifdef CONFIG_NOCOPY_SHAREDMEM +int fill_shared_mem_info(uint64_t start_vaddr, uint32_t pages_no, + uint32_t offset, uint32_t buffer_size, uint64_t info_addr) +{ + struct pagelist_info *page_info = NULL; + struct page **pages = NULL; + uint64_t *phys_addr = NULL; + uint32_t page_num; + uint32_t i; + + if (pages_no == 0) + return -EFAULT; + + pages = (struct page **)vmalloc(pages_no * sizeof(uint64_t)); + if (pages == NULL) + return -EFAULT; + + down_read(&mm_sem_lock(current->mm)); + page_num = get_user_pages((uintptr_t)start_vaddr, pages_no, FOLL_WRITE, pages, NULL); + up_read(&mm_sem_lock(current->mm)); + if (page_num != pages_no) { + tloge("get page phy addr failed\n"); + if (page_num > 0) + release_pages(pages, page_num); + vfree(pages); + return -EFAULT; + } + + page_info = (struct pagelist_info *)(uintptr_t)info_addr; + page_info->page_num = pages_no; + page_info->page_size = PAGE_SIZE; + page_info->sharedmem_offset = offset; + page_info->sharedmem_size = buffer_size; + + phys_addr = (uint64_t *)(uintptr_t)info_addr + (sizeof(*page_info) / sizeof(uint64_t)); + for (i = 0; i < pages_no; i++) { + struct page *page = pages[i]; + if (page == NULL) { + release_pages(pages, page_num); + vfree(pages); + return -EFAULT; + } + phys_addr[i] = (uintptr_t)page_to_phys(page); + } + + vfree(pages); + return 0; +} + +void release_shared_mem_page(uint64_t buf, uint32_t buf_size) +{ + uint32_t i; + uint64_t *phys_addr = NULL; + struct pagelist_info *page_info = NULL; + struct page *page = NULL; + + page_info = (struct pagelist_info *)(uintptr_t)buf; + phys_addr = (uint64_t *)(uintptr_t)buf + (sizeof(*page_info) / sizeof(uint64_t)); + + if (buf_size != sizeof(*page_info) + sizeof(uint64_t) * page_info->page_num) { + tloge("bad size, cannot release page\n"); + return; + } + + for (i = 0; i < page_info->page_num; i++) { + page = (struct page *)(uintptr_t)phys_to_page(phys_addr[i]); + if (page == NULL) + continue; + set_bit(PG_dirty, &page->flags); + put_page(page); + } +} +#endif + #ifdef CONFIG_SHARED_MEM_RESERVED #define CMD_MEM_MIN_SIZE 0x1000 #define SPI_MEM_MIN_SIZE 0x1000 #define OPERATION_MEM_MIN_SIZE 0x1000 +#define MAILBOX_BUF_MIN_SIZE 0x10 uint64_t g_cmd_mem_paddr; uint64_t g_cmd_mem_size; uint64_t g_mailbox_paddr; @@ -142,7 +234,7 @@ uintptr_t mailbox_page_address(mailbox_page_t *page) if (!page) return 0; - return (uintptr_t)*page; + return *page; } uintptr_t mailbox_virt_to_phys(uintptr_t addr) @@ -171,12 +263,17 @@ void free_operation(uint64_t op_vaddr) (void)op_vaddr; } -/* - * This function only for platform, CONFIG_LOG_POOL - * marco controls the log retention of soft reset feature. - * Enable COCNFIG_LOG_POOL macro, this function won't memset - * log pool memory, and the old log before reset can be retention. - */ +uint64_t get_mailbox_buffer_vaddr(uint32_t pool_count) +{ + (void)pool_count; + return g_shmem_start_virt + MAILBOX_POOL_SIZE + sizeof(struct tc_ns_operation); +} + +void free_mailbox_buffer(uint64_t op_vaddr) +{ + (void)op_vaddr; +} + uint64_t get_log_mem_vaddr(void) { uint64_t log_vaddr = (uint64_t)(uintptr_t)ioremap_cache(g_log_mem_paddr, g_log_mem_size); @@ -209,13 +306,7 @@ void free_log_mem(uint64_t log_vaddr) uint64_t get_cmd_mem_vaddr(void) { - uint64_t cmd_vaddr = (uint64_t)(uintptr_t)ioremap_cache(g_cmd_mem_paddr, g_cmd_mem_size); - if (cmd_vaddr == 0) { - tloge("io remap for cmd buffer failed\n"); - return 0; - } - (void)memset_s((void *)(uintptr_t)cmd_vaddr, g_cmd_mem_size, 0, g_cmd_mem_size); - return cmd_vaddr; + return get_reserved_cmd_vaddr_of(g_cmd_mem_paddr, g_cmd_mem_size); } uint64_t get_cmd_mem_paddr(uint64_t cmd_vaddr) @@ -277,7 +368,7 @@ uintptr_t mailbox_page_address(mailbox_page_t *page) if (!page) return 0; - return (uintptr_t)page_address(page); + return page_address(page); } uintptr_t mailbox_virt_to_phys(uintptr_t addr) @@ -285,7 +376,7 @@ uintptr_t mailbox_virt_to_phys(uintptr_t addr) if (!addr) return 0; - return virt_to_phys((void *)addr); + return virt_to_phys(addr); } mailbox_page_t *mailbox_virt_to_page(uint64_t ptr) @@ -298,7 +389,7 @@ mailbox_page_t *mailbox_virt_to_page(uint64_t ptr) uint64_t get_operation_vaddr(void) { - return (uint64_t)kzalloc(sizeof(struct tc_ns_operation), GFP_KERNEL); + return kzalloc(sizeof(struct tc_ns_operation), GFP_KERNEL); } void free_operation(uint64_t op_vaddr) @@ -306,7 +397,22 @@ void free_operation(uint64_t op_vaddr) if (!op_vaddr) return; - kfree((void *)op_vaddr); + kfree(op_vaddr); +} + +uint64_t get_mailbox_buffer_vaddr(uint32_t pool_count) +{ + if (pool_count == 0) + return 0; + return kzalloc(sizeof(struct mailbox_buffer) * pool_count, GFP_KERNEL); +} + +void free_mailbox_buffer(uint64_t op_vaddr) +{ + if (!op_vaddr) + return; + + kfree(op_vaddr); } uint64_t get_log_mem_vaddr(void) diff --git a/core/shared_mem.h b/core/shared_mem.h index a0d4176..998024c 100644 --- a/core/shared_mem.h +++ b/core/shared_mem.h @@ -30,6 +30,14 @@ typedef struct page mailbox_page_t; typedef uintptr_t mailbox_page_t; #endif +struct pagelist_info { + uint64_t page_num; + uint64_t page_size; + uint64_t sharedmem_offset; + uint64_t sharedmem_size; +}; + +uint64_t get_reserved_cmd_vaddr_of(phys_addr_t cmd_phys, uint64_t cmd_size); int load_tz_shared_mem(struct device_node *np); mailbox_page_t *mailbox_alloc_pages(int order); @@ -38,6 +46,8 @@ uintptr_t mailbox_page_address(mailbox_page_t *page); mailbox_page_t *mailbox_virt_to_page(uint64_t ptr); uint64_t get_operation_vaddr(void); void free_operation(uint64_t op_vaddr); +uint64_t get_mailbox_buffer_vaddr(uint32_t pool_count); +void free_mailbox_buffer(uint64_t op_vaddr); uint64_t get_log_mem_vaddr(void); uint64_t get_log_mem_paddr(uint64_t log_vaddr); @@ -51,4 +61,9 @@ void free_cmd_mem(uint64_t cmd_vaddr); uint64_t get_spi_mem_vaddr(void); uint64_t get_spi_mem_paddr(uintptr_t spi_vaddr); void free_spi_mem(uint64_t spi_vaddr); +#ifdef CONFIG_NOCOPY_SHAREDMEM +int fill_shared_mem_info(unint64_t start_vaddr, uint32_t pages_no, + uint32_t offset, uint32_t buffer_size, uint64_t info_addr); +void release_shared_mem_page(uint64_t buf, uint32_t buf_size); +#endif #endif diff --git a/core/smc_abi.c b/core/smc_abi.c new file mode 100644 index 0000000..5cf5bd8 --- /dev/null +++ b/core/smc_abi.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "smc_call.h" +#include "smc_smp.h" +#include "teek_ns_client.h" +#include "smc_abi.h" + +#ifndef CONFIG_ARCH32 +void do_smc_transport(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait) +{ + isb(); + wmb(); + do { + asm volatile( + "mov x0, %[fid]\n" + "mov x1, %[a1]\n" + "mov x2, %[a2]\n" + "mov x3, %[a3]\n" + "mov x4, %[a4]\n" + "mov x5, %[a5]\n" + "mov x6, %[a6]\n" + "mov x7, %[a7]\n" + "smc #0\n" + "str x0, [%[re0]]\n" + "str x1, [%[re1]]\n" + "str x2, [%[re2]]\n" + "str x3, [%[re3]]\n" : + [fid] "+r"(in->x0), + [a1] "+r"(in->x1), + [a2] "+r"(in->x2), + [a3] "+r"(in->x3), + [a4] "+r"(in->x4), + [a5] "+r"(in->x5), + [a6] "+r"(in->x6), + [a7] "+r"(in->x7): + [re0] "r"(&out->ret), + [re1] "r"(&out->exit_reason), + [re2] "r"(&out->ta), + [re3] "r"(&out->target) : + "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7"); + } while (out->ret == TSP_REQUEST && wait != 0); + isb(); + wmb(); +} +#else +void do_smc_transport(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait) +{ + isb(); + wmb(); + do { + asm volatile( + "mov r0, %[fid]\n" + "mov r1, %[a1]\n" + "mov r2, %[a2]\n" + "mov r3, %[a3]\n" + ".arch_extension sec\n" + "smc #0\n" + "str r0, [%[re0]]\n" + "str r1, [%[re1]]\n" + "str r2, [%[re2]]\n" + "str r3, [%[re3]]\n" : + [fid] "+r"(in->x0), + [a1] "+r"(in->x1), + [a2] "+r"(in->x2), + [a3] "+r"(in->x3): + [re0] "r"(&out->ret), + [re1] "r"(&out->exit_reason), + [re2] "r"(&out->ta), + [re3] "r"(&out->target) : + "r0", "r1", "r2", "r3"); + } while (out->ret == TSP_REQUEST && wait != 0); + isb(); + wmb(); +} +#endif + +void smc_req(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait) +{ + do_smc_transport(in, out, wait); +} diff --git a/core/smc_smp.c b/core/smc_smp.c index 8857c7e..53139bc 100644 --- a/core/smc_smp.c +++ b/core/smc_smp.c @@ -16,6 +16,8 @@ * GNU General Public License for more details. */ #include "smc_smp.h" +#include +#include #include #include #include @@ -40,6 +42,7 @@ #include #include #include +#include #if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE) #include @@ -66,9 +69,7 @@ #include "secs_power_ctrl.h" #include "shared_mem.h" #include "internal_functions.h" -#ifdef CONFIG_SMC_HOOK -#include "smc_hook.h" -#endif +#include "smc_call.h" #define PREEMPT_COUNT 10000 #define HZ_COUNT 10 @@ -101,21 +102,6 @@ /* Current state of the system */ static bool g_sys_crash; -struct smc_in_params { - unsigned long x0; - unsigned long x1; - unsigned long x2; - unsigned long x3; - unsigned long x4; -}; - -struct smc_out_params { - unsigned long ret; - unsigned long exit_reason; - unsigned long ta; - unsigned long target; -}; - struct shadow_work { struct kthread_work kthwork; struct work_struct work; @@ -126,7 +112,7 @@ unsigned long g_shadow_thread_id = 0; static struct task_struct *g_siq_thread; static struct task_struct *g_smc_svc_thread; static struct task_struct *g_ipi_helper_thread; -static struct kthread_worker g_ipi_helper_worker; +static struct kthread_worker *g_ipi_helper_worker = NULL; enum cmd_reuse { CLEAR, /* clear this cmd index */ @@ -178,29 +164,6 @@ enum smc_ops_exit { #define SHADOW_EXIT_RUN 0x1234dead #define SMC_EXIT_TARGET_SHADOW_EXIT 0x1 -#define SYM_NAME_LEN_MAX 16 -#define SYM_NAME_LEN_1 7 -#define SYM_NAME_LEN_2 4 -#define CRASH_REG_NUM 3 -#define LOW_FOUR_BITE 4 - -union crash_inf { - uint64_t crash_reg[CRASH_REG_NUM]; - struct { - uint8_t halt_reason : LOW_FOUR_BITE; - uint8_t app : LOW_FOUR_BITE; - char sym_name[SYM_NAME_LEN_1]; - uint16_t off; - uint16_t size; - uint32_t far; - uint32_t fault; - union { - char sym_name_append[SYM_NAME_LEN_2]; - uint32_t elr; - }; - } crash_msg; -}; - #define compile_time_assert(cond, msg) typedef char g_assert_##msg[(cond) ? 1 : -1] #ifndef CONFIG_BIG_SESSION @@ -208,6 +171,36 @@ compile_time_assert(sizeof(struct tc_ns_smc_queue) <= PAGE_SIZE, size_of_tc_ns_smc_queue_too_large); #endif +static bool g_reserved_cmd_buffer = false; +static u64 g_cmd_size = 0; +static bool g_tz_uefi_enable = false; + +#ifndef CONFIG_TZDRIVER_MODULE +static int __init tz_check_uefi_enable_func(char *str) +{ + if (str != NULL && *str == '1') + g_tz_uefi_enable = true; + + return 0; +} +early_param("tz_uefi_enable", tz_check_uefi_enable_func); +#endif + +#define MIN_CMDLINE_SIZE 0x1000 +static int reserved_cmdline(struct reserved_mem *rmem) +{ + if (g_tz_uefi_enable && rmem && rmem->size >= MIN_CMDLINE_SIZE) { + g_cmd_phys = rmem->base; + g_cmd_size = rmem->size; + g_reserved_cmd_buffer = true; + } else { + g_reserved_cmd_buffer = false; + } + + return 0; +} +RESERVEDMEM_OF_DECLARE(g_teeos_cmdline, "teeos-cmdline", reserved_cmdline); + static void acquire_smc_buf_lock(smc_buf_lock_t *lock) { int ret; @@ -400,7 +393,7 @@ static void show_in_bitmap(int *cmd_in, uint32_t len) } } bitmap[MAX_SMC_CMD] = '\0'; - tloge("in bitmap: %s\n", bitmap); + tlogi("in bitmap: %s\n", bitmap); } static void show_out_bitmap(int *cmd_out, uint32_t len) @@ -421,7 +414,7 @@ static void show_out_bitmap(int *cmd_out, uint32_t len) } } bitmap[MAX_SMC_CMD] = '\0'; - tloge("out bitmap: %s\n", bitmap); + tlogi("out bitmap: %s\n", bitmap); } static void show_doing_bitmap(void) @@ -438,7 +431,7 @@ static void show_doing_bitmap(void) bitmap[idx] = '0'; } bitmap[MAX_SMC_CMD] = '\0'; - tloge("doing bitmap: %s\n", bitmap); + tlogi("doing bitmap: %s\n", bitmap); } static void show_single_cmd_info(const int *cmd, uint32_t len) @@ -451,7 +444,7 @@ static void show_single_cmd_info(const int *cmd, uint32_t len) for (idx = 0; idx < MAX_SMC_CMD; idx++) { if (cmd[idx] == -1) break; - tloge("cmd[%d]: cmd_id=%u, ca_pid=%u, dev_id = 0x%x, " + tlogi("cmd[%d]: cmd_id=%u, ca_pid=%u, dev_id = 0x%x, " "event_nr=%u, ret_val=0x%x\n", cmd[idx], g_cmd_data->in[cmd[idx]].cmd_id, @@ -492,10 +485,10 @@ void show_cmd_bitmap(void) show_doing_bitmap(); show_out_bitmap(cmd_out, MAX_SMC_CMD); - tloge("cmd in value:\n"); + tlogi("cmd in value:\n"); show_single_cmd_info(cmd_in, MAX_SMC_CMD); - tloge("cmd_out value:\n"); + tlogi("cmd_out value:\n"); show_single_cmd_info(cmd_out, MAX_SMC_CMD); release_smc_buf_lock(&g_cmd_data->smc_lock); @@ -704,104 +697,73 @@ static void set_smc_send_arg(struct smc_in_params *in_param, in_param->x2, in_param->x3, in_param->x4); } -#ifndef CONFIG_ARCH32 -static void send_asm_smc_cmd(struct smc_in_params *in_param, - struct smc_out_params *out_param) +static void send_smc_cmd(struct smc_in_params *in_param, + struct smc_out_params *out_param, uint8_t wait) { - do { - asm volatile( - "mov x0, %[fid]\n" - "mov x1, %[a1]\n" - "mov x2, %[a2]\n" - "mov x3, %[a3]\n" - "mov x4, %[a4]\n" - "smc #0\n" - "str x0, [%[re0]]\n" - "str x1, [%[re1]]\n" - "str x2, [%[re2]]\n" - "str x3, [%[re3]]\n" : - [fid] "+r"(in_param->x0), - [a1] "+r"(in_param->x1), - [a2] "+r"(in_param->x2), - [a3] "+r"(in_param->x3), - [a4] "+r"(in_param->x4) : - [re0] "r"(&out_param->ret), - [re1] "r"(&out_param->exit_reason), - [re2] "r"(&out_param->ta), - [re3] "r"(&out_param->target) : - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", - "x8", "x9", "x10", "x11", "x12", "x13", - "x14", "x15", "x16", "x17"); - } while (0); + smc_req(in_param, out_param, wait); } -#else -static void send_asm_smc_cmd(struct smc_in_params *in_param, + +static void send_smc_cmd_with_retry(struct smc_in_params *in_param, struct smc_out_params *out_param) { - do { - asm volatile( - "mov r0, %[fid]\n" - "mov r1, %[a1]\n" - "mov r2, %[a2]\n" - "mov r3, %[a3]\n" - ".arch_extension sec\n" - "smc #0\n" - "str r0, [%[re0]]\n" - "str r1, [%[re1]]\n" - "str r2, [%[re2]]\n" - "str r3, [%[re3]]\n" : - [fid] "+r"(in_param->x0), - [a1] "+r"(in_param->x1), - [a2] "+r"(in_param->x2), - [a3] "+r"(in_param->x3): - [re0] "r"(&out_param->ret), - [re1] "r"(&out_param->exit_reason), - [re2] "r"(&out_param->ta), - [re3] "r"(&out_param->target) : - "r0", "r1", "r2", "r3"); - } while (0); -} +#if (CONFIG_CPU_AFF_NR != 0) + struct cpumask old_mask; + set_cpu_strategy(&old_mask); #endif +retry: + send_smc_cmd(in_param, out_param, 0); + + if (out_param->exit_reason == SMC_EXIT_PREEMPTED + && out_param->ret == TSP_RESPONSE) { +#if (!defined(CONFIG_PREEMPT)) || defined(CONFIG_RTOS_PREEMPT_OFF) + cond_resched(); +#endif + in_param->x1 = SMC_OPS_SCHEDTO; + goto retry; + } +#if (CONFIG_CPU_AFF_NR != 0) + restore_cpu(&old_mask); +#endif +} + #ifdef CONFIG_TEE_REBOOT -int send_smc_cmd_rebooting(uint32_t cmd_id, phys_addr_t cmd_addr, uint32_t cmd_type, - const struct tc_ns_smc_cmd *in_cmd) +int send_smc_cmd_rebooting(uint32_t cmd_id, const struct tc_ns_smc_cmd *in_cmd) { struct tc_ns_smc_cmd cmd = { {0}, 0 }; - struct smc_in_params in_param = { cmd_id, cmd_addr, cmd_type, cmd_addr >> ADDR_TRANS_NUM, TEE_ERROR_IS_DEAD}; + struct smc_in_params in_param = {cmd_id, 0, 0, 0, TEE_ERROR_IS_DEAD}; struct smc_out_params out_param = {0}; + int cmd_index = 0; if (in_cmd != NULL) { if (memcpy_s(&cmd, sizeof(cmd), in_cmd, sizeof(*in_cmd)) != EOK) { tloge("memcpy in cmd failed\n"); return -EFAULT; } +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + cmd.nsid = task_active_pid_ns(current)->ns.inum; +#else + cmd.nsid = PROC_PID_INIT_INO; +#endif - if (occupy_free_smc_in_entry(&cmd) == -1) { + cmd_index = occupy_free_smc_in_entry(&cmd); + if (cmd_index == -1) { tloge("there's no more smc entry\n"); return -ENOMEM; } +#ifdef CONFIG_TEE_UPGRADE + in_param.x2 = cmd_index; +#endif } -retry: - isb(); - wmb(); - send_asm_smc_cmd(&in_param, &out_param); - isb(); - wmb(); - - if (out_param.exit_reason == SMC_EXIT_PREEMPTED) - goto retry; + send_smc_cmd_with_retry(&in_param, &out_param); return out_param.exit_reason; } #else -int send_smc_cmd_rebooting(uint32_t cmd_id, phys_addr_t cmd_addr, uint32_t cmd_type, - const struct tc_ns_smc_cmd *in_cmd) +int send_smc_cmd_rebooting(uint32_t cmd_id, const struct tc_ns_smc_cmd *in_cmd) { (void)cmd_id; - (void)cmd_addr; - (void)cmd_type; (void)in_cmd; return 0; } @@ -821,13 +783,9 @@ static noinline int smp_smc_send(uint32_t cmd, unsigned long ops, unsigned long #endif retry: set_smc_send_arg(&in_param, secret, ops); - isb(); - wmb(); tee_trace_add_event(SMC_SEND, 0); - send_asm_smc_cmd(&in_param, &out_param); + send_smc_cmd(&in_param, &out_param, 0); tee_trace_add_event(SMC_DONE, 0); - isb(); - wmb(); tlogd("[cpu %d] return val %lx exit_reason %lx ta %lx targ %lx\n", raw_smp_processor_id(), out_param.ret, out_param.exit_reason, out_param.ta, out_param.target); @@ -861,88 +819,34 @@ retry: return (int)out_param.ret; } -#ifndef CONFIG_ARCH32 -static uint64_t send_smc_cmd(uint32_t cmd, phys_addr_t cmd_addr, - uint32_t cmd_type, uint8_t wait) -{ - struct smc_in_params in_param = { cmd, cmd_addr, cmd_type, cmd_addr >> ADDR_TRANS_NUM, 0 }; - uint64_t ret = 0; - - do { - asm volatile( - "mov x0, %[fid]\n" - "mov x1, %[a1]\n" - "mov x2, %[a2]\n" - "mov x3, %[a3]\n" - "mov x4, %[a4]\n" - "smc #0\n" - "str x0, [%[re0]]\n": - [fid] "+r"(in_param.x0), - [a1] "+r"(in_param.x1), - [a2] "+r"(in_param.x2), - [a3] "+r"(in_param.x3), - [a4] "+r"(in_param.x0): - [re0] "r"(&ret): - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7"); - } while (ret == TSP_REQUEST && wait != 0); - - isb(); - wmb(); - - return ret; -} -#else -static uint32_t send_smc_cmd(uint32_t cmd, phys_addr_t cmd_addr, - uint32_t cmd_type, uint8_t wait) -{ - struct smc_in_params in_param = { cmd, cmd_addr, cmd_type, (uint64_t)cmd_addr >> ADDR_TRANS_NUM }; - uint32_t ret = 0; - - do { - asm volatile( - "mov r0, %[fid]\n" - "mov r1, %[a1]\n" - "mov r2, %[a2]\n" - "mov r3, %[a3]\n" - "mov r4, %[a4]\n" - ".arch_extension sec\n" - "smc #0\n" - "str r0, [%[re0]]\n" : - [fid] "+r"(in_param.x0), - [a1] "+r"(in_param.x1), - [a2] "+r"(in_param.x2), - [a3] "+r"(in_param.x3), - [a4] "+r"(in_param.x0) : - [re0] "r"(&ret) : - "r0", "r1", "r2", "r3", "r4"); - } while (ret == TSP_REQUEST && wait); - - isb(); - wmb(); - - return ret; -} -#endif - -unsigned long raw_smc_send(uint32_t cmd, phys_addr_t cmd_addr, - uint32_t cmd_type, uint8_t wait) +static unsigned long raw_smc_send(uint32_t cmd, uint32_t param1, + uint32_t param2, uint8_t wait) { - unsigned long x0; + struct smc_in_params in_param = {cmd, param1, param2}; + struct smc_out_params out_param = {0}; #if (CONFIG_CPU_AFF_NR != 0) struct cpumask old_mask; set_cpu_strategy(&old_mask); #endif - x0 = send_smc_cmd(cmd, cmd_addr, cmd_type, wait); + + send_smc_cmd(&in_param, &out_param, wait); + #if (CONFIG_CPU_AFF_NR != 0) restore_cpu(&old_mask); #endif - return x0; + return out_param.ret; } -static void siq_dump(phys_addr_t mode, uint32_t siq_mode) +static void siq_dump(uint32_t mode, uint32_t siq_mode) { - (void)raw_smc_send(TSP_REE_SIQ, mode, 0, false); + int ret = raw_smc_send(TSP_REE_SIQ, mode, 0, false); + if (ret == TSP_CRASH) { + tloge("TEEOS has crashed!\n"); + g_sys_crash = true; + cmd_monitor_ta_crash(TYPE_CRASH_TEE, NULL, 0); + } + if (siq_mode == SIQ_DUMP_TIMEOUT) { tz_log_write(); } else if (siq_mode == SIQ_DUMP_SHELL) { @@ -982,6 +886,7 @@ static uint32_t get_undo_siq_index(void) #define RUN_SIQ_THREAD 1 #define STOP_SIQ_THREAD 2 +#define MODE_DUMP 1 static int siq_thread_fn(void *arg) { int ret; @@ -1003,7 +908,7 @@ static int siq_thread_fn(void *arg) i = get_undo_siq_index(); if (i >= MAX_SIQ_NUM) break; - siq_dump((phys_addr_t)(1), g_siq_queue[i]); + siq_dump(MODE_DUMP, g_siq_queue[i]); g_siq_queue[i] = 0; } while (true); atomic_set(&g_siq_th_run, 0); @@ -1050,15 +955,17 @@ static void upload_audit_event(unsigned int eventindex) } #endif -static void cmd_result_check(const struct tc_ns_smc_cmd *cmd) +static void cmd_result_check(const struct tc_ns_smc_cmd *cmd, int cmd_index) { if (cmd->ret_val == (int)TEEC_PENDING || cmd->ret_val == (int)TEEC_PENDING2) tlogd("wakeup command %u\n", cmd->event_nr); if (cmd->ret_val == (int)TEE_ERROR_TAGET_DEAD) { - tloge("error smc call: ret = %x and cmd.err_origin=%x\n", - cmd->ret_val, cmd->err_origin); - cmd_monitor_ta_crash(TYPE_CRASH_TA); + bool ta_killed = g_cmd_data->in[cmd_index].cmd_id == GLOBAL_CMD_ID_KILL_TASK; + tloge("error smc call: ret = %x and cmd.err_origin=%x, [ta is %s]\n", + cmd->ret_val, cmd->err_origin, (ta_killed == true) ? "killed" : "crash"); + cmd_monitor_ta_crash((ta_killed == true) ? TYPE_KILLED_TA : TYPE_CRASH_TA, + cmd->uuid, sizeof(struct tc_uuid)); ta_crash_report_log(); } else if (cmd->ret_val == (int)TEEC_ERROR_TUI_NOT_AVAILABLE) { do_ns_tui_release(); @@ -1095,88 +1002,20 @@ static void set_shadow_smc_param(struct smc_in_params *in_params, } } -#ifndef CONFIG_ARCH32 static void shadow_wo_pm(const void *arg, struct smc_out_params *out_params, int *n_idled) { struct smc_in_params in_params = { - TSP_REQUEST, SMC_OPS_START_SHADOW, current->pid, 0, *(const u64 *)arg + TSP_REQUEST, SMC_OPS_START_SHADOW, current->pid, 0, *(unsigned long *)arg }; set_shadow_smc_param(&in_params, out_params, n_idled); - isb(); - wmb(); tlogd("%s: [cpu %d] x0=%lx x1=%lx x2=%lx x3=%lx x4=%lx\n", __func__, raw_smp_processor_id(), in_params.x0, in_params.x1, in_params.x2, in_params.x3, in_params.x4); - do { - asm volatile( - "mov x0, %[fid]\n" - "mov x1, %[a1]\n" - "mov x2, %[a2]\n" - "mov x3, %[a3]\n" - "mov x4, %[a4]\n" - "smc #0\n" - "str x0, [%[re0]]\n" - "str x1, [%[re1]]\n" - "str x2, [%[re2]]\n" - "str x3, [%[re3]]\n" : - [fid] "+r"(in_params.x0), [a1] "+r"(in_params.x1), - [a2] "+r"(in_params.x2), [a3] "+r"(in_params.x3), - [a4] "+r"(in_params.x4) : - [re0] "r"(&out_params->ret), - [re1] "r"(&out_params->exit_reason), - [re2] "r"(&out_params->ta), - [re3] "r"(&out_params->target) : - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", - "x8", "x9", "x10", "x11", "x12", "x13", - "x14", "x15", "x16", "x17"); - } while (0); - isb(); - wmb(); + smc_req(&in_params, out_params, 0); } -#else -static void shadow_wo_pm(const void *arg, struct smc_out_params *out_params, - int *n_idled) -{ - struct smc_in_params in_params = { - TSP_REQUEST, SMC_OPS_START_SHADOW, current->pid, 0, *(const u32 *)arg - }; - - set_shadow_smc_param(&in_params, out_params, n_idled); - isb(); - wmb(); - tlogd("%s: [cpu %d] x0=%lx x1=%lx x2=%lx x3=%lx x4=%lx\n", - __func__, raw_smp_processor_id(), in_params.x0, in_params.x1, - in_params.x2, in_params.x3, in_params.x4); - do { - asm volatile( - "mov r0, %[fid]\n" - "mov r1, %[a1]\n" - "mov r2, %[a2]\n" - "mov r3, %[a3]\n" - "mov r4, %[a4]\n" - ".arch_extension sec\n" - "smc #0\n" - "str r0, [%[re0]]\n" - "str r1, [%[re1]]\n" - "str r2, [%[re2]]\n" - "str r3, [%[re3]]\n" : - [fid] "+r"(in_params.x0), [a1] "+r"(in_params.x1), - [a2] "+r"(in_params.x2), [a3] "+r"(in_params.x3), - [a4] "+r"(in_params.x4) : - [re0] "r"(&out_params->ret), - [re1] "r"(&out_params->exit_reason), - [re2] "r"(&out_params->ta), - [re3] "r"(&out_params->target) : - "r0", "r1", "r2", "r3"); - } while (0); - - isb(); - wmb(); -} -#endif static void set_preempted_counter(int *n_preempted, int *n_idled, struct pending_entry *pe) @@ -1236,7 +1075,7 @@ static bool check_shadow_crash(uint64_t crash_reason, int *ret_val) tloge("power down cc failed\n"); g_sys_crash = true; - cmd_monitor_ta_crash(TYPE_CRASH_TEE); + cmd_monitor_ta_crash(TYPE_CRASH_TEE, NULL, 0); report_log_system_error(); *ret_val = -1; return true; @@ -1332,7 +1171,18 @@ static void shadow_work_func(struct kthread_work *work) } tlogd("%s: create shadow thread %lu for target %llx\n", __func__, g_shadow_thread_id, *target_arg); +#if CONFIG_CPU_AFF_NR + struct cpumask shadow_mask; + unsigned int i; + + cpumask_clear(&shadow_mask); + for (i = 0; i < CONFIG_CPU_AFF_NR; i++) + cpumask_set_cpu(i, &shadow_mask); + + koadpt_kthread_bind_mask(shadow_thread, &shadow_mask); +#else tz_kthread_bind_mask(shadow_thread); +#endif wake_up_process(shadow_thread); } @@ -1344,7 +1194,7 @@ static int proc_smc_wakeup_ca(pid_t ca, int which) struct pending_entry *pe = find_pending_entry(ca); if (!pe) { - (void)raw_smc_send(TSP_REE_SIQ, (phys_addr_t)ca, 0, false); + (void)raw_smc_send(TSP_REE_SIQ, (uint32_t)ca, 0, false); tlogd("invalid ca pid=%d for pending entry\n", (int)ca); return -1; @@ -1412,9 +1262,9 @@ int smc_queue_shadow_worker(uint64_t target) }; #if (KERNEL_VERSION(4, 9, 0) > LINUX_VERSION_CODE) - if (!queue_kthread_work(&g_ipi_helper_worker, &work.kthwork)) { + if (!queue_kthread_work(g_ipi_helper_worker, &work.kthwork)) { #else - if (!kthread_queue_work(&g_ipi_helper_worker, &work.kthwork)) { + if (!kthread_queue_work(g_ipi_helper_worker, &work.kthwork)) { #endif tloge("ipi helper work fail queue, was already pending\n"); return -1; @@ -1487,15 +1337,15 @@ static int smc_ops_normal(struct cmd_reuse_info *info, static int smp_smc_send_cmd_done(int cmd_index, struct tc_ns_smc_cmd *cmd, struct tc_ns_smc_cmd *in) { - (void)cmd_index; - cmd_result_check(cmd); + cmd_result_check(cmd, cmd_index); switch (cmd->ret_val) { case TEEC_PENDING2: { unsigned int agent_id = cmd->agent_id; + unsigned int nsid = cmd->nsid; /* If the agent does not exist post * the answer right back to the TEE */ - if (agent_process_work(cmd, agent_id) != 0) + if (agent_process_work(cmd, agent_id, nsid) != 0) tloge("agent process work failed\n"); return PENDING2_RETRY; } @@ -1577,7 +1427,7 @@ static int smp_smc_send_process(struct tc_ns_smc_cmd *cmd, u64 ops, struct smc_cmd_ret *cmd_ret, int cmd_index) { int ret; - + unsigned long ca; tlogd("smc send start cmd_id = %u, ca = %u\n", cmd->cmd_id, cmd->ca_pid); @@ -1587,11 +1437,10 @@ static int smp_smc_send_process(struct tc_ns_smc_cmd *cmd, u64 ops, return -1; } -#ifdef CONFIG_SMC_HOOK - call_smc_pre_hook(cmd->cmd_id); -#endif + ca = is_ccos() ? (cmd_index) : ((unsigned long)(uint32_t)(current->pid)); + ret = smp_smc_send(TSP_REQUEST, (unsigned long)ops, - (unsigned long)(uint32_t)(current->pid), cmd_ret, ops != SMC_OPS_ABORT_TASK); + ca, cmd_ret, ops != SMC_OPS_ABORT_TASK); if (power_down_cc() != 0) { tloge("power down cc failed\n"); @@ -1613,7 +1462,7 @@ static int smp_smc_send_process(struct tc_ns_smc_cmd *cmd, u64 ops, print_crash_msg(&crash_info); g_sys_crash = true; - cmd_monitor_ta_crash(TYPE_CRASH_TEE); + cmd_monitor_ta_crash(TYPE_CRASH_TEE, NULL, 0); tee_wake_up_reboot(); #ifndef CONFIG_TEE_REBOOT @@ -1640,6 +1489,13 @@ static int init_for_smc_send(struct tc_ns_smc_cmd *in, } in->ca_pid = (unsigned int)current->pid; +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + if (in->nsid == 0) + in->nsid = task_active_pid_ns(current)->ns.inum; +#else + in->nsid = PROC_PID_INIT_INO; +#endif + if (reuse) return 0; @@ -1768,7 +1624,7 @@ enum smc_status_t { static long wait_event_internal(struct pending_entry *pe, struct timeout_step_t *step) { if (!current->mm) { - return wait_event_interruptible_timeout(pe->wq, atomic_read(&pe->run), + return wait_event_freezable_timeout(pe->wq, atomic_read(&pe->run), step->steps[step->cur]); } else { return wait_event_timeout(pe->wq, atomic_read(&pe->run), @@ -1804,7 +1660,7 @@ resleep: */ if (timer_no_irq) { *ops = SMC_OPS_SCHEDTO; - return PD_TIMEOUT; + return PD_WAKEUP; } else { goto resleep; } @@ -1877,6 +1733,13 @@ static enum smc_status_t handle_cmd_working_done( return ST_DONE; } +static void set_cmd_reuse_info(struct cmd_reuse_info *info, struct tc_ns_smc_cmd *in) +{ + info->saved_index = (int)in->event_nr; + info->cmd_index = (int)in->event_nr; + info->cmd_usage = RESEND; +} + static int smp_smc_send_func(struct tc_ns_smc_cmd *in, bool reuse) { struct cmd_reuse_info info = { 0, 0, CLEAR }; @@ -1890,18 +1753,18 @@ static int smp_smc_send_func(struct tc_ns_smc_cmd *in, bool reuse) if (init_for_smc_send(in, &pe, &cmd, reuse) != 0) return TEEC_ERROR_GENERIC; - if (reuse) { - info.saved_index = (int)in->event_nr; - info.cmd_index = (int)in->event_nr; - info.cmd_usage = RESEND; - } + if (reuse) + set_cmd_reuse_info(&info, in); ops = SMC_OPS_NORMAL; retry: #ifdef CONFIG_TEE_REBOOT - if (is_tee_rebooting() && in->cmd_id == GLOBAL_CMD_ID_SET_SERVE_CMD) + if (is_tee_rebooting() && in->cmd_id == GLOBAL_CMD_ID_SET_SERVE_CMD) { + release_pending_entry(pe); return TEE_ERROR_IS_DEAD; + } #endif + set_timeout_step(&timeout_step); if (smc_ops_normal(&info, &cmd, ops) != 0) { @@ -1937,6 +1800,7 @@ clean: static int smc_svc_thread_fn(void *arg) { (void)arg; + set_freezable(); while (!kthread_should_stop()) { struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; int ret; @@ -1991,6 +1855,13 @@ static int proc_tc_ns_smc(struct tc_ns_smc_cmd *cmd, bool reuse) return TEE_ERROR_IS_DEAD; } +#ifdef CONFIG_TEE_UPGRADE + if (is_tee_rebooting()) { + tloge("tee is upgrading\n"); + return TEE_ERROR_IS_DEAD; + } +#endif + if (!cmd) { tloge("invalid cmd\n"); return TEEC_ERROR_GENERIC; @@ -2015,25 +1886,29 @@ int tc_ns_smc_with_no_nr(struct tc_ns_smc_cmd *cmd) return proc_tc_ns_smc(cmd, true); } -static void smc_work_no_wait(uint32_t type) +void send_smc_cmd_buffer(bool tee_is_dead) { - (void)raw_smc_send(TSP_REQUEST, g_cmd_phys, type, true); -} + struct smc_in_params in_param = {TSP_REQUEST, g_cmd_phys, TC_NS_CMD_TYPE_SECURE_CONFIG, + g_cmd_phys >> ADDR_TRANS_NUM}; + struct smc_out_params out_param = {0}; -void send_smc_reset_cmd_buffer(void) -{ - send_smc_cmd_rebooting(TSP_REQUEST, g_cmd_phys, TC_NS_CMD_TYPE_SECURE_CONFIG, NULL); + if (tee_is_dead) + in_param.x4 = TEE_ERROR_IS_DEAD; + + send_smc_cmd_with_retry(&in_param, &out_param); } static void smc_work_set_cmd_buffer(struct work_struct *work) { (void)work; - smc_work_no_wait(TC_NS_CMD_TYPE_SECURE_CONFIG); + send_smc_cmd_buffer(false); } void smc_set_cmd_buffer(void) { struct work_struct work; + if (g_reserved_cmd_buffer) + return; INIT_WORK_ONSTACK(&work, smc_work_set_cmd_buffer); /* Run work on CPU 0 */ @@ -2044,6 +1919,14 @@ void smc_set_cmd_buffer(void) static int alloc_cmd_buffer(void) { + if (g_reserved_cmd_buffer) { + tlogi("use reserved cmd buffer"); + g_cmd_data = (struct tc_ns_smc_queue *)get_reserved_cmd_vaddr_of(g_cmd_phys, (uint64_t)g_cmd_size); + if (!g_cmd_data) + return -ENOMEM; + + return 0; + } g_cmd_data = (struct tc_ns_smc_queue *)(uintptr_t)get_cmd_mem_vaddr(); if (!g_cmd_data) return -ENOMEM; @@ -2068,9 +1951,9 @@ static int init_smc_related_rsrc(const struct device *class_dev) koadpt_kthread_bind_mask(g_siq_thread, &new_mask); /* some products specify the cpu that kthread need to bind */ tz_kthread_bind_mask(g_siq_thread); - kthread_init_worker(&g_ipi_helper_worker); + g_ipi_helper_worker = kthread_create_worker(0, "g_ipi_helper_worker"); g_ipi_helper_thread = kthread_create(kthread_worker_fn, - &g_ipi_helper_worker, "ipihelper"); + g_ipi_helper_worker, "ipihelper"); if (IS_ERR_OR_NULL(g_ipi_helper_thread)) { dev_err(class_dev, "couldn't create ipi helper threads %ld\n", PTR_ERR(g_ipi_helper_thread)); @@ -2088,11 +1971,16 @@ static int init_smc_related_rsrc(const struct device *class_dev) return 0; } -static int parse_params_from_tee(void) +int parse_params_from_tee(void) { int ret; void *buffer = NULL; + if (g_reserved_cmd_buffer) { + tlogw("uefi mode, not check teeos compat level\n"); + return 0; + } + buffer = (void *)(g_cmd_data->in); ret = check_teeos_compat_level((uint32_t *)buffer, COMPAT_LEVEL_BUF_LEN); @@ -2185,8 +2073,10 @@ void svc_thread_release(void) void free_smc_data(void) { struct pending_entry *pe = NULL, *temp = NULL; - - free_cmd_mem((uint64_t)(uintptr_t)g_cmd_data); + if (g_reserved_cmd_buffer) + iounmap((void __iomem *)g_cmd_data); + else + free_cmd_mem((uint64_t)(uintptr_t)g_cmd_data); smc_wakeup_broadcast(); svc_thread_release(); if (!IS_ERR_OR_NULL(g_siq_thread)) { @@ -2197,10 +2087,12 @@ void free_smc_data(void) } #if (KERNEL_VERSION(4, 9, 0) > LINUX_VERSION_CODE) - flush_kthread_worker(&g_ipi_helper_worker); + flush_kthread_worker(g_ipi_helper_worker); #else - kthread_flush_worker(&g_ipi_helper_worker); + kthread_flush_worker(g_ipi_helper_worker); #endif + kthread_destroy_worker(g_ipi_helper_worker); + g_ipi_helper_worker = NULL; if (!IS_ERR_OR_NULL(g_ipi_helper_thread)) { kthread_stop(g_ipi_helper_thread); g_ipi_helper_thread = NULL; diff --git a/core/smc_smp.h b/core/smc_smp.h index c36e797..d853725 100644 --- a/core/smc_smp.h +++ b/core/smc_smp.h @@ -51,7 +51,7 @@ struct pending_entry { }; #ifdef CONFIG_BIG_SESSION -#define MAX_SMC_CMD CONFIG_BIG_SESSION +#define MAX_SMC_CMD (CONFIG_BIG_SESSION * 10) #else #define MAX_SMC_CMD 18 #endif @@ -102,6 +102,29 @@ struct tc_ns_smc_queue { struct tc_ns_smc_cmd out[MAX_SMC_CMD]; }; +#define SYM_NAME_LEN_MAX 16 +#define SYM_NAME_LEN_1 7 +#define SYM_NAME_LEN_2 4 +#define CRASH_REG_NUM 3 +#define LOW_FOUR_BITE 4 + +union crash_inf { + uint64_t crash_reg[CRASH_REG_NUM]; + struct { + uint8_t halt_reason : LOW_FOUR_BITE; + uint8_t app : LOW_FOUR_BITE; + char sym_name[SYM_NAME_LEN_1]; + uint16_t off; + uint16_t size; + uint32_t far; + uint32_t fault; + union { + char sym_name_append[SYM_NAME_LEN_2]; + uint32_t elr; + }; + } crash_msg; +}; + #define RESLEEP_TIMEOUT 15 bool sigkill_pending(struct task_struct *tsk); @@ -122,13 +145,11 @@ void foreach_pending_entry(void (*func)(struct pending_entry *)); void put_pending_entry(struct pending_entry *pe); void show_cmd_bitmap(void); void wakeup_tc_siq(uint32_t siq_mode); -void smc_set_cmd_buffer(void); -unsigned long raw_smc_send(uint32_t cmd, phys_addr_t cmd_addr, uint32_t cmd_type, uint8_t wait); void occupy_clean_cmd_buf(void); void clr_system_crash_flag(void); void svc_thread_release(void); -int send_smc_cmd_rebooting(uint32_t cmd_id, phys_addr_t cmd_addr, uint32_t cmd_type, - const struct tc_ns_smc_cmd *in_cmd); -void send_smc_reset_cmd_buffer(void); +int send_smc_cmd_rebooting(uint32_t cmd_id, const struct tc_ns_smc_cmd *in_cmd); +void send_smc_cmd_buffer(bool tee_is_dead); +int parse_params_from_tee(void); #endif diff --git a/core/tc_client_driver.c b/core/tc_client_driver.c index f3f0d7a..cea5c5f 100644 --- a/core/tc_client_driver.c +++ b/core/tc_client_driver.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -72,17 +73,34 @@ #include "client_hash_auth.h" #include "auth_base_impl.h" #include "tlogger.h" +#include "tzdebug.h" #include "session_manager.h" #include "internal_functions.h" #include "ko_adapt.h" #include "tz_pm.h" #include "reserved_mempool.h" +#ifdef CONFIG_TEE_REBOOT +#include "reboot.h" +#endif + +#ifdef CONFIG_FFA_SUPPORT +#include "ffa_abi.h" +#endif + +#ifdef CONFIG_TEE_TELEPORT_SUPPORT +#include "tee_portal.h" +#endif + +#include "tee_info.h" static struct class *g_driver_class; static struct device_node *g_dev_node; struct dev_node g_tc_client; struct dev_node g_tc_private; +#if defined(CONFIG_CONFIDENTIAL_CONTAINER) || defined(CONFIG_TEE_TELEPORT_SUPPORT) +struct dev_node g_tc_cvm; +#endif #ifdef CONFIG_ACPI static int g_acpi_irq; @@ -95,12 +113,47 @@ static DEFINE_MUTEX(g_set_ca_hash_lock); /* dev node list and itself has mutex to avoid race */ struct tc_ns_dev_list g_tc_ns_dev_list; +static bool g_init_succ = false; + +static void set_tz_init_flag(void) +{ + g_init_succ = true; +} + +static void clear_tz_init_flag(void) +{ + g_init_succ = false; +} + +bool get_tz_init_flag(void) +{ + return g_init_succ; +} struct tc_ns_dev_list *get_dev_list(void) { return &g_tc_ns_dev_list; } +int tc_ns_register_host_nsid(void) +{ + struct tc_ns_smc_cmd smc_cmd = {{0}, 0}; + int ret = 0; + smc_cmd.cmd_type = CMD_TYPE_GLOBAL; + smc_cmd.cmd_id = GLOBAL_CMD_ID_REGISTER_HOST_NSID; + + if (is_tee_rebooting()) + ret = send_smc_cmd_rebooting(TSP_REQUEST, &smc_cmd); + else + ret = tc_ns_smc(&smc_cmd); + + if (ret != 0) { + ret = -EPERM; + tloge("smc call return error ret 0x%x\n", smc_cmd.ret_val); + } + return ret; +} + static int tc_ns_get_tee_version(const struct tc_ns_dev_file *dev_file, void __user *argp) { @@ -201,7 +254,7 @@ static int get_public_key(struct tc_ns_dev_file *dev_file, return 0; } -static bool is_cert_buffer_size_valid(int cert_buffer_size) +static bool is_cert_buffer_size_valid(unsigned int cert_buffer_size) { /* * GET PACKAGE NAME AND APP CERTIFICATE: @@ -369,6 +422,9 @@ int tc_ns_client_open(struct tc_ns_dev_file **dev_file, uint8_t kernel_api) mutex_init(&dev->cainfo_hash_setup_lock); #endif init_completion(&dev->close_comp); +#ifdef CONFIG_TEE_TELEPORT_SUPPORT + dev->portal_enabled = false; +#endif *dev_file = dev; return 0; @@ -580,6 +636,18 @@ static int tc_client_mmap(struct file *filp, struct vm_area_struct *vma) return ret; } +static uint32_t get_nsid(void) +{ + uint32_t nsid; + +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + nsid = task_active_pid_ns(current)->ns.inum; +#else + nsid = PROC_PID_INIT_INO; +#endif + return nsid; +} + static int ioctl_register_agent(struct tc_ns_dev_file *dev_file, unsigned long arg) { int ret; @@ -605,56 +673,64 @@ static int ioctl_register_agent(struct tc_ns_dev_file *dev_file, unsigned long a return ret; } -static int ioctl_unregister_agent(const struct tc_ns_dev_file *dev_file, - unsigned long arg) +static int ioctl_check_agent_owner(const struct tc_ns_dev_file *dev_file, + unsigned int agent_id, unsigned int nsid) { - int ret; struct smc_event_data *event_data = NULL; - event_data = find_event_control((unsigned int)arg); - if (!event_data) { + event_data = find_event_control(agent_id, nsid); + if (event_data == NULL) { tloge("invalid agent id\n"); return -EINVAL; } if (event_data->owner != dev_file) { - tloge("invalid unregister request\n"); + tloge("invalid request, access denied!\n"); put_agent_event(event_data); - return -EINVAL; + return -EPERM; } put_agent_event(event_data); - ret = tc_ns_unregister_agent((unsigned int)arg); - - return ret; + return 0; } /* ioctls for the secure storage daemon */ -static int public_ioctl(const struct file *file, unsigned int cmd, unsigned long arg, bool is_from_client_node) +int public_ioctl(const struct file *file, unsigned int cmd, unsigned long arg, bool is_from_client_node) { int ret = -EINVAL; - struct tc_ns_dev_file *dev_file = file->private_data; + struct tc_ns_dev_file *dev_file = NULL; + uint32_t nsid = get_nsid(); void *argp = (void __user *)(uintptr_t)arg; - if (!dev_file) { + if (file == NULL || file->private_data == NULL) { tloge("invalid params\n"); return -EINVAL; } + dev_file = file->private_data; +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + dev_file->nsid = nsid; +#endif switch (cmd) { case TC_NS_CLIENT_IOCTL_WAIT_EVENT: - ret = tc_ns_wait_event((unsigned int)arg); + if (ioctl_check_agent_owner(dev_file, (unsigned int)arg, nsid) != 0) + return -EINVAL; + ret = tc_ns_wait_event((unsigned int)arg, nsid); break; case TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE: - ret = tc_ns_send_event_response((unsigned int)arg); + if (ioctl_check_agent_owner(dev_file, (unsigned int)arg, nsid) != 0) + return -EINVAL; + ret = tc_ns_send_event_response((unsigned int)arg, nsid); break; case TC_NS_CLIENT_IOCTL_REGISTER_AGENT: ret = ioctl_register_agent(dev_file, arg); break; case TC_NS_CLIENT_IOCTL_UNREGISTER_AGENT: - ret = ioctl_unregister_agent(dev_file, arg); + if (ioctl_check_agent_owner(dev_file, (unsigned int)arg, nsid) != 0) + return -EINVAL; + ret = tc_ns_unregister_agent((unsigned int)arg, nsid); break; case TC_NS_CLIENT_IOCTL_LOAD_APP_REQ: - ret = tc_ns_load_secfile(file->private_data, argp, is_from_client_node); + ret = tc_ns_load_secfile(file->private_data, argp, NULL, is_from_client_node); break; default: tloge("invalid cmd!"); @@ -693,10 +769,10 @@ static int get_agent_id(unsigned long arg, unsigned int cmd, uint32_t *agent_id) switch (cmd) { case TC_NS_CLIENT_IOCTL_WAIT_EVENT: case TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE: + case TC_NS_CLIENT_IOCTL_UNREGISTER_AGENT: *agent_id = (unsigned int)arg; break; case TC_NS_CLIENT_IOCTL_REGISTER_AGENT: - case TC_NS_CLIENT_IOCTL_UNREGISTER_AGENT: if (copy_from_user(&args, (void *)(uintptr_t)arg, sizeof(args)) != 0) { tloge("copy agent args failed\n"); return -EFAULT; @@ -736,14 +812,14 @@ static int tc_client_agent_ioctl(const struct file *file, unsigned int cmd, return ret; } -static void handle_cmd_prepare(unsigned int cmd) +void handle_cmd_prepare(unsigned int cmd) { if (cmd != TC_NS_CLIENT_IOCTL_WAIT_EVENT && cmd != TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE) livepatch_down_read_sem(); } -static void handle_cmd_finish(unsigned int cmd) +void handle_cmd_finish(unsigned int cmd) { if (cmd != TC_NS_CLIENT_IOCTL_WAIT_EVENT && cmd != TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE) @@ -760,6 +836,9 @@ static long tc_private_ioctl(struct file *file, unsigned int cmd, case TC_NS_CLIENT_IOCTL_GET_TEE_VERSION: ret = tc_ns_get_tee_version(file->private_data, argp); break; + case TC_NS_CLIENT_IOCTL_GET_TEE_INFO: + ret = tc_ns_get_tee_info(file, argp); + break; case TC_NS_CLIENT_IOCTL_SET_NATIVECA_IDENTITY: mutex_lock(&g_set_ca_hash_lock); ret = tc_ns_set_native_hash((unsigned long)(uintptr_t)argp, GLOBAL_CMD_ID_SET_CA_HASH); @@ -801,9 +880,6 @@ static long tc_client_ioctl(struct file *file, unsigned int cmd, case TC_NS_CLIENT_IOCTL_LOGIN: ret = tc_ns_client_login_func(file->private_data, argp); break; - case TC_NS_CLIENT_IOCTL_TST_CMD_REQ: - ret = tc_ns_tst_cmd(argp); - break; case TC_NS_CLIENT_IOCTL_LOAD_APP_REQ: ret = public_ioctl(file, cmd, arg, true); break; @@ -834,7 +910,9 @@ static int tc_client_open(struct inode *inode, struct file *file) ret = tc_ns_client_open(&dev, TEE_REQ_FROM_USER_MODE); if (ret == 0) file->private_data = dev; - +#ifdef CONFIG_TEE_REBOOT + get_teecd_pid(); +#endif return ret; } @@ -860,7 +938,7 @@ static int tc_private_close(struct inode *inode, struct file *file) /* for teecd close fd */ if (is_system_agent(dev)) { /* for teecd agent close fd */ - send_event_response_single(dev); + send_crashed_event_response_single(dev); free_dev(dev); } else { /* for ca damon close fd */ @@ -1022,13 +1100,13 @@ static int create_dev_node(struct dev_node *node) return -EFAULT; } if (alloc_chrdev_region(&(node->devt), 0, 1, - node->node_name) != 0) { + node->node_name) != 0) { tloge("alloc chrdev region failed"); ret = -EFAULT; return ret; } node->class_dev = device_create(node->driver_class, NULL, node->devt, - NULL, node->node_name); + NULL, node->node_name); if (IS_ERR_OR_NULL(node->class_dev)) { tloge("class device create failed"); ret = -ENOMEM; @@ -1047,7 +1125,7 @@ chrdev_region_unregister: } static int init_dev_node(struct dev_node *node, char *node_name, - struct class *driver_class, const struct file_operations *fops) + struct class *driver_class, const struct file_operations *fops) { int ret = -1; if (!node) { @@ -1074,19 +1152,30 @@ static int enable_dev_nodes(void) int ret; ret = cdev_add(&(g_tc_private.char_dev), - MKDEV(MAJOR(g_tc_private.devt), 0), 1); + MKDEV(MAJOR(g_tc_private.devt), 0), 1); if (ret < 0) { tloge("cdev add failed %d", ret); return ret; } ret = cdev_add(&(g_tc_client.char_dev), - MKDEV(MAJOR(g_tc_client.devt), 0), 1); + MKDEV(MAJOR(g_tc_client.devt), 0), 1); + if (ret < 0) { + tloge("cdev add failed %d", ret); + cdev_del(&(g_tc_private.char_dev)); + return ret; + } + +#if defined(CONFIG_CONFIDENTIAL_CONTAINER) || defined(CONFIG_TEE_TELEPORT_SUPPORT) + ret = cdev_add(&(g_tc_cvm.char_dev), + MKDEV(MAJOR(g_tc_cvm.devt), 0), 1); if (ret < 0) { tloge("cdev add failed %d", ret); + cdev_del(&(g_tc_client.char_dev)); cdev_del(&(g_tc_private.char_dev)); return ret; } +#endif return 0; } @@ -1123,6 +1212,17 @@ static int tc_ns_client_init(void) goto unmap_res_mem; } +#if defined(CONFIG_CONFIDENTIAL_CONTAINER) || defined(CONFIG_TEE_TELEPORT_SUPPORT) + ret = init_dev_node(&g_tc_cvm, TC_NS_CVM_DEV, g_driver_class, get_cvm_fops()); + if (ret != 0) { + destory_dev_node(&g_tc_private, g_driver_class); + destory_dev_node(&g_tc_client, g_driver_class); + class_destroy(g_driver_class); + goto unmap_res_mem; + } +#endif + + INIT_LIST_HEAD(&g_tc_ns_dev_list.dev_file_list); mutex_init(&g_tc_ns_dev_list.dev_lock); init_crypto_hash_lock(); @@ -1166,6 +1266,13 @@ static int tc_teeos_init(struct device *class_dev) tloge("tz spi init failed\n"); goto release_mempool; } + + ret = tc_ns_register_host_nsid(); + if (ret != 0) { + tloge("failed to register host nsid\n"); + goto release_mempool; + } + return 0; release_mempool: free_mailbox_mempool(); @@ -1192,6 +1299,8 @@ static void tc_re_init(const struct device *class_dev) if (ret != 0) tloge("tlogger init failed\n"); #endif + if (tzdebug_init() != 0) + tloge("tzdebug init failed\n"); ret = init_tui(class_dev); if (ret != 0) @@ -1209,16 +1318,6 @@ static void tc_re_init(const struct device *class_dev) ret = -EFAULT; } -#ifdef CONFIG_LIVEPATCH_ENABLE - /* - * access this sys node only after this function is initialized - */ - if (livepatch_init(class_dev)) { - tloge("livepatch init failed\n"); - ret = -EFAULT; - } -#endif - if (ret != 0) tloge("Caution! Running environment init failed!\n"); } @@ -1231,6 +1330,11 @@ static __init int tc_init(void) ret = tc_ns_client_init(); if (ret != 0) return ret; + +#ifdef CONFIG_FFA_SUPPORT + ffa_abi_register(); +#endif + ret = tc_teeos_init(g_tc_client.class_dev); if (ret != 0) { tloge("tc teeos init failed\n"); @@ -1239,6 +1343,10 @@ static __init int tc_init(void) /* run-time environment init failure don't block tzdriver init proc */ tc_re_init(g_tc_client.class_dev); +#ifdef CONFIG_TEE_TELEPORT_SUPPORT + tee_portal_init(); +#endif + /* * Note: the enable_dev_nodes function must be called * at the end of tc_init @@ -1248,9 +1356,17 @@ static __init int tc_init(void) tloge("enable dev nodes failed\n"); goto class_device_destroy; } + + set_tz_init_flag(); +#if defined(DYNAMIC_DRV_DIR) || defined(DYNAMIC_CRYPTO_DRV_DIR) || defined(DYNAMIC_SRV_DIR) + tz_load_dynamic_dir(); +#endif return 0; class_device_destroy: +#if defined(CONFIG_CONFIDENTIAL_CONTAINER) || defined(CONFIG_TEE_TELEPORT_SUPPORT) + destory_dev_node(&g_tc_cvm, g_driver_class); +#endif destory_dev_node(&g_tc_client, g_driver_class); destory_dev_node(&g_tc_private, g_driver_class); class_destroy(g_driver_class); @@ -1273,10 +1389,14 @@ static void free_dev_list(void) static void tc_exit(void) { tlogi("tz client exit"); + clear_tz_init_flag(); /* * You should first execute "cdev_del" to * prevent access to the device node when uninstalling "tzdriver". */ +#if defined(CONFIG_CONFIDENTIAL_CONTAINER) || defined(CONFIG_TEE_TELEPORT_SUPPORT) + cdev_del(&(g_tc_cvm.char_dev)); +#endif cdev_del(&(g_tc_private.char_dev)); cdev_del(&(g_tc_client.char_dev)); free_agent(); @@ -1284,6 +1404,10 @@ static void tc_exit(void) free_tui(); free_tz_spi(g_tc_client.class_dev); /* run-time environment exit should before teeos exit */ +#if defined(CONFIG_CONFIDENTIAL_CONTAINER) || defined(CONFIG_TEE_TELEPORT_SUPPORT) + destory_dev_node(&g_tc_cvm, g_driver_class); +#endif + destory_dev_node(&g_tc_client, g_driver_class); destory_dev_node(&g_tc_private, g_driver_class); platform_driver_unregister(&g_tz_platform_driver); @@ -1291,6 +1415,7 @@ static void tc_exit(void) free_smc_data(); free_event_mem(); #ifdef CONFIG_TZDRIVER_MODULE + free_tzdebug(); free_tlogger_service(); #endif free_interrupt_trace(); @@ -1301,6 +1426,9 @@ static void tc_exit(void) free_livepatch(); free_all_session(); free_dev_list(); +#ifdef CONFIG_FFA_SUPPORT + ffa_abi_unregister(); +#endif tlogi("tz client exit finished"); } diff --git a/core/tc_client_driver.h b/core/tc_client_driver.h index 3bfeb24..45f758a 100644 --- a/core/tc_client_driver.h +++ b/core/tc_client_driver.h @@ -31,11 +31,22 @@ struct dev_node { char *node_name; }; +bool get_tz_init_flag(void); struct tc_ns_dev_list *get_dev_list(void); struct tc_ns_dev_file *tc_find_dev_file(unsigned int dev_file_id); int tc_ns_client_open(struct tc_ns_dev_file **dev_file, uint8_t kernel_api); int tc_ns_client_close(struct tc_ns_dev_file *dev); -int is_agent_alive(unsigned int agent_id); +int is_agent_alive(unsigned int agent_id, unsigned int nsid); +int tc_ns_register_host_nsid(void); + +#if defined(CONFIG_CONFIDENTIAL_CONTAINER) || defined(CONFIG_TEE_TELEPORT_SUPPORT) +const struct file_operations *get_cvm_fops(void); +#endif + +void handle_cmd_prepare(unsigned int cmd); +void handle_cmd_finish(unsigned int cmd); +int public_ioctl(const struct file *file, unsigned int cmd, unsigned long arg, bool is_from_client_node); +void free_dev(struct tc_ns_dev_file *dev); #ifdef CONFIG_ACPI int get_acpi_tz_irq(void); diff --git a/core/tc_cvm_driver.c b/core/tc_cvm_driver.c new file mode 100644 index 0000000..fa125b4 --- /dev/null +++ b/core/tc_cvm_driver.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "tc_client_driver.h" +#include +#include +#include +#include +#include +#include +#include "auth_base_impl.h" +#include "agent.h" +#ifdef CONFIG_TEE_TELEPORT_SUPPORT +#include "tee_portal.h" +#endif + +#include "tee_info.h" + +#if defined(CONFIG_CONFIDENTIAL_CONTAINER) || defined(CONFIG_TEE_TELEPORT_SUPPORT) +static int tc_cvm_open(struct inode *inode, struct file *file) +{ + int ret = -1; + struct tc_ns_dev_file *dev = NULL; + (void)inode; + +#ifdef CONFIG_TEE_TELEPORT_AUTH + ret = check_tee_teleport_auth(); +#endif +#ifdef CONFIG_TEE_AGENTD_AUTH + if (ret != 0) + ret = check_tee_agentd_auth(); +#endif + if (ret != 0) { + tloge("teleport/agentd auth failed, ret %d\n", ret); + return -EACCES; + } + + file->private_data = NULL; + ret = tc_ns_client_open(&dev, TEE_REQ_FROM_USER_MODE); + if (ret == 0) + file->private_data = dev; + return ret; +} + +static long tc_cvm_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = -EFAULT; + void *argp = (void __user *)(uintptr_t)arg; + handle_cmd_prepare(cmd); + + switch (cmd) { + case TC_NS_CLIENT_IOCTL_GET_TEE_INFO: + ret = tc_ns_get_tee_info(file, argp); + break; + +#ifdef CONFIG_TEE_TELEPORT_SUPPORT + case TC_NS_CLIENT_IOCTL_PORTAL_REGISTER: + if (check_tee_teleport_auth() == 0) + ret = tee_portal_register(file->private_data, argp); + else + tloge("check tee_teleport path failed\n"); + break; + case TC_NS_CLIENT_IOCTL_PORTAL_WORK: + if (check_tee_teleport_auth() == 0) + ret = tee_portal_work(file->private_data); + else + tloge("check tee_teleport path failed\n"); + break; +#endif + default: + ret = public_ioctl(file, cmd, arg, false); + break; + } + + handle_cmd_finish(cmd); + return ret; +} + +#ifdef CONFIG_COMPAT +long tc_compat_cvm_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long ret; + + if (!file) + return -EINVAL; + + ret = tc_cvm_ioctl(file, cmd, (unsigned long)(uintptr_t)compat_ptr(arg)); + return ret; +} +#endif + +static int tc_cvm_close(struct inode *inode, struct file *file) +{ + struct tc_ns_dev_file *dev = file->private_data; + (void)inode; + +#ifdef CONFIG_TEE_TELEPORT_SUPPORT + if (dev->portal_enabled) + tee_portal_unregister(file->private_data); +#endif + + if (is_system_agent(dev)) { + send_crashed_event_response_single(dev); + free_dev(dev); + } else { + free_dev(dev); + } + file->private_data = NULL; + + return 0; +} + +static const struct file_operations g_cvm_fops = { + .owner = THIS_MODULE, + .open = tc_cvm_open, + .release = tc_cvm_close, + .unlocked_ioctl = tc_cvm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = tc_compat_cvm_ioctl, +#endif +}; + +const struct file_operations *get_cvm_fops(void) +{ + return &g_cvm_fops; +} +#endif diff --git a/core/tee_compat_check.c b/core/tee_compat_check.c index b9baac4..8cfb45a 100644 --- a/core/tee_compat_check.c +++ b/core/tee_compat_check.c @@ -19,31 +19,69 @@ #include "tee_compat_check.h" #include #include +#include #include "teek_ns_client.h" #include "tc_ns_log.h" +#define RETRY_MAX_COUNT 100 +#define COMPAT_LEVEL_RETRY_SLEEP 10 + +struct os_version { + uint32_t magic; + uint32_t major_version; + uint32_t minor_version; + uint32_t reserved[8]; + uint32_t feature_ccos:1; + uint32_t feature_reserved:31; +}; + +static bool g_ccos_flag = false; + int32_t check_teeos_compat_level(const uint32_t *buffer, uint32_t size) { const uint16_t major = TEEOS_COMPAT_LEVEL_MAJOR; const uint16_t minor = TEEOS_COMPAT_LEVEL_MINOR; + struct os_version *version = NULL; + uint32_t retry_count = 0; if (!buffer || size != COMPAT_LEVEL_BUF_LEN) { tloge("check teeos compat level failed, invalid param\n"); return -EINVAL; } - if (buffer[0] != VER_CHECK_MAGIC_NUM) { - tloge("check ver magic num %u failed\n", buffer[0]); + version = (struct os_version *)buffer; + + while (retry_count < RETRY_MAX_COUNT && version->magic != VER_CHECK_MAGIC_NUM) { + tlogd("sync compat level msg, cnt: %d\n", retry_count); + msleep(COMPAT_LEVEL_RETRY_SLEEP); + retry_count++; + } + + if (version->magic != VER_CHECK_MAGIC_NUM) { + tloge("check ver magic num %u failed\n", version->magic); + return -EPERM; + } + if (version->major_version != major) { + tloge("check major ver failed, tzdriver expect teeos version=%u, actual teeos version=%u\n", + major, version->major_version); return -EPERM; } - if (buffer[1] != major) { - tloge("check major ver failed, major tz=%u, major tee=%u\n", - major, buffer[1]); + + if (version->minor_version < minor) { + tloge("check minor ver failed, tzdriver expect teeos minor version=%u, actual minor teeos version=%u\n", + minor, version->minor_version); return -EPERM; + } else { + tlogi("current tzdriver expect teeos version %u.%u, actual tee version %u.%u\n", + major, minor, version->major_version, version->minor_version); } - /* just print warning */ - if (buffer[2] != minor) - tlogw("check minor ver failed, minor tz=%u, minor tee=%u\n", - minor, buffer[2]); + + g_ccos_flag = (version->feature_ccos == TEEOS_CONFIDENTIAL_OS_FLAG) ? true : false; + return 0; } + +bool is_ccos(void) +{ + return g_ccos_flag; +} diff --git a/core/tee_compat_check.h b/core/tee_compat_check.h index 7a18240..30800f4 100644 --- a/core/tee_compat_check.h +++ b/core/tee_compat_check.h @@ -25,11 +25,17 @@ * this version number MAJOR.MINOR is used * to identify the compatibility of tzdriver and teeos */ -#define TEEOS_COMPAT_LEVEL_MAJOR 2 +#define TEEOS_COMPAT_LEVEL_MAJOR 3 #define TEEOS_COMPAT_LEVEL_MINOR 0 +#define TZDRIVER_LEVEL_MAJOR_SELF 3 +#define TZDRIVER_LEVEL_MINOR_SELF 0 + +#define TEEOS_CONFIDENTIAL_OS_FLAG 1 + #define VER_CHECK_MAGIC_NUM 0x5A5A5A5A #define COMPAT_LEVEL_BUF_LEN 12 int32_t check_teeos_compat_level(const uint32_t *buffer, uint32_t size); +bool is_ccos(void); #endif diff --git a/core/tee_info.c b/core/tee_info.c new file mode 100644 index 0000000..c7a6505 --- /dev/null +++ b/core/tee_info.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "tee_info.h" +#include +#include +#include +#include "teek_ns_client.h" +#include "tee_compat_check.h" +#include + +int32_t tc_ns_get_tee_info(struct file *file, void __user *argp) +{ + int32_t ret; + struct tc_ns_tee_info info; + + if (!argp) { + tloge("error input parameter\n"); + return -EINVAL; + } + + (void)file; + ret = 0; + (void)memset_s(&info, sizeof(info), 0, sizeof(info)); + info.tzdriver_version_major = TZDRIVER_LEVEL_MAJOR_SELF; + info.tzdriver_version_minor = TZDRIVER_LEVEL_MINOR_SELF; + if (copy_to_user(argp, &info, sizeof(info)) != 0) + ret = -EFAULT; + + return ret; +} diff --git a/core/tee_info.h b/core/tee_info.h new file mode 100644 index 0000000..6f3c739 --- /dev/null +++ b/core/tee_info.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef TEE_INFO_H +#define TEE_INFO_H + +#include +#include +#include "teek_ns_client.h" + +int32_t tc_ns_get_tee_info(struct file *file, void __user *argp); +#endif diff --git a/core/tee_portal.c b/core/tee_portal.c new file mode 100644 index 0000000..7d6418b --- /dev/null +++ b/core/tee_portal.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "tee_portal.h" +#include "agent.h" +#include "teek_client_constants.h" +#include "teek_client_id.h" +#include "mailbox_mempool.h" +#include "smc_smp.h" +#include "shared_mem.h" +#include +#include +#include +#include +#include + +#define TEE_PORTAL_EVENT_REGISTER_SHM 0 +#define TEE_PORTAL_EVENT_UNREGISTER_SHM 1 +#define TEE_PORTAL_EVENT_WORK 2 + +struct portal_t { + struct list_head list; + void *owner; + void *buf; + uint32_t size; + uint32_t event; + uint32_t mb_l_addr; + uint32_t mb_h_addr; +}; + +static struct portal_t g_portal_head; +DEFINE_MUTEX(g_portal_lock); +DEFINE_MUTEX(g_portal_enable_lock); + +void tee_portal_init(void) +{ + INIT_LIST_HEAD(&g_portal_head.list); +} + +static int send_portal_smc(const struct portal_t *param) +{ + struct tc_ns_smc_cmd smc_cmd = {{0}, 0}; + int ret = 0; + struct tc_uuid appmgr_uuid = TEE_SERVICE_APPMGR; + kuid_t kuid = current_uid(); + + if (param == NULL) + return -EINVAL; + + (void)memcpy_s(&smc_cmd.uuid, sizeof(struct tc_uuid), &appmgr_uuid, sizeof(struct tc_uuid)); + smc_cmd.cmd_type = CMD_TYPE_GLOBAL; + smc_cmd.cmd_id = GLOBAL_CMD_ID_PORTAL_WORK; + smc_cmd.eventindex = param->event; + smc_cmd.login_data_phy = param->mb_l_addr; + smc_cmd.login_data_h_addr = param->mb_h_addr; + smc_cmd.login_data_len = param->size; + smc_cmd.uid = kuid.val; + + ret = tc_ns_smc(&smc_cmd); + if (ret != 0) { + tloge("smc call returns error ret 0x%x\n", smc_cmd.ret_val); + if (smc_cmd.ret_val == TEEC_ERROR_SERVICE_NOT_EXIST) + return -EOPNOTSUPP; + else if (smc_cmd.ret_val == TEEC_ERROR_OUT_OF_MEMORY) + return -ENOMEM; + } + + return ret; +} + +#ifndef CONFIG_NOCOPY_SHAREDMEM +static int fill_shared_mem_info(uint64_t start_vaddr, uint32_t pages_no, + uint32_t offset, uint32_t buffer_size, uint64_t info_addr) +{ + (void)start_vaddr; + (void)pages_no; + (void)offset; + (void)buffer_size; + (void)info_addr; + tloge("shared memory is unsupported\n"); + return -EINVAL; +} + +static void release_shared_mem_page(uint64_t buf, uint32_t buf_size) +{ + (void)buf; + (void)buf_size; + tloge("shared memory is unsupported\n"); +} +#endif + +static int init_portal_node(struct portal_t *portal, struct agent_ioctl_args *args, void* owner) +{ + int ret = 0; + uint64_t start_vaddr; + uint32_t page_num; + uint32_t mb_buff_len; + void *mb_buff = NULL; + start_vaddr = args->addr; + page_num = args->buffer_size / PAGE_SIZE; + mb_buff_len = sizeof(struct pagelist_info) + (sizeof(uint64_t) * page_num); + mb_buff = mailbox_alloc(mb_buff_len, MB_FLAG_ZERO); + if (mb_buff == NULL) { + tloge("cannot alloc mailbox mem\n"); + return -ENOMEM; + } + + if (fill_shared_mem_info(start_vaddr, page_num, 0, args->buffer_size, (uint64_t)mb_buff)) { + tloge("cannot fill shared memory info\n"); + mailbox_free(mb_buff); + return -EFAULT; + } + + portal->mb_l_addr = mailbox_virt_to_phys((uintptr_t)mb_buff); + portal->mb_h_addr = (uint64_t)mailbox_virt_to_phys((uintptr_t)mb_buff) >> ADDR_TRANS_NUM; + portal->event = TEE_PORTAL_EVENT_REGISTER_SHM; + portal->buf = mb_buff; + portal->size = mb_buff_len; + portal->owner = owner; + + return ret; +} + +static bool check_portal_exist(void *owner) +{ + struct portal_t *pos = NULL; + list_for_each_entry(pos, &g_portal_head.list, list) { + if (pos->owner == owner) + return true; + } + return false; +} + +int tee_portal_register(void *owner, void __user *arg) +{ + int ret; + struct agent_ioctl_args args; + + if (owner == NULL || arg == NULL) + return -EFAULT; + + if (copy_from_user(&args, (void *)(uintptr_t)arg, sizeof(args))) { + tloge("copy args failed\n"); + return -EFAULT; + } + + if (args.addr % PAGE_SIZE != 0 || args.buffer_size % PAGE_SIZE != 0 || + args.buffer_size > SZ_256M || args.buffer_size == 0) { + tloge("bad memory addr or size\n"); + return -EFAULT; + } + + struct portal_t *portal; + portal = (struct portal_t *)kmalloc(sizeof(struct portal_t), GFP_KERNEL); + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)(portal))) { + tloge("failed to alloc mem for portal node!\n"); + return -EFAULT; + } + + mutex_lock(&g_portal_lock); + if (check_portal_exist(owner)) { + mutex_unlock(&g_portal_lock); + tloge("illegal register request!\n"); + return -EFAULT; + } + + ret = init_portal_node(portal, &args, owner); + if (ret != 0) { + mutex_unlock(&g_portal_lock); + tloge("failed to init portal node!\n"); + goto clean; + } + + list_add(&portal->list, &g_portal_head.list); + mutex_unlock(&g_portal_lock); + + ret = send_portal_smc(portal); + if (ret != 0) { + release_shared_mem_page(portal->buf, portal->size); + mailbox_free(portal->buf); + mutex_lock(&g_portal_lock); + list_del(&portal->list); + mutex_unlock(&g_portal_lock); + goto clean; + } + + mutex_lock(&g_portal_enable_lock); + ((struct tc_ns_dev_file *)owner)->portal_enabled = true; + mutex_unlock(&g_portal_enable_lock); + return 0; +clean: + kfree(portal); + return ret; +} + +int tee_portal_unregister(const void *owner) +{ + int ret; + if (!owner) + return -EFAULT; + + struct portal_t *pos; + bool found = false; + mutex_lock(&g_portal_lock); + list_for_each_entry(pos, &g_portal_head.list, list) { + if (pos->owner == owner) { + found = true; + break; + } + } + + if (!found) { + tloge("failed to release portal!\n"); + mutex_unlock(&g_portal_lock); + return -EFAULT; + } + + pos->event = TEE_PORTAL_EVENT_UNREGISTER_SHM; + ret = send_portal_smc(pos); + + release_shared_mem_page(pos->buf, pos->size); + mailbox_free(pos->buf); + + list_del(&pos->list); + kfree(pos); + mutex_unlock(&g_portal_lock); + return ret; +} + +int tee_portal_work(const void *owner) +{ + struct portal_t *pos; + int ret = -EFAULT; + bool found = false; + + mutex_lock(&g_portal_lock); + list_for_each_entry(pos, &g_portal_head.list, list) { + if (pos->owner == owner) { + found = true; + pos->event = TEE_PORTAL_EVENT_WORK; + break; + } + } + mutex_unlock(&g_portal_lock); + + mutex_lock(&g_portal_enable_lock); + found &= ((struct tc_ns_dev_file *)owner)->portal_enabled; + mutex_unlock(&g_portal_enable_lock); + + if (!found) { + tloge("failed to found portal!\n"); + return ret; + } + + ret = send_portal_smc(pos); + return ret; +} diff --git a/core/tee_portal.h b/core/tee_portal.h new file mode 100644 index 0000000..10c392f --- /dev/null +++ b/core/tee_portal.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef TEE_PORTAL_H +#define TEE_PORTAL_H + +int tee_portal_register(void *owner, void __user *arg); +int tee_portal_unregister(const void *owner); +int tee_portal_work(const void *owner); +void tee_portal_init(void); + +#endif diff --git a/core/tz_pm.c b/core/tz_pm.c index 9fdfb80..3a95f03 100644 --- a/core/tz_pm.c +++ b/core/tz_pm.c @@ -24,6 +24,7 @@ #include "tc_ns_client.h" #include "teek_ns_client.h" #include "tc_ns_log.h" +#include "smc_call.h" #define S4_ADDR_4G 0xffffffff #define RESERVED_SECOS_PHYMEM_BASE 0x22800000 @@ -50,7 +51,7 @@ static void *tc_vmap(phys_addr_t paddr, size_t size) pages_count = (uint32_t)(PAGE_ALIGN(size + offset) / PAGE_SIZE); pages = kzalloc(sizeof(struct page *) * pages_count, GFP_KERNEL); - if (pages == NULL) + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)pages)) return NULL; for (i = 0; i < pages_count; i++) @@ -104,26 +105,14 @@ static void free_resource(const char *kernel_mem_addr) g_s4_buffer_size = 0; } -#ifndef CONFIG_ARCH32 static uint64_t tc_s4_suspend_or_resume(uint32_t power_op) { u64 smc_id = (u64)power_op; u64 smc_ret = 0xffff; - - do { - asm volatile ( - "mov x0, %[fid]\n" - "smc #0\n" - "str x0, [%[re0]]\n" : - [fid] "+r"(smc_id) : - [re0] "r"(&smc_ret) : - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", - "x8", "x9", "x10", "x11", "x12", "x13", - "x14", "x15", "x16", "x17"); - } while (0); - - isb(); - wmb(); + struct smc_in_params in_param = {smc_id}; + struct smc_out_params out_param = {smc_ret}; + smc_req(&in_param, &out_param, 0); + smc_ret = out_param.ret; return smc_ret; } @@ -138,89 +127,13 @@ static uint64_t tc_s4_crypto_and_copy(uint32_t crypt_op, u64 arg2 = (u64)size; u64 arg3 = (u64)index; u64 smc_ret = 0xffff; + struct smc_in_params in_param = {smc_id, arg0, arg1, arg2, arg3}; + struct smc_out_params out_param = {smc_ret}; - do { - asm volatile ( - "mov x0, %[fid]\n" - "mov x1, %[a1]\n" - "mov x2, %[a2]\n" - "mov x3, %[a3]\n" - "mov x4, %[a4]\n" - "smc #0\n" - "str x0, [%[re0]]\n" : - [fid] "+r"(smc_id), - [a1] "+r"(arg0), - [a2] "+r"(arg1), - [a3] "+r"(arg2), - [a4] "+r"(arg3) : - [re0] "r"(&smc_ret) : - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", - "x8", "x9", "x10", "x11", "x12", "x13", - "x14", "x15", "x16", "x17"); - } while (0); - - isb(); - wmb(); - return smc_ret; -} -#else -static uint32_t tc_s4_suspend_or_resume(uint32_t power_op) -{ - u32 smc_id = power_op; - u32 smc_ret = 0xffff; - - do { - asm volatile ( - "mov r0, %[fid]\n" - ".arch_extension sec\n" - "smc #0\n" - "str r0, [%[re0]]\n" : - [fid] "+r"(smc_id) : - [re0] "r"(&smc_ret) : - "r0"); - } while (0); - - isb(); - wmb(); - return smc_ret; -} - -static uint32_t tc_s4_crypto_and_copy(uint32_t crypt_op, - uint64_t middle_mem_addr, - uintptr_t secos_mem, - uint32_t size, uint32_t index) -{ - u32 smc_id = crypt_op; - u32 arg0 = (u32)middle_mem_addr; - u32 arg1 = (u32)secos_mem; - u32 arg2 = size; - u32 arg3 = index; - u32 smc_ret = 0xffff; - - do { - asm volatile ( - "mov r0, %[fid]\n" - "mov r1, %[a1]\n" - "mov r2, %[a2]\n" - "mov r3, %[a3]\n" - "mov r4, %[a4]\n" - ".arch_extension sec\n" - "smc #0\n" - "str r0, [%[re0]]\n" : - [fid] "+r"(smc_id), - [a1] "+r"(arg0), - [a2] "+r"(arg1), - [a3] "+r"(arg2), - [a4] "+r"(arg3) : - [re0] "r"(&smc_ret) : - "r0", "r1", "r2", "r3", "r4"); - } while (0); - - isb(); - wmb(); + smc_req(&in_param, &out_param, 0); + smc_ret = out_param.ret; return smc_ret; } -#endif static int tc_s4_transfer_data(char *kernel_mem_addr, uint32_t crypt_op) { @@ -271,9 +184,6 @@ static int tc_s4_pm_ops(struct device *dev, uint32_t power_op, else kernel_mem_addr = g_s4_kernel_mem_addr; - isb(); - wmb(); - /* notify TEEOS to suspend all pm driver */ if (power_op == TSP_S4_SUSPEND) { ret = (int)tc_s4_suspend_or_resume(power_op); diff --git a/core/tz_spi_notify.c b/core/tz_spi_notify.c index 587ef49..b4bc711 100644 --- a/core/tz_spi_notify.c +++ b/core/tz_spi_notify.c @@ -400,7 +400,7 @@ static void tc_notify_set_affinity(struct notify_data_entry *entry) uint32_t i; cpumask_clear(&mask); - for (i = 0; i < (uint32_t)NR_CPUS; i++) { + for_each_online_cpu(i) { struct aff_bits_t *aff = &af_data->aff; if (aff->aff_bits[i / AFF_BITS_SIZE] & aff_bits_mask(i)) cpumask_set_cpu(i, &mask); @@ -581,18 +581,13 @@ int TC_NS_RegisterServiceCallbackFunc(const char *uuid, void *func, const void *private_data) { const char *uuid_in = uuid; + + if (!get_tz_init_flag()) return EFAULT; return tc_ns_register_service_call_back_func(uuid_in, func, private_data); } EXPORT_SYMBOL(TC_NS_RegisterServiceCallbackFunc); -int tc_ns_tst_cmd(void *argp) -{ - (void)argp; - tloge("usr img do not support this cmd\n"); - return 0; -} - int send_notify_cmd(unsigned int cmd_id) { struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; @@ -619,7 +614,7 @@ int send_notify_cmd(unsigned int cmd_id) (unsigned int)((uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM); if (is_tee_rebooting()) - ret = send_smc_cmd_rebooting(TSP_REQUEST, 0, 0, &smc_cmd); + ret = send_smc_cmd_rebooting(TSP_REQUEST, &smc_cmd); else ret = tc_ns_smc(&smc_cmd); diff --git a/core/tz_spi_notify.h b/core/tz_spi_notify.h index 1722dc3..1469559 100644 --- a/core/tz_spi_notify.h +++ b/core/tz_spi_notify.h @@ -23,7 +23,6 @@ int tz_spi_init(struct device *class_dev, struct device_node *np); void free_tz_spi(struct device *class_dev); -int tc_ns_tst_cmd(void *argp); int send_notify_cmd(unsigned int cmd_id); #endif diff --git a/tzdriver_internal/tee_reboot/reboot.c b/tzdriver_internal/tee_reboot/reboot.c new file mode 100644 index 0000000..2bd79f1 --- /dev/null +++ b/tzdriver_internal/tee_reboot/reboot.c @@ -0,0 +1,433 @@ +/* + * reboot.c + * + * functions for TEE reboot + * + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "reboot.h" +#include +#include +#include "agent.h" +#include "cmdmonitor.h" +#include "mailbox_mempool.h" +#include "tlogger.h" +#include "tz_spi_notify.h" +#include "secs_power_ctrl.h" +#include "session_manager.h" +#include "smc_smp.h" +#include "ko_adapt.h" +#include "tz_kthread_affinity.h" +#include "tc_client_driver.h" +#include +#include + +static atomic_t secondary_cpu_reboot; +static bool g_is_tee_rebooting = false; +static tee_alarm_func g_tee_alarm_func = NULL; +static struct pid *g_teecd_pid = NULL; + +#ifdef CONFIG_CONFIDENTIAL_TEE +#if (CONFIG_NEW_TEE_LOADED == 1) +static bool g_new_tee_on = true; +#else +static bool g_new_tee_on = false; +#endif +#endif + +static void set_tee_is_dead_flag(void) +{ + g_is_tee_rebooting = true; +} + +static void clr_tee_is_dead_flag(void) +{ + g_is_tee_rebooting = false; +} + + +bool is_tee_rebooting(void) +{ + return g_is_tee_rebooting; +} + +static void tee_reboot_smc(uint32_t cmd) +{ + int ret; + unsigned long flags; + + if (power_on_cc() != 0) { + tloge("power on cc failed\n"); + return; + } + + local_irq_save(flags); + ret = send_smc_cmd_rebooting(cmd, NULL); + + local_irq_restore(flags); + if (power_down_cc() != 0) { + tloge("power down cc failed\n"); + return; + } + + return; +} + +static struct work_struct reboot_work; +static struct work_struct reboot_done_work; +static struct work_struct secondary_cpu_on_work[NR_CPUS]; + +static void secondary_cpu_on_func(struct work_struct *dummy) +{ + tee_reboot_smc(TSP_CPU_ON); + atomic_add(1, &secondary_cpu_reboot); + return; +} + +static void tee_reboot_secondary_cpus(void) +{ + int i; + tlogd("secondary cpu will reboot\n"); + /* reboot secondary cpus */ + get_online_cpus(); + for_each_online_cpu(i) { + if (i != 0) { + INIT_WORK(&secondary_cpu_on_work[i], secondary_cpu_on_func); + schedule_work_on(i, &secondary_cpu_on_work[i]); + tlogi("before flush work cpu %d\n", i); + flush_work(&secondary_cpu_on_work[i]); + tlogi("after flush work cpu %d\n", i); + } + } + put_online_cpus(); +} + +static void tee_reboot_work_func(struct work_struct *dummy) +{ + tlogd("primary cpu will reboot\n"); + tee_reboot_smc(TSP_REBOOT); + + tee_reboot_secondary_cpus(); + return; +} + +static int tee_reboot_work(void) +{ + uint32_t retry_count = 0; + atomic_set(&secondary_cpu_reboot, 0); + + INIT_WORK(&reboot_work, tee_reboot_work_func); + schedule_work_on(0, &reboot_work); + flush_work(&reboot_work); + + while (retry_count < REBOOT_MAX_COUNT) { + /* The number of secondary cpu is the total number of cpus minus one. */ + if (atomic_read(&secondary_cpu_reboot) >= (num_online_cpus() - 1)) { +#ifdef CONFIG_CONFIDENTIAL_TEE + g_new_tee_on = true; +#endif + return 0; + } + msleep(REBOOT_SLEEP); + retry_count++; + } + + return -1; +} + +static void tee_reboot_done_work_func(struct work_struct *dummy) +{ + tlogd("clear reboot flag\n"); + tee_reboot_smc(TSP_REBOOT_DONE); + return; +} + +static void tee_reboot_done_work(void) +{ + INIT_WORK(&reboot_done_work, tee_reboot_done_work_func); + schedule_work_on(0, &reboot_done_work); + flush_work(&reboot_done_work); +} + +static bool get_gic_mpidr_mt(void) +{ + /* MT decides how to send a sgi */ + if (get_mpidr_el1() & MPIDR_MT) + return true; + else + return false; +} + +static uint64_t get_gic_cpu_affinity(uint32_t cpu_id) +{ + /* set affinity of each cpu */ + return get_mpidr_el1() & MPIDR_AFF_MASK; +} + +static void gic_send_sgi(uint32_t irq, uint32_t target_list) +{ + uint32_t i; + for_each_online_cpu(i) { + if ((1 << i) & target_list) { + uint64_t sgi1r; + uint64_t aff = get_gic_cpu_affinity(i); + if (get_gic_mpidr_mt()) { + sgi1r = ((aff >> MPIDR_AFF3_FIELD) << SGI_AFF3_FIELD) | /* aff3 */ + (((aff >> MPIDR_AFF2_FIELD) & AFF_MASK) << SGI_AFF2_FIELD) | /* aff2 */ + (((aff >> MPIDR_AFF1_FIELD) & AFF_MASK) << SGI_AFF1_FIELD) | /* aff1 */ + 1 | /* if mt is true, targetlist is always 1 */ + ((uint64_t)irq << SGI_ID_FIELD); /* irq */ + } else { + sgi1r = ((aff >> MPIDR_AFF3_FIELD) << SGI_AFF3_FIELD) | /* aff3 */ + (((aff >> MPIDR_AFF2_FIELD) & AFF_MASK) << SGI_AFF2_FIELD) | /* aff2 */ + (((aff >> MPIDR_AFF1_FIELD) & AFF_MASK) << SGI_AFF1_FIELD) | /* aff1 */ + (1 << (i % GIC_AFF_LEVEL)) | /* if mt is false, can shoose PE */ + ((uint64_t)irq << SGI_ID_FIELD); /* irq */ + } + set_icc_sgi1r_el1(sgi1r); + __asm__ volatile ("isb" : : : "memory"); + } + } +} + +static uint32_t get_online_cpu_mask(void) +{ + uint32_t i; + uint32_t cpu_mask = 0; + for_each_online_cpu(i) + cpu_mask |= (1 << i); + return cpu_mask; +} + +static void tee_alarm_report(int alarm_id) +{ + if (g_tee_alarm_func == NULL) + return; + + int ret = g_tee_alarm_func(alarm_id, ALARM_REPORT); + if (ret != 0) + tloge("report crash fail, ret is %d\n", ret); +} + +static void tee_alarm_clear(int alarm_id) +{ + if (g_tee_alarm_func == NULL) + return; + + int ret = g_tee_alarm_func(alarm_id, ALARM_CLEAR); + if (ret != 0) + tloge("clean crash fail, ret is %d\n", ret); +} + +int teek_register_alarm_func(tee_alarm_func alarm_func) +{ + if (alarm_func == NULL) + return -EINVAL; + + g_tee_alarm_func = alarm_func; + return 0; +} +EXPORT_SYMBOL(teek_register_alarm_func); + +void get_teecd_pid(void) +{ + get_task_struct(current); + g_teecd_pid = get_task_pid(current, PIDTYPE_PID); +} + +static void kill_teecd_and_tlogcat(void) +{ + if (g_teecd_pid != NULL) + kill_pid(g_teecd_pid, SIGKILL, 1); + recycle_tlogcat_processes(); +} + +static bool prepare_reboot(void) +{ +#ifdef CONFIG_CONFIDENTIAL_TEE + if (g_new_tee_on == true) { + tloge("new tee is on, cannot upgrade again\n"); + return false; + } + if (check_running_ca()) { + tloge("there are one or more running tasks, stop upgrade\n"); + return false; + } +#endif + set_tee_is_dead_flag(); + tee_alarm_report(TEE_CRASH); + gic_send_sgi(GIC_CPU_RESCHEDULE, get_online_cpu_mask()); + return true; +} + +int tee_reboot(void) +{ + int ret = 0; + if (!prepare_reboot()) + return -1; + + ret = tee_reboot_work(); + if (ret != 0) { + tloge("tee reboot work failed, ret 0x%x\n", ret); + goto err; + } + + smc_wakeup_broadcast(); +#ifndef CONFIG_DISABLE_SVC + svc_thread_release(); +#endif + + occupy_clean_cmd_buf(); + free_agent_list(); + send_smc_cmd_buffer(true); + ret = parse_params_from_tee(); + if (ret != 0) { + tloge("reboot parse params from tee failed\n"); + goto err; + } + ret = re_register_mailbox(); + if (ret != 0) { + tloge("re-register mailbox failed, ret 0x%x\n", ret); + goto err; + } + + ret = send_notify_cmd(GLOBAL_CMD_ID_REGISTER_NOTIFY_MEMORY); + if (ret != 0) { + tloge("send notify cmd failed, ret 0x%x\n", ret); + goto err; + } + + ret = tc_ns_register_host_nsid(); + if (ret != 0) { + tloge("register host nsid failed, ret 0x%x\n", ret); + goto err; + } + + free_all_session(); + ret = register_tloger_mem(); + if (ret != 0) { + tloge("re-register tloger failed, ret 0x%x\n", ret); + goto err; + } + + clr_tee_is_dead_flag(); + tee_reboot_done_work(); + clr_system_crash_flag(); + occupy_clean_cmd_buf(); +#ifndef CONFIG_DISABLE_SVC + ret = init_smc_svc_thread(); + if (ret != 0) { + tloge("init svc thread failed\n"); + goto err; + } +#endif + + tee_alarm_clear(TEE_CRASH); + kill_teecd_and_tlogcat(); + + return 0; + +err: + tee_alarm_report(TEE_REBOOT_FAIL); + return ret; +} +#ifdef CONFIG_TEE_UPGRADE +EXPORT_SYMBOL(tee_reboot); +#endif + +static struct task_struct *g_reboot_thread; +DEFINE_MUTEX(g_reboot_lock); +static DECLARE_WAIT_QUEUE_HEAD(reboot_th_wait); +static atomic_t g_reboot_th_run; + +#define RUN_REBOOT_THREAD 1 +#define STOP_REBOOT_THREAD 2 +static int tee_reboot_fn(void *arg) +{ + int ret; + while (1) { + ret = wait_event_interruptible(reboot_th_wait, + atomic_read(&g_reboot_th_run)); + if (ret != 0) { + tloge("wait reboot event interruptible failed!\n"); + return -EINTR; + } + if (atomic_read(&g_reboot_th_run) == STOP_REBOOT_THREAD) + break; + + mutex_lock(&g_reboot_lock); + if (tee_reboot() != 0) + tloge("tee reboot failed\n"); + + atomic_set(&g_reboot_th_run, 0); + mutex_unlock(&g_reboot_lock); + } + return ret; +} + +static int tee_create_reboot_thread(void) +{ + g_reboot_thread = kthread_create(tee_reboot_fn, NULL, "reboot_thread"); + if (unlikely(IS_ERR_OR_NULL(g_reboot_thread))) { + tloge("couldn't create reboot thread %ld\n", + PTR_ERR(g_reboot_thread)); + return -1; + } + return 0; +} + +#ifndef CONFIG_TEE_UPGRADE +int tee_init_reboot_thread(void) +{ + if (tee_create_reboot_thread() != 0) { + tloge("init reboot thread failed\n"); + return -EFAULT; + } + wake_up_process(g_reboot_thread); + return 0; +} + +void free_reboot_thread(void) +{ + set_tee_is_dead_flag(); + if (!IS_ERR_OR_NULL(g_reboot_thread)) { + atomic_set(&g_reboot_th_run, STOP_REBOOT_THREAD); + wake_up_interruptible(&reboot_th_wait); + kthread_stop(g_reboot_thread); + g_reboot_thread = NULL; + } +} + +int tee_wake_up_reboot(void) +{ + tloge("tee will reboot\n"); + atomic_set(&g_reboot_th_run, RUN_REBOOT_THREAD); + wake_up_interruptible(&reboot_th_wait); + return 0; +} +#else +int tee_init_reboot_thread(void) +{ + return 0; +} + +int tee_wake_up_reboot(void) +{ + return 0; +} + +void free_reboot_thread(void) +{ + return; +} +#endif diff --git a/tzdriver_internal/tee_reboot/reboot.h b/tzdriver_internal/tee_reboot/reboot.h new file mode 100644 index 0000000..2e22039 --- /dev/null +++ b/tzdriver_internal/tee_reboot/reboot.h @@ -0,0 +1,81 @@ +/* + * reboot.h + * + * functions declarations for tee reboot + * + * Copyright (c) 2023-2023 Huawei Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef REBOOT_H +#define REBOOT_H + +#include + +#define REBOOT_MAX_COUNT 100 +#define REBOOT_SLEEP 20 + +#define MPIDR_MT (1 << 24) +#define MPIDR_AFF_MASK 0xff00ffffffULL + +#define MPIDR_AFF3_FIELD 32 +#define MPIDR_AFF2_FIELD 16 +#define MPIDR_AFF1_FIELD 8 +#define AFF_MASK 0xff +#define SGI_AFF3_FIELD 48 +#define SGI_AFF2_FIELD 32 +#define SGI_AFF1_FIELD 16 +#define SGI_ID_FIELD 24 + +#define GIC_AFF_LEVEL 4 +#define GIC_CPU_RESCHEDULE 0 + +#define mrs(reg, v) asm volatile("mrs %0," reg : "=r"(v)) +#define msr(reg, v) asm volatile("msr " reg ",%0 :: "r" (v)) + +#define define_sysreg_rd(name, reg) \ +static unsigned long get_##name(void) \ +{ \ + unsigned long val; \ + mrs(#reg, val); \ + return val; \ +} + +#define define_sysreg_wr(name, reg) \ +static void set_##name(unsigned long val) \ +{ \ + msr(#reg, val); \ +} + +define_sysreg_rd(mpidr_el1, mpidr_el1); +define_sysreg_wr(icc_sgi1r_el1, s3_0_c12_c11_5); + +enum alarm_id { + TEE_CRASH = 0, + TEE_REBOOT_FAIL, +}; + +enum alarm_status { + ALARM_REPORT = 0, + ALARM_CLEAR, +}; + +typedef int32_t (*tee_alarm_func)(int32_t alarm_type, int32_t alarm_status); + +#ifdef CONFIG_TEE_REBOOT +bool is_tee_rebooting(void); +void get_teecd_pid(void); +void recycle_tlogcat_processes(void); +int tee_init_reboot_thread(void); +int tee_wake_up_reboot(void); +void free_reboot_thread(void); +#endif +#endif -- Gitee