From 648147af3c996ef9f6e0fb44337d16c1035a1c1e Mon Sep 17 00:00:00 2001 From: wangxing45 Date: Mon, 3 Jul 2023 15:06:38 +0800 Subject: [PATCH 1/4] update tzdriver to itrustee 7.3.0 --- CMakeLists.txt | 11 +- Makefile | 29 +- auth/auth_base_impl.c | 38 +- auth/auth_base_impl.h | 33 ++ auth/client_hash_auth.c | 26 +- core/agent.c | 304 +++++++---- core/agent.h | 27 +- 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_abi.h | 20 + core/smc_call.h | 39 ++ core/smc_smp.c | 498 +++++++----------- core/smc_smp.h | 33 +- core/tc_client_driver.c | 209 ++++++-- 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 - core/tzdebug.c | 467 ++++++++++++++++ core/tzdebug.h | 43 ++ ko_adapt.c | 2 +- tc_ns_client.h | 32 +- teek_client_constants.h | 11 + teek_client_id.h | 18 +- teek_ns_client.h | 23 + tlogger/tlogger.c | 316 ++++++++--- .../include/internal_functions.h | 35 +- tzdriver_internal/tee_reboot/reboot.c | 433 +++++++++++++++ tzdriver_internal/tee_reboot/reboot.h | 81 +++ 46 files changed, 3426 insertions(+), 1018 deletions(-) create mode 100644 core/smc_abi.c create mode 100644 core/smc_abi.h create mode 100644 core/smc_call.h 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 core/tzdebug.c create mode 100644 core/tzdebug.h create mode 100644 tzdriver_internal/tee_reboot/reboot.c create mode 100644 tzdriver_internal/tee_reboot/reboot.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d503196..2b6abb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,11 @@ set(TARGET_NAME tzdriver) # Add source files set(depend-objs "core/smc_smp.o core/tc_client_driver.o core/session_manager.o core/mailbox_mempool.o core/teek_app_load.o") -set(depend-objs "${depend-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") +set(depend-objs "${depend-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") set(depend-objs "${depend-objs} auth/auth_base_impl.o auth/client_hash_auth.o tlogger/tlogger.o tlogger/log_pages_cfg.o ko_adapt.o") set(depend-objs "${depend-objs} core/reserved_mempool.o tzdriver_internal/tee_trace_event/tee_trace_event.o tzdriver_internal/tee_trace_event/tee_trace_interrupt.o") -set(depend-objs "${depend-objs} core/shared_mem.o") +set(depend-objs "${depend-objs} core/shared_mem.o core/smc_abi.o core/tee_info.o tzdriver_internal/tee_reboot/reboot.o") +set(depend-objs "${depend-objs} core/tee_portal.o core/tc_cvm_driver.o") # Check libboundscheck.so execute_process(COMMAND cat /proc/kallsyms COMMAND grep vsnprintf_s OUTPUT_VARIABLE RESULT) @@ -30,7 +31,7 @@ set(KERNEL_DIR ${KPATH}/${KDIR}) # Set extra options set(CMAKE_EXTRA_FLAGS "-fstack-protector-strong -DCONFIG_TEELOG -DCONFIG_TZDRIVER_MODULE -DCONFIG_TEECD_AUTH -DCONFIG_PAGES_MEM=y -DCONFIG_CLOUDSERVER_TEECD_AUTH") -set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -DCONFIG_CPU_AFF_NR=0 -DCONFIG_BIG_SESSION=1000 -DCONFIG_NOTIFY_PAGE_ORDER=4 -DCONFIG_512K_LOG_PAGES_MEM -DCONFIG_TEE_TRACE") +set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -DCONFIG_CPU_AFF_NR=0 -DCONFIG_BIG_SESSION=100 -DCONFIG_NOTIFY_PAGE_ORDER=4 -DCONFIG_512K_LOG_PAGES_MEM -DCONFIG_TEE_TRACE") set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -DCONFIG_TEE_LOG_ACHIVE_PATH=\\\\\\\"/var/log/tee/last_teemsg\\\\\\\"") set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -DNOT_TRIGGER_AP_RESET -DLAST_TEE_MSG_ROOT_GID -DCONFIG_NOCOPY_SHAREDMEM") set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -DTEECD_PATH_UID_AUTH_CTX=\\\\\\\"/usr/bin/teecd:0\\\\\\\"") @@ -39,6 +40,10 @@ set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -I${PROJECT_SOURCE_DIR}/libboundsche set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -I${PROJECT_SOURCE_DIR}/tlogger -I${PROJECT_SOURCE_DIR}/tzdriver_internal/kthread_affinity -I${PROJECT_SOURCE_DIR}/tzdriver_internal/include") set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -I${PROJECT_SOURCE_DIR}/tzdriver_internal/tee_trace_event") set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -isystem /usr/lib/gcc/aarch64-linux-gnu/10.3.1/include") +set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -DCONFIG_TEE_TELEPORT_SUPPORT -DCONFIG_TEE_TELEPORT_AUTH -DTEE_TELEPORT_PATH_UID_AUTH_CTX=\\\\\\\"/usr/bin/tee_teleport:0\\\\\\\"") +set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -DCONFIG_CONFIDENTIAL_CONTAINER -DCONFIG_TEE_AGENTD_AUTH -DTEE_AGENTD_PATH_UID_AUTH_CTX=\\\\\\\"/usr/bin/agentd:0\\\\\\\"") +set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -DCONFIG_TA_AFFINITY=y -DCONFIG_TA_AFFINITY_CPU_NUMS=128 -DCONFIG_TEE_UPGRADE -DCONFIG_TEE_REBOOT -DCONFIG_CONFIDENTIAL_TEE") +set(CMAKE_EXTRA_FLAGS "${CMAKE_EXTRA_FLAGS} -I${PROJECT_SOURCE_DIR}/tzdriver_internal/tee_reboot -DMAILBOX_POOL_COUNT=8") # Compile .ko file add_custom_target(${TARGET_NAME} ALL COMMAND @echo "Compiling module ${TARGET_NAME}.ko...") 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..1e19c5c 100644 --- a/auth/client_hash_auth.c +++ b/auth/client_hash_auth.c @@ -54,7 +54,7 @@ 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 +295,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 +428,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 +448,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 +472,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/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..dcb17ea 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,62 @@ 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 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); @@ -108,93 +134,103 @@ static void mailbox_show_status(void) static void mailbox_show_details(void) { unsigned int i; + unsigned int 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 j; + unsigned int 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; - - if ((size == 0) || !g_m_zone) { - tlogw("alloc 0 size mailbox or zone struct is NULL\n"); - return NULL; - } + bool tag = false; if (order > g_max_oder || order < 0) { tloge("invalid order %d\n", order); return NULL; } - mutex_lock(&g_mb_lock); - for (i = (unsigned int)order; i <= (unsigned int)g_max_oder; i++) { - unsigned int j; - head = &g_m_zone->free_areas[i].page_list; - if (list_empty(head) != 0) - continue; + if ((size == 0) || !check_zone()) { + tlogw("alloc 0 size mailbox or zone struct is NULL\n"); + mutex_unlock(&g_mb_lock); + return NULL; + } + + 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[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 +239,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 +279,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 +321,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 +565,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 +574,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,13 +587,17 @@ 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); @@ -571,84 +614,184 @@ 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; + uint32_t 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); + g_m_zone = NULL; + 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; + uint32_t 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..ab3bc43 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(uint64_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_abi.h b/core/smc_abi.h new file mode 100644 index 0000000..da4dbdf --- /dev/null +++ b/core/smc_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/smc_call.h b/core/smc_call.h new file mode 100644 index 0000000..4d2d1fa --- /dev/null +++ b/core/smc_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/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..89ca104 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,16 @@ 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 +1265,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 +1298,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 +1317,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 +1329,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 +1342,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 +1355,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 +1388,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 +1403,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 +1414,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 +1425,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..14d4858 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/core/tzdebug.c b/core/tzdebug.c new file mode 100644 index 0000000..bce2d07 --- /dev/null +++ b/core/tzdebug.c @@ -0,0 +1,467 @@ +/* + * tzdebug.c + * + * function for set kthread affinity + * + * Copyright (c) 2021-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 "tzdebug.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tc_ns_log.h" +#include "tc_ns_client.h" +#include "tc_client_driver.h" +#include "teek_ns_client.h" +#include "smc_smp.h" +#include "teek_client_constants.h" +#include "mailbox_mempool.h" +#include "tlogger.h" +#include "cmdmonitor.h" +#include "session_manager.h" +#include "internal_functions.h" + +#define DEBUG_OPT_LEN 128 + +#ifdef CONFIG_TA_MEM_INUSE_ONLY +#define TA_MEMSTAT_ALL 0 +#else +#define TA_MEMSTAT_ALL 1 +#endif + +static struct dentry *g_tz_dbg_dentry; + +typedef void (*tzdebug_opt_func)(const char *param); + +struct opt_ops { + char *name; + tzdebug_opt_func func; +}; + +static DEFINE_MUTEX(g_meminfo_lock); +static struct tee_mem g_tee_meminfo; +static void tzmemdump(const char *param); +static int send_dump_mem(int flag, int history, const struct tee_mem *statmem) +{ + struct tc_ns_smc_cmd smc_cmd = { {0}, 0 }; + struct mb_cmd_pack *mb_pack = NULL; + int ret = 0; + + if (!statmem) { + tloge("statmem is NULL\n"); + return -EINVAL; + } + + mb_pack = mailbox_alloc_cmd_pack(); + if (!mb_pack) + return -ENOMEM; + + smc_cmd.cmd_id = GLOBAL_CMD_ID_DUMP_MEMINFO; + smc_cmd.cmd_type = CMD_TYPE_GLOBAL; + mb_pack->operation.paramtypes = teec_param_types( + TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); + mb_pack->operation.params[0].memref.buffer = (unsigned int)mailbox_virt_to_phys((uintptr_t)statmem); + mb_pack->operation.params[0].memref.size = sizeof(*statmem); + mb_pack->operation.buffer_h_addr[0] = + (unsigned int)((uint64_t)mailbox_virt_to_phys((uintptr_t)statmem) >> ADDR_TRANS_NUM); + mb_pack->operation.params[1].value.a = (unsigned int)flag; + mb_pack->operation.params[1].value.b = (unsigned int)history; + smc_cmd.operation_phys = + (unsigned int)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation); + smc_cmd.operation_h_phys = + (unsigned int)((uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM); + + livepatch_down_read_sem(); + if (tc_ns_smc(&smc_cmd) != 0) { + ret = -EPERM; + tloge("send dump mem failed\n"); + } + livepatch_up_read_sem(); + + tz_log_write(); + mailbox_free(mb_pack); + return ret; +} + +void tee_dump_mem(void) +{ + tzmemdump(NULL); + if (tlogger_store_msg(CONFIG_TEE_LOG_ACHIVE_PATH, + sizeof(CONFIG_TEE_LOG_ACHIVE_PATH)) < 0) { + tloge("[cmd_monitor_tick]tlogger store lastmsg failed\n"); + } +} + +/* get meminfo (tee_mem + N * ta_mem < 4Kbyte) from tee */ +static int get_tee_meminfo_cmd(void) +{ + int ret; + struct tee_mem *mem = NULL; + + mem = mailbox_alloc(sizeof(*mem), MB_FLAG_ZERO); + if (!mem) { + return -ENOMEM; + } + + ret = send_dump_mem(0, TA_MEMSTAT_ALL, mem); + if (ret != 0) { + tloge("send dump failed\n"); + mailbox_free(mem); + return ret; + } + + mutex_lock(&g_meminfo_lock); + ret = memcpy_s(&g_tee_meminfo, sizeof(g_tee_meminfo), mem, sizeof(*mem)); + if (ret != 0) { + tloge("memcpy failed\n"); + } + mutex_unlock(&g_meminfo_lock); + mailbox_free(mem); + + return ret; +} + +static atomic_t g_cmd_send = ATOMIC_INIT(1); + +void set_cmd_send_state(void) +{ + atomic_set(&g_cmd_send, 1); +} + +int get_tee_meminfo(struct tee_mem *meminfo) +{ + errno_t s_ret; + + if (!get_tz_init_flag()) { + return EFAULT; + } + if (!meminfo) { + return -EINVAL; + } + if (atomic_read(&g_cmd_send) != 0) { + if (get_tee_meminfo_cmd() != 0) { + return -EFAULT; + } + } else { + atomic_set(&g_cmd_send, 0); + } + + mutex_lock(&g_meminfo_lock); + s_ret = memcpy_s(meminfo, sizeof(*meminfo), + &g_tee_meminfo, sizeof(g_tee_meminfo)); + mutex_unlock(&g_meminfo_lock); + if (s_ret != 0) { + return -1; + } + + return 0; +} +EXPORT_SYMBOL(get_tee_meminfo); + +static void tzdump(const char *param) +{ + (void)param; + show_cmd_bitmap(); + wakeup_tc_siq(SIQ_DUMP_SHELL); +} + +static void tzmemdump(const char *param) +{ + struct tee_mem *mem = NULL; + + (void)param; + mem = mailbox_alloc(sizeof(*mem), MB_FLAG_ZERO); + if (!mem) { + tloge("mailbox alloc failed\n"); + return; + } + + if (send_dump_mem(1, 1, mem) != 0) { + tloge("send dump mem failed\n"); + } + mailbox_free(mem); +} + +static struct opt_ops g_opt_arr[] = { + {"dump", tzdump}, + {"memdump", tzmemdump}, + {"dump_service", dump_services_status}, +}; + +static ssize_t tz_dbg_opt_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char *obuf = NULL; + char *p = NULL; + ssize_t ret; + uint32_t oboff = 0; + uint32_t i; + + (void)(filp); + + obuf = kzalloc(DEBUG_OPT_LEN, GFP_KERNEL); + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)obuf)) + return -ENOMEM; + p = obuf; + + for (i = 0; i < ARRAY_SIZE(g_opt_arr); i++) { + int len = snprintf_s(p, DEBUG_OPT_LEN - oboff, DEBUG_OPT_LEN -oboff -1, + "%s ", g_opt_arr[i].name); + if (len < 0) { + kfree(obuf); + tloge("snprintf opt name of idx %d failed\n", i); + return -EINVAL; + } + p += len; + oboff += (uint32_t)len; + } + obuf[oboff - 1] = '\n'; + + ret = simple_read_from_buffer(ubuf, cnt, ppos, obuf, oboff); + kfree(obuf); + + return ret; +} + +static ssize_t tz_dbg_opt_write(struct file *filp, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char buf[128] = {0}; + char *value = NULL; + char *p = NULL; + uint32_t i = 0; + + if (!ubuf || !filp || !ppos) + return -EINVAL; + + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (cnt == 0) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt) != 0) + return -EFAULT; + + buf[cnt] = 0; + if (cnt > 0 && buf[cnt -1] == '\n') + buf[cnt - 1] = 0; + value = buf; + p = strsep(&value, ":"); /* when buf has no :, value may be NULL */ + if (!p) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(g_opt_arr); i++) { + if ((strncmp(p, g_opt_arr[i].name, + strlen(g_opt_arr[i].name)) ==0) && + strlen(p) == strlen(g_opt_arr[i].name)) { + g_opt_arr[i].func(value); + return (ssize_t)cnt; + } + } + return -EFAULT; +} + +static const struct file_operations g_tz_dbg_opt_fops = { + .owner = THIS_MODULE, + .read = tz_dbg_opt_read, + .write = tz_dbg_opt_write, +}; + +#ifdef CONFIG_MEMSTAT_DEBUGFS +static int memstat_debug_show(struct seq_file *m, void *v) +{ + struct tee_mem *mem_stat = NULL; + int ret; + uint32_t i; + (void)v; + + mem_stat = kzalloc(sizeof(*mem_stat), GFP_KERNEL); + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)mem_stat)) + return -ENOMEM; + + ret = get_tee_meminfo(mem_stat); + if (ret != 0) { + tloge("get tee meminfo failed \n"); + kfree(mem_stat); + mem_stat = NULL; + return -EINVAL; + } + + seq_printf(m, "TotalMem:%u Pmem:%u Free_Mem:%u Free_Mem_Min:%u\n TA_Num:%u\n", + mem_stat->total_mem, mem_stat->pmem, mem_stat->free_mem, mem_stat->free_mem_min, mem_stat->ta_num); + + for (i = 0; i < mem_stat->ta_num; i++) + seq_printf(m, "ta_name:%s ta_pmem:%u pmem_max:%u\n pmem_limit:%u\n", + mem_stat->ta_mem_info[i].ta_name, mem_stat->ta_mem_info[i].pmem, + mem_stat->ta_mem_info[i].pmem_max, mem_stat->ta_mem_info[i].pmem_limit); + + kfree(mem_stat); + mem_stat = NULL; + return 0; +} + +static int tz_memstat_open(struct inode *inode, struct file *file) +{ + (void)inode; + return single_open(file, memstat_debug_show, NULL); +} + +static const struct file_operations g_tz_dbg_memstat_fops = { + .owner = THIS_MODULE, + .open = tz_memstat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + +#ifdef CONFIG_TEE_TRACE +static int tee_trace_event_show(struct seq_file *m, void *v) +{ + struct tee_trace_view_t view = { 0, 0, 0, 0, { 0 }, { 0 } }; + struct trace_log_info log_info; + (void)v; + + get_tee_trace_start(&view); + if (view.buffer_is_full == 1) + seq_printf(m, "Total Trace Events: %u (Notice: Buffer is full)\n", view.total); + else + seq_printf(m, "Total Trace Events: %u\n", view.total); + + if (view.total > 0) { + uint32_t i = 0; + + while (get_tee_trace_next(&view, &log_info, false) != 1) { + uint32_t task_ca = (uint32_t)(log_info.add_info); + uint32_t task_idx = (uint32_t)(log_info.add_info >> 32); + + if (log_info.event_id == SCHED_IN || log_info.event_id == SCHED_OUT) { + seq_printf(m, "[%4U][cpu%3u][ca-%5u] %10llu : %s %u %s\n", + i++, log_info.cpu, log_info.ca_pid, log_info.time, log_info.event_name, + task_ca, get_tee_trace_task_name(task_idx)); + } else { + seq_printf(m, "[%4U][cpu%3u][ca-%5u] %10llu : %s %llu\n", + i++, log_info.cpu, log_info.ca_pid, log_info.time, log_info.event_name, + log_info.add_info); + } + } + } + + return 0; +} + +static int tee_trace_event_open(struct inode *inode, struct file *file) +{ + return single_open(file, tee_trace_event_show, NULL); +} + +struct tee_trace_cmd_t { + const char *cmd; + int (*func)(void); +} tee_trace_cmd[] = { + {"start", tee_trace_event_start}, + {"loop_record", tee_trace_event_start_loop_record}, + {"stop", tee_trace_event_stop} +}; + +static ssize_t tee_trace_event_write(struct file *filp, + const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + char buf[32] = {0}; + uint32_t i = 0; + + if (cnt >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt)) + return -EINVAL; + + buf[cnt] = 0; + if (cnt > 0 && buf[cnt - 1] == '\n') + buf[cnt - 1] = 0; + + for (i = 0; i < ARRAY_SIZE(tee_trace_cmd); i++) { + if (!strncmp(buf, tee_trace_cmd[i].cmd, + strlen(tee_trace_cmd[i].cmd))) { + tee_trace_cmd[i].func(); + return cnt; + } + } + return -EINVAL; +} + +static const struct file_operations tee_trace_event_fops = { + .owner = THIS_MODULE, + .open = tee_trace_event_open, + .read = seq_read, + .write = tee_trace_event_write, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + +int tzdebug_init(void) +{ +#if defined(DEF_ENG) || defined(CONFIG_TZDRIVER_MODULE) + g_tz_dbg_dentry = debugfs_create_dir("tzdebug", NULL); + if (!g_tz_dbg_dentry) + return -1; + + debugfs_create_file("opt", 0660, g_tz_dbg_dentry, NULL, + &g_tz_dbg_opt_fops); + +#ifdef CONFIG_MEMSTAT_DEBUGFS + debugfs_create_file("memstat", 0444, g_tz_dbg_dentry, NULL, + &g_tz_dbg_memstat_fops); +#endif + +#ifdef CONFIG_TEE_TRACE + debugfs_create_file("tee_trace", 0660, g_tz_dbg_dentry, NULL, + &tee_trace_event_fops); + tee_trace_event_enable(); +#endif + +#else + (void)g_tz_dbg_dentry; + (void)g_tz_dbg_opt_fops; +#endif + return 0; +} + +void free_tzdebug(void) +{ +#if defined(DEF_ENG) || defined(CONFIG_TZDRIVER_MODULE) + if (!g_tz_dbg_dentry) + return; + + debugfs_remove_recursive(g_tz_dbg_dentry); + g_tz_dbg_dentry = NULL; +#endif +} \ No newline at end of file diff --git a/core/tzdebug.h b/core/tzdebug.h new file mode 100644 index 0000000..02754d9 --- /dev/null +++ b/core/tzdebug.h @@ -0,0 +1,43 @@ +/* + * tzdebug.h + * + * function for find symbols not exported + * + * Copyright (c) 2012-2022 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 TZDEBUG_H +#define TZDEBUG_H + +#include +struct ta_mem { + char ta_name[64]; + uint32_t pmem; + uint32_t pmem_max; + uint32_t pmem_limit; +}; +#define MEMINFO_TA_MAX 100 +struct tee_mem { + uint32_t total_mem; + uint32_t pmem; + uint32_t free_mem; + uint32_t free_mem_min; + uint32_t ta_num; + struct ta_mem ta_mem_info[MEMINFO_TA_MAX]; +}; + +int get_tee_meminfo(struct tee_mem *meminfo); +void tee_dump_mem(void); +int tzdebug_init(void); +void free_tzdebug(void); + +#endif \ No newline at end of file diff --git a/ko_adapt.c b/ko_adapt.c index a094b28..c579703 100644 --- a/ko_adapt.c +++ b/ko_adapt.c @@ -110,7 +110,7 @@ struct workqueue_attrs *koadpt_alloc_workqueue_attrs(gfp_t gfp_mask) (void)gfp_mask; attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); - if (!attrs) { + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)attrs)) { tloge("alloc workqueue attr fail\n"); return NULL; } diff --git a/tc_ns_client.h b/tc_ns_client.h index 3d53252..bb66146 100644 --- a/tc_ns_client.h +++ b/tc_ns_client.h @@ -95,6 +95,12 @@ struct tc_ns_client_time { uint32_t millis; }; +struct tc_ns_tee_info { + uint16_t tzdriver_version_major; + uint16_t tzdriver_version_minor; + uint32_t reserved[15]; +}; + enum secfile_type_t { LOAD_TA = 0, LOAD_SERVICE, @@ -142,11 +148,12 @@ struct tc_ns_client_crl { uint32_t size; }; -#define TST_CMD_01 1 -#define TST_CMD_02 2 -#define TST_CMD_03 3 -#define TST_CMD_04 4 -#define TST_CMD_05 5 +#ifdef CONFIG_LOG_POOL_ENABLE +struct tc_ns_log_pool { + uint64_t addr; + uint64_t size; +}; +#endif #define MAX_SHA_256_SZ 32 @@ -176,8 +183,6 @@ struct tc_ns_client_crl { _IOWR(TC_NS_CLIENT_IOC_MAGIC, 13, struct tc_ns_client_context) #define TC_NS_CLIENT_IOCTL_LOGIN \ _IOWR(TC_NS_CLIENT_IOC_MAGIC, 14, int) -#define TC_NS_CLIENT_IOCTL_TST_CMD_REQ \ - _IOWR(TC_NS_CLIENT_IOC_MAGIC, 15, int) #define TC_NS_CLIENT_IOCTL_TUI_EVENT \ _IOWR(TC_NS_CLIENT_IOC_MAGIC, 16, int) #define TC_NS_CLIENT_IOCTL_SYC_SYS_TIME \ @@ -192,5 +197,16 @@ struct tc_ns_client_crl { _IOWR(TC_NS_CLIENT_IOC_MAGIC, 21, unsigned int) #define TC_NS_CLIENT_IOCTL_UPDATE_TA_CRL\ _IOWR(TC_NS_CLIENT_IOC_MAGIC, 22, struct tc_ns_client_crl) - +#ifdef CONFIG_LOG_POOL_ENABLE +#define TC_NS_CLIENT_IOCTL_GET_LOG_POOL \ + _IOWR(TC_NS_CLIENT_IOC_MAGIC, 23, struct tc_ns_log_pool) +#endif +#ifdef CONFIG_TEE_TELEPORT_SUPPORT +#define TC_NS_CLIENT_IOCTL_PORTAL_REGISTER \ + _IOWR(TC_NS_CLIENT_IOC_MAGIC, 24, struct agent_ioctl_args) +#define TC_NS_CLIENT_IOCTL_PORTAL_WORK \ + _IOWR(TC_NS_CLIENT_IOC_MAGIC, 25, struct agent_ioctl_args) +#endif +#define TC_NS_CLIENT_IOCTL_GET_TEE_INFO \ + _IOWR(TC_NS_CLIENT_IOC_MAGIC, 26, struct tc_ns_tee_info) #endif diff --git a/teek_client_constants.h b/teek_client_constants.h index 652c120..e408cd8 100644 --- a/teek_client_constants.h +++ b/teek_client_constants.h @@ -51,11 +51,22 @@ enum global_service_cmd_id { GLOBAL_CMD_ID_DUMP_MEMINFO = 0x1a, /* this cmd will be used to service no ca handle cmd */ GLOBAL_CMD_ID_SET_SERVE_CMD = 0x1b, + GLOBAL_CMD_ID_ADD_DYNAMIC_ION = 0x1c, + GLOBAL_CMD_ID_DEL_DYNAMIC_ION = 0x1d, + GLOBAL_CMD_ID_RELEASE_ION_SRV = 0x1e, + /* this cmd for tui to get notch_size */ + GLOBAL_CMD_ID_TUI_NOTCH = 0x1f, GLOBAL_CMD_ID_LATE_INIT = 0x20, + /* this cmd for tui to get information of foldable screen */ + GLOBAL_CMD_ID_TUI_FOLD = 0x21, GLOBAL_CMD_ID_GET_TEE_VERSION = 0x22, GLOBAL_CMD_ID_REGISTER_RESMEM = 0x24, GLOBAL_CMD_ID_DUMP_SRV_SESS = 0x25, GLOBAL_CMD_ID_TRACE_ENABLE = 0x26, +#ifdef CONFIG_TEE_TELEPORT_SUPPORT + GLOBAL_CMD_ID_PORTAL_WORK = 0x2b, +#endif + GLOBAL_CMD_ID_REGISTER_HOST_NSID = 0x2d, GLOBAL_CMD_ID_UNKNOWN = 0x7FFFFFFE, GLOBAL_CMD_ID_MAX = 0x7FFFFFFF }; diff --git a/teek_client_id.h b/teek_client_id.h index 94e22d9..be28d94 100644 --- a/teek_client_id.h +++ b/teek_client_id.h @@ -58,7 +58,16 @@ 0x80, 0x0B, 0x42, 0xBB, 0x3F, 0xC3, 0x14, 0x1F \ } \ } - +/* d2807abe-9242-54a9-d323-90a49ee291e3 */ +#define TEE_SERVICE_APPMGR \ +{ \ + 0xD2807ABE, \ + 0x9242, \ + 0x54A9, \ + { \ + 0xD3, 0x23, 0x90, 0xA4, 0x9E, 0xE2, 0x91, 0xE3 \ + } \ +} enum SVC_SECBOOT_CMD_ID { SECBOOT_CMD_ID_INVALID = 0x0, SECBOOT_CMD_ID_COPY_VRL, @@ -72,9 +81,12 @@ enum SVC_SECBOOT_CMD_ID { SECBOOT_CMD_ID_COPY_IMG_TYPE, SECBOOT_CMD_ID_BSP_MODEM_CALL, SECBOOT_CMD_ID_BSP_MODULE_VERIFY, - SECBOOT_CMD_ID_BSP_ICC_OPEN_THREAD, - SECBOOT_CMD_ID_BSP_RFILE_RW_THREAD, + SECBOOT_CMD_ID_BSP_MODEM_CALL_EXT = SECBOOT_CMD_ID_BSP_MODULE_VERIFY, SECBOOT_CMD_ID_GET_RNG_NUM, + SECBOOT_CMD_ID_BSP_LOAD_MODEM_TEEOS, + SECBOOT_CMD_ID_BSP_UNLOAD_MODEM_TEEOS, + SECBOOT_CMD_VERIFY_BYPASS_NET_CERT, + SECBOOT_CMD_ID_GET_SOCID, }; enum SVC_SECBOOT_IMG_TYPE { diff --git a/teek_ns_client.h b/teek_ns_client.h index 54fafe3..417b366 100644 --- a/teek_ns_client.h +++ b/teek_ns_client.h @@ -28,13 +28,27 @@ #define TC_NS_CLIENT_IOC_MAGIC 't' #define TC_NS_CLIENT_DEV "tc_ns_client" #define TC_PRIV_DEV "tc_private" +#define TC_NS_CVM_DEV "tc_ns_cvm" #define TC_NS_CLIENT_DEV_NAME "/dev/tc_ns_client" #define EXCEPTION_MEM_SIZE (8*1024) /* mem for exception handling */ + #define TSP_REQUEST 0xB2000008 #define TSP_RESPONSE 0xB2000009 + #define TSP_REE_SIQ 0xB200000A #define TSP_CRASH 0xB200000B + +#ifdef CONFIG_TEE_UPGRADE +#define TSP_REBOOT 0xB2000012 +#define TSP_CPU_ON 0xB2000013 +#define TSP_REBOOT_DONE 0xB2000015 +#else +#define TSP_REBOOT 0xB200000E +#define TSP_CPU_ON 0xB200000F +#define TSP_REBOOT_DONE 0xB2000010 +#endif + #define TSP_PREEMPTED 0xB2000005 #define TC_CALL_GLOBAL 0x01 #define TC_CALL_SYNC 0x02 @@ -84,6 +98,7 @@ struct tc_ns_service { struct list_head head; struct mutex operation_lock; /* for session's open/close */ atomic_t usage; + unsigned int nsid; }; #define SERVICES_MAX_COUNT 32 /* service limit can opened on 1 fd */ @@ -112,7 +127,13 @@ struct tc_ns_dev_file { uint32_t pub_key_len; uint8_t pub_key[MAX_PUBKEY_LEN]; int load_app_flag; +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + uint32_t nsid; +#endif struct completion close_comp; /* for kthread close unclosed session */ +#ifdef CONFIG_TEE_TELEPORT_SUPPORT + bool portal_enabled; +#endif }; union tc_ns_parameter { @@ -150,6 +171,7 @@ enum smc_cmd_type { CMD_TYPE_TA_AGENT, CMD_TYPE_TA2TA_AGENT, /* compatible with TA2TA2TA->AGENT etc. */ CMD_TYPE_BUILDIN_AGENT, + CMD_TYPE_RELEASE_AGENT, /* only for release agent */ }; struct tc_ns_smc_cmd { @@ -171,6 +193,7 @@ struct tc_ns_smc_cmd { unsigned int uid; unsigned int ca_pid; /* pid */ unsigned int pid; /* tgid */ + unsigned int nsid; unsigned int eventindex; /* tee audit event index for upload */ bool started; } __attribute__((__packed__)); diff --git a/tlogger/tlogger.c b/tlogger/tlogger.c index 90183a1..fa5bdda 100644 --- a/tlogger/tlogger.c +++ b/tlogger/tlogger.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -35,6 +37,11 @@ #include "tc_ns_log.h" #include "ko_adapt.h" #include "internal_functions.h" +#ifdef CONFIG_TEE_REBOOT +#include "reboot.h" +#endif +#include "tee_info.h" +#include "tee_compat_check.h" /* for log item ----------------------------------- */ #define LOG_ITEM_MAGIC 0x5A5A @@ -53,6 +60,7 @@ #define SET_READERPOS_CUR_BASE 6 #define SET_TLOGCAT_STAT_BASE 7 #define GET_TLOGCAT_STAT_BASE 8 +#define GET_TEE_INFO_BASE 9 /* get tee verison */ #define MAX_TEE_VERSION_LEN 256 @@ -65,6 +73,8 @@ _IO(LOGGERIOCTL, SET_TLOGCAT_STAT_BASE) #define TEELOGGER_GET_TLOGCAT_STAT \ _IO(LOGGERIOCTL, GET_TLOGCAT_STAT_BASE) +#define TEELOGGER_GET_TEE_INFO \ + _IOR(LOGGERIOCTL, GET_TEE_INFO_BASE, struct tc_ns_tee_info) int g_tlogcat_f = 0; @@ -73,14 +83,18 @@ int g_tlogcat_f = 0; #endif #define TEE_LOG_FILE_NAME_MAX 256 +#ifdef CONFIG_TEE_LOG_DUMP_PATH +/* last read offset only for msg dump */ uint32_t g_last_read_offset = 0; +#endif -#define NEVER_USED_LEN 32U +#define NEVER_USED_LEN 28U #define LOG_ITEM_RESERVED_LEN 1U /* 64 byte head + user log */ struct log_item { unsigned char never_used[NEVER_USED_LEN]; + unsigned int nsid; unsigned short magic; unsigned short reserved0; uint32_t serial_no; @@ -112,7 +126,8 @@ struct log_buffer_flag { uint32_t last_pos; uint32_t write_loops; uint32_t log_level; - uint32_t reserved[LOG_BUFFER_RESERVED_LEN]; /* [0] for magic, [1] for serial_no */ + /* [0] is magic failed, [1] is serial_no failed, used fior log retention feature */ + uint32_t reserved[LOG_BUFFER_RESERVED_LEN]; uint32_t max_len; unsigned char version_info[VERSION_INFO_LEN]; }; @@ -127,17 +142,27 @@ static struct log_buffer *g_log_buffer = NULL; struct tlogger_log { unsigned char *buffer_info; /* ring buffer info */ struct mutex mutex_info; /* this mutex protects buffer_info */ - wait_queue_head_t wait_queue_head; /* wait queue head for reader */ struct list_head logs; /* log channels list */ + struct mutex mutex_log_chnl; /* this mutex protects log channels */ struct miscdevice misc_device; /* misc device log */ struct list_head readers; /* log's readers */ }; static LIST_HEAD(m_log_list); +struct tlogger_group { + struct list_head node; + uint32_t nsid; + volatile uint32_t reader_cnt; + volatile uint32_t tlogf_stat; +}; + struct tlogger_reader { struct tlogger_log *log; /* tlogger_log info data */ + struct tlogger_group *group; /* tlogger_group info data */ + struct pid *pid; /* current process pid */ struct list_head list; /* log entry in tlogger_log's list */ + wait_queue_head_t wait_queue_head; /* wait queue head for reader */ /* Current reading position, start position of next read again */ uint32_t r_off; uint32_t r_loops; @@ -153,6 +178,9 @@ static uint32_t g_log_mem_len = 0; static uint32_t g_tlogcat_count = 0; static struct tlogger_log *g_log; +static struct mutex g_reader_group_mutex; +static LIST_HEAD(g_reader_group_list); + static struct tlogger_log *get_reader_log(const struct file *file) { struct tlogger_reader *reader = NULL; @@ -203,6 +231,17 @@ static struct log_item *get_next_log_item(const unsigned char *buffer_start, return item; } +static bool check_group_compat(struct tlogger_group *group, struct log_item *item) +{ + if (group->nsid == item->nsid) + return true; + + if (group->nsid == PROC_PID_INIT_INO && item->nsid == 0) + return true; + + return false; +} + struct reader_position { const unsigned char *buffer_start; uint32_t max_len; @@ -210,8 +249,8 @@ struct reader_position { uint32_t end_pos; }; -static uint32_t parse_log_item(char __user *buf, size_t count, - struct reader_position *position, uint32_t *read_off, +static uint32_t parse_log_item(struct tlogger_reader *reader, + char __user *buf, size_t count, struct reader_position *position, bool *user_buffer_left) { struct log_item *next_item = NULL; @@ -224,7 +263,7 @@ static uint32_t parse_log_item(char __user *buf, size_t count, buf_written = 0; buf_left = count; - con = (!read_off || !position->buffer_start); + con = (!position->buffer_start || reader->group == NULL); if (con) return buf_written; @@ -238,21 +277,22 @@ static uint32_t parse_log_item(char __user *buf, size_t count, /* copy to user */ item_len = next_item->buffer_len + sizeof(*next_item); - if (buf_left < item_len) { - *user_buffer_left = false; - break; - } + if (check_group_compat(reader->group, next_item)) { + if (buf_left < item_len) { + *user_buffer_left = false; + break; + } - start_pos += item_len; - if (copy_to_user(buf + buf_written, - (void *)next_item, item_len) != 0) - tloge("copy failed, item len %u\n", item_len); + if (copy_to_user(buf + buf_written, (void *)next_item, item_len) != 0) + tloge("copy failed, item len %u\n", item_len); - buf_written += item_len; - buf_left -= item_len; + buf_written += item_len; + buf_left -= item_len; + } + start_pos += item_len; } - *read_off = start_pos; + reader->r_off = start_pos; return buf_written; } @@ -333,15 +373,9 @@ static void set_reader_position(struct reader_position *position, static ssize_t proc_read_ret(uint32_t buf_written, const struct tlogger_reader *reader) { - ssize_t ret; - - if (buf_written == 0) { - ret = LOG_READ_STATUS_ERROR; - } else { - ret = buf_written; - tlogd("read length %u\n", buf_written); - g_last_read_offset = reader->r_off; - } + ssize_t ret = buf_written; + (void)reader; + tlogd("read length %u\n", buf_written); return ret; } @@ -376,8 +410,7 @@ static ssize_t trigger_parse_log(char __user *buf, size_t count, set_reader_position(&position, log_buffer->buffer_start, buffer_flag->max_len, reader->r_off, log_last_pos); - buf_written = parse_log_item(buf, count, &position, - &reader->r_off, &user_buffer_left); + buf_written = parse_log_item(reader, buf, count, &position, &user_buffer_left); return proc_read_ret(buf_written, reader); } @@ -392,16 +425,14 @@ static ssize_t trigger_parse_log(char __user *buf, size_t count, set_reader_position(&position, log_buffer->buffer_start, buffer_flag->max_len, reader->r_off, buffer_flag->max_len); - buf_written = parse_log_item(buf, count, &position, - &reader->r_off, &user_buffer_left); + buf_written = parse_log_item(reader, buf, count, &position, &user_buffer_left); if (count > buf_written && user_buffer_left) { set_reader_position(&position, log_buffer->buffer_start, buffer_flag->max_len, 0, log_last_pos); - buf_written += parse_log_item(buf + buf_written, - count - buf_written, &position, - &reader->r_off, &user_buffer_left); + buf_written += parse_log_item(reader, buf + buf_written, + count - buf_written, &position, &user_buffer_left); reader->r_loops = buffer_flag->write_loops; } @@ -443,6 +474,7 @@ static ssize_t process_tlogger_read(struct file *file, void tz_log_write(void) { struct log_buffer *log_buffer = NULL; + struct tlogger_reader *reader = NULL; if (!g_log) return; @@ -451,14 +483,55 @@ void tz_log_write(void) if (!log_buffer) return; - if (g_last_read_offset != log_buffer->flag.last_pos) { - tlogd("wake up write tz log\n"); - wake_up_interruptible(&g_log->wait_queue_head); + mutex_lock(&g_log->mutex_log_chnl); + list_for_each_entry(reader, &g_log->readers, list) { + if (reader->r_off != log_buffer->flag.last_pos) { + tlogd("wake up write tz log\n"); + wake_up_interruptible(&reader->wait_queue_head); + } } + mutex_unlock(&g_log->mutex_log_chnl); return; } +#ifdef CONFIG_TEE_REBOOT +void recycle_tlogcat_processes(void) +{ + struct log_buffer *log_buffer = NULL; + struct tlogger_reader *reader = NULL; + + if (g_log == NULL) + return; + + log_buffer = (struct log_buffer *)g_log->buffer_info; + if (log_buffer == NULL) + return; + + mutex_lock(&g_log->mutex_log_chnl); + list_for_each_entry(reader, &g_log->readers, list) + kill_pid(reader->pid, SIGKILL, 1); + mutex_unlock(&g_log->mutex_log_chnl); +} +#endif + +static struct tlogger_group *get_tlogger_group(void) +{ + struct tlogger_group *group = NULL; +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + uint32_t nsid = task_active_pid_ns(current)->ns.inum; +#else + uint32_t nsid = PROC_PID_INIT_INO; +#endif + + list_for_each_entry(group, &g_reader_group_list, node) { + if (group->nsid == nsid) + return group; + } + + return NULL; +} + static struct tlogger_log *get_tlogger_log_by_minor(int minor) { struct tlogger_log *log = NULL; @@ -471,12 +544,45 @@ static struct tlogger_log *get_tlogger_log_by_minor(int minor) return NULL; } +static void init_tlogger_reader(struct tlogger_reader *reader, struct tlogger_log *log, struct tlogger_group *group) +{ + reader->log = log; + reader->group = group; + + get_task_struct(current); + reader->pid = get_task_pid(current, PIDTYPE_PID); + put_task_struct(current); + + reader->r_all = true; + reader->r_off = 0; + reader->r_loops = 0; + reader->r_sn = 0; + reader->r_failtimes = 0; + reader->r_is_tlogf = 0; + reader->r_from_cur = 0; + + INIT_LIST_HEAD(&reader->list); + init_waitqueue_head(&reader->wait_queue_head); +} + +static void init_tlogger_group(struct tlogger_group *group) +{ + group->reader_cnt = 1; +#ifdef CONFIG_CONFIDENTIAL_CONTAINER + group->nsid = task_active_pid_ns(current)->ns.inum; +#else + group->nsid = PROC_PID_INIT_INO; +#endif + group->tlogf_stat = 0; +} + static int process_tlogger_open(struct inode *inode, struct file *file) { struct tlogger_log *log = NULL; int ret; struct tlogger_reader *reader = NULL; + struct tlogger_group *group = NULL; tlogd("open logger open ++\n"); /* not support seek */ @@ -489,25 +595,37 @@ static int process_tlogger_open(struct inode *inode, if (!log) return -ENODEV; + mutex_lock(&g_reader_group_mutex); + group = get_tlogger_group(); + if (group == NULL) { + group = kzalloc(sizeof(*group), GFP_KERNEL); + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)group)) { + mutex_unlock(&g_reader_group_mutex); + return -ENOMEM; + } + init_tlogger_group(group); + list_add_tail(&group->node, &g_reader_group_list); + } else { + group->reader_cnt++; + } + mutex_unlock(&g_reader_group_mutex); + reader = kmalloc(sizeof(*reader), GFP_KERNEL); - if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)reader)) + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)reader)) { + mutex_lock(&g_reader_group_mutex); + if (--group->reader_cnt == 0) { + list_del(&group->node); + kfree(group); + } + mutex_unlock(&g_reader_group_mutex); return -ENOMEM; + } + init_tlogger_reader(reader, log, group); - reader->log = log; - reader->r_all = true; - reader->r_off = 0; - reader->r_loops = 0; - reader->r_sn = 0; - reader->r_failtimes = 0; - reader->r_is_tlogf = 0; - reader->r_from_cur = 0; - - INIT_LIST_HEAD(&reader->list); - - mutex_lock(&log->mutex_info); + mutex_lock(&log->mutex_log_chnl); list_add_tail(&reader->list, &log->readers); g_tlogcat_count++; - mutex_unlock(&log->mutex_info); + mutex_unlock(&log->mutex_log_chnl); file->private_data = reader; tlogd("tlogcat count %u\n", g_tlogcat_count); @@ -519,6 +637,7 @@ static int process_tlogger_release(struct inode *ignored, { struct tlogger_reader *reader = NULL; struct tlogger_log *log = NULL; + struct tlogger_group *group = NULL; (void)ignored; @@ -539,15 +658,23 @@ static int process_tlogger_release(struct inode *ignored, return -1; } - mutex_lock(&log->mutex_info); + mutex_lock(&log->mutex_log_chnl); list_del(&reader->list); if (g_tlogcat_count >= 1) g_tlogcat_count--; - mutex_unlock(&log->mutex_info); - - tlogd("logger_release r_is_tlogf-%u\n", reader->r_is_tlogf); - if (reader->r_is_tlogf != 0) - g_tlogcat_f = 0; + mutex_unlock(&log->mutex_log_chnl); + + group = reader->group; + if (group != NULL) { + mutex_lock(&g_reader_group_mutex); + if (reader->r_is_tlogf != 0) + group->tlogf_stat = 0; + if (--group->reader_cnt == 0) { + list_del(&group->node); + kfree(group); + } + mutex_unlock(&g_reader_group_mutex); + } kfree(reader); tlogd("tlogcat count %u\n", g_tlogcat_count); @@ -586,7 +713,7 @@ static unsigned int process_tlogger_poll(struct file *file, return ret; } - poll_wait(file, &log->wait_queue_head, wait); + poll_wait(file, &reader->wait_queue_head, wait); if (buffer->flag.last_pos != reader->r_off) ret |= POLLIN | POLLRDNORM; @@ -622,24 +749,46 @@ static void set_tlogcat_f_stat(const struct file *file) { struct tlogger_reader *reader = NULL; - if (!file) + if (file == NULL) { return; + } reader = file->private_data; - if (!reader) + if (reader == NULL) { return; + } reader->r_is_tlogf = 1; - g_tlogcat_f = 1; + if (reader->group != NULL) { + mutex_lock(&g_reader_group_mutex); + reader->group->tlogf_stat = 1; + mutex_unlock(&g_reader_group_mutex); + } - tlogi("set tlogcat_f-%d\n", g_tlogcat_f); return; } -static int get_tlogcat_f_stat(void) +static int get_tlogcat_f_stat(const struct file *file) { - tlogi("get tlogcat_f-%d\n", g_tlogcat_f); - return g_tlogcat_f; + struct tlogger_reader *reader = NULL; + int tlogf_stat = 0; + + if (file == NULL) { + return tlogf_stat; + } + + reader = file->private_data; + if (reader == NULL) { + return tlogf_stat; + } + + if (reader->group != NULL) { + mutex_lock(&g_reader_group_mutex); + tlogf_stat = reader->group->tlogf_stat; + mutex_unlock(&g_reader_group_mutex); + } + + return tlogf_stat; } static int check_user_arg(unsigned long arg, size_t arg_len) @@ -711,7 +860,10 @@ static long process_tlogger_ioctl(struct file *file, ret = 0; break; case TEELOGGER_GET_TLOGCAT_STAT: - ret = get_tlogcat_f_stat(); + ret = get_tlogcat_f_stat(file); + break; + case TEELOGGER_GET_TEE_INFO: + ret = tc_ns_get_tee_info(file, (void *)(uintptr_t)arg); break; default: tloge("ioctl error default\n"); @@ -753,7 +905,7 @@ static int __init register_device(const char *log_name, (void)size; log = kzalloc(sizeof(*log), GFP_KERNEL); - if (!log) { + if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)log)) { tloge("kzalloc is failed\n"); return -ENOMEM; } @@ -768,9 +920,9 @@ static int __init register_device(const char *log_name, log->misc_device.fops = &g_logger_fops; log->misc_device.parent = NULL; - init_waitqueue_head(&log->wait_queue_head); INIT_LIST_HEAD(&log->readers); mutex_init(&log->mutex_info); + mutex_init(&log->mutex_log_chnl); INIT_LIST_HEAD(&log->logs); list_add_tail(&log->logs, &m_log_list); @@ -826,15 +978,13 @@ static struct log_item *msg_get_next(unsigned char *buffer_start, #ifdef CONFIG_TZDRIVER_MODULE /* there is no way to chown in kernel-5.10 for ko */ -static int tlogger_chown(const char *file_path, uint32_t file_path_len) +static void tlogger_chown(const char *file_path, uint32_t file_path_len) { (void)file_path; (void)file_path_len; - - return 0; } #else -static int tlogger_chown(const char *file_path, uint32_t file_path_len) +static void tlogger_chown(const char *file_path, uint32_t file_path_len) { (void)file_path_len; uid_t user = ROOT_UID; @@ -846,7 +996,7 @@ static int tlogger_chown(const char *file_path, uint32_t file_path_len) /* not need modify chown attr */ if (group == ROOT_GID && user == ROOT_UID) - return 0; + return; old_fs = get_fs(); set_fs(KERNEL_DS); @@ -855,14 +1005,10 @@ static int tlogger_chown(const char *file_path, uint32_t file_path_len) #else ret = (int)sys_chown((const char __user *)file_path, user, group); #endif - if (ret != 0) { - tloge("sys chown for last teemsg file error\n"); - set_fs(old_fs); - return -1; - } + if (ret != 0) + tloge("sys chown for last teemsg file error %d\n", ret); set_fs(old_fs); - return 0; } #endif @@ -1096,9 +1242,7 @@ int tlogger_store_msg(const char *file_path, uint32_t file_path_len) if (ret != 0) goto free_res; - ret = tlogger_chown(file_path, file_path_len); - if (ret != 0) - goto free_res; + tlogger_chown(file_path, file_path_len); ret = write_version_to_msg(filep, &pos); if (ret != 0) @@ -1107,6 +1251,10 @@ int tlogger_store_msg(const char *file_path, uint32_t file_path_len) ret = write_log_to_msg(filep, buffer, buffer_max_len, &pos, read_start, read_end); +#ifdef CONFIG_TEE_LOG_DUMP_PATH + g_last_read_offset = ((struct log_buffer*)g_log->buffer_info)->flag.last_pos; +#endif + free_res: if (buffer) { kfree(buffer); @@ -1156,7 +1304,7 @@ int register_mem_to_teeos(uint64_t mem_addr, uint32_t mem_len, bool is_cache_mem (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); @@ -1221,7 +1369,7 @@ static int register_tloger_device(void) { int ret; - tlogi("tlogcat version 1.0.0\n"); + tlogi("tlogcat version %d.%d\n", TZDRIVER_LEVEL_MAJOR_SELF, TZDRIVER_LEVEL_MINOR_SELF); ret = register_device(LOGGER_LOG_TEEOS, (uintptr_t)g_log_buffer, sizeof(*g_log_buffer) + g_log_buffer->flag.max_len); if (ret != 0) { @@ -1300,5 +1448,5 @@ module_exit(free_tlogger_service); MODULE_AUTHOR("iTrustee"); MODULE_DESCRIPTION("TrustCore Logger"); -MODULE_VERSION("1.00"); +MODULE_VERSION("3.00"); #endif diff --git a/tzdriver_internal/include/internal_functions.h b/tzdriver_internal/include/internal_functions.h index 05104f8..215e0ac 100644 --- a/tzdriver_internal/include/internal_functions.h +++ b/tzdriver_internal/include/internal_functions.h @@ -28,13 +28,6 @@ static inline int tc_ns_register_ion_mem(void) } #endif -#ifndef CONFIG_HISI_VLTMM -static inline void vltmm_agent_register(void) -{ - return; -} -#endif - #ifndef CONFIG_TEE_FAULT_MANAGER static inline void fault_monitor_start(int32_t type) { @@ -92,7 +85,7 @@ static inline void kill_ion_by_uuid(const struct tc_uuid *uuid) } #endif -#ifndef CONFIG_ION_HISI +#ifndef CONFIG_ION_MM static inline int alloc_for_ion(const struct tc_call_params *call_params, struct tc_op_params *op_params, uint8_t kernel_params, uint32_t param_type, unsigned int index) @@ -107,7 +100,7 @@ static inline int alloc_for_ion(const struct tc_call_params *call_params, } #endif -#ifndef CONFIG_ION_HISI_SECSG +#ifndef CONFIG_ION_MM_SECSG static inline int alloc_for_ion_sglist(const struct tc_call_params *call_params, struct tc_op_params *op_params, uint8_t kernel_params, uint32_t param_type, unsigned int index) @@ -142,9 +135,6 @@ static inline void tz_workqueue_bind_mask(struct workqueue_struct *wq, } #endif -#ifdef CONFIG_TEE_TUI -#include "tui.h" -#else static inline bool is_tui_agent(unsigned int agent_id) { (void)agent_id; @@ -204,11 +194,7 @@ static inline int tc_ns_tui_event(struct tc_ns_dev_file *dev_file, const void *a (void)argp; return 0; } -#endif -#ifdef CONFIG_LIVEPATCH_ENABLE -#include "livepatch_cmd.h" -#else static inline int livepatch_init(const struct device *dev) { (void)dev; @@ -223,7 +209,6 @@ static inline void livepatch_up_read_sem(void) static inline void free_livepatch(void) { } -#endif #ifdef CONFIG_TEE_TRACE #include "tee_trace_event.h" @@ -263,4 +248,20 @@ static inline void free_reboot_thread(void) } #endif + +#ifdef CONFIG_KBOX_MEM +#include "kbox.h" +#else +static inline void kbox_report(int32_t type, const uint8_t *ta_uuid, uint32_t uuid_len) +{ + (void)type; + (void)ta_uuid; + (void)uuid_len; +} +#endif + +#if defined(DYNAMIC_DRV_DIR) || defined(DYNAMIC_CRYPTO_DRV_DIR) || defined(DYNAMIC_SRV_DIR) +#include "tz_load_dynamic.h" #endif + +#endif \ No newline at end of file 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..d65237e --- /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 From eca22ac2bc0cfa8f30c1beb7805bd525c777b3b6 Mon Sep 17 00:00:00 2001 From: wangxing45 Date: Wed, 5 Jul 2023 14:29:09 +0000 Subject: [PATCH 2/4] update Makefile. fix start bugs Signed-off-by: wangxing45 --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 030b138..0fc2c80 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ tzdriver-objs += core/agent.o core/gp_ops.o core/mem.o core/cmdmonitor.o core/tz 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 core/smc_abi.o +tzdriver-objs += core/tee_client_api.o tzdriver-objs += core/tee_info.o tzdriver-objs += tzdriver_internal/tee_reboot/reboot.o -- Gitee From 6559a2253706d7ceedcf7519091366461019e73e Mon Sep 17 00:00:00 2001 From: wangxing45 Date: Wed, 5 Jul 2023 14:35:33 +0000 Subject: [PATCH 3/4] =?UTF-8?q?update=20core/teek=5Fclient=5Fapi.c.=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=AB=98=E7=BA=A7=E8=AF=AD=E8=A8=80=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: wangxing45 --- core/teek_client_api.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/teek_client_api.c b/core/teek_client_api.c index 0c68793..2b15096 100644 --- a/core/teek_client_api.c +++ b/core/teek_client_api.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -313,7 +314,8 @@ uint32_t teek_check_operation(const struct teec_operation *operation) */ int teek_is_agent_alive(unsigned int agent_id) { - return is_agent_alive(agent_id); + if (!get_tz_init_flag()) return EFAULT; + return is_agent_alive(agent_id, PROC_PID_INIT_INO); } /* @@ -325,7 +327,7 @@ uint32_t teek_initialize_context(const char *name, struct teec_context *context) { int32_t ret; - + if (!get_tz_init_flag()) return (uint32_t)TEEC_ERROR_BUSY; /* name current not used */ (void)(name); tlogd("teek_initialize_context Started:\n"); @@ -353,6 +355,7 @@ EXPORT_SYMBOL(teek_initialize_context); */ void teek_finalize_context(struct teec_context *context) { + if (!get_tz_init_flag()) return; tlogd("teek_finalize_context started\n"); if (!context || !context->dev) { tloge("context or dev is null, not correct\n"); @@ -557,7 +560,7 @@ uint32_t teek_open_session(struct teec_context *context, { int i; uint32_t ret; - + if (!get_tz_init_flag()) return (uint32_t)TEEC_ERROR_BUSY; for (i = 0; i < RETRY_TIMES; i++) { ret = proc_teek_open_session(context, session, destination, connection_method, connection_data, -- Gitee From 1b10bfb282388a97085d5472f8dc6da3c357e043 Mon Sep 17 00:00:00 2001 From: wangxing45 Date: Wed, 5 Jul 2023 14:40:12 +0000 Subject: [PATCH 4/4] update core/tzdebug.c. fix bufs Signed-off-by: wangxing45 --- core/tzdebug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/tzdebug.c b/core/tzdebug.c index bce2d07..2a8bc86 100644 --- a/core/tzdebug.c +++ b/core/tzdebug.c @@ -358,16 +358,16 @@ static int tee_trace_event_show(struct seq_file *m, void *v) if (view.total > 0) { uint32_t i = 0; - while (get_tee_trace_next(&view, &log_info, false) != 1) { + while (get_tee_trace_next(&view, &log_info, false) != -1) { uint32_t task_ca = (uint32_t)(log_info.add_info); uint32_t task_idx = (uint32_t)(log_info.add_info >> 32); if (log_info.event_id == SCHED_IN || log_info.event_id == SCHED_OUT) { - seq_printf(m, "[%4U][cpu%3u][ca-%5u] %10llu : %s %u %s\n", + seq_printf(m, "[%4u][cpu%3u][ca-%5u] %10llu : %s %u %s\n", i++, log_info.cpu, log_info.ca_pid, log_info.time, log_info.event_name, task_ca, get_tee_trace_task_name(task_idx)); } else { - seq_printf(m, "[%4U][cpu%3u][ca-%5u] %10llu : %s %llu\n", + seq_printf(m, "[%4u][cpu%3u][ca-%5u] %10llu : %s %llu\n", i++, log_info.cpu, log_info.ca_pid, log_info.time, log_info.event_name, log_info.add_info); } -- Gitee