add tzdriver

Signed-off-by: suwanghw <wangsu14@huawei.com>
This commit is contained in:
suwanghw
2023-12-27 19:46:07 +08:00
parent a16b72dce5
commit 3d157be8a3
101 changed files with 23771 additions and 0 deletions
+1
View File
@@ -1,5 +1,6 @@
(1) The directories below are licensed under GPL-2.0-or-later.
./newip/
./tzdriver/
./xpm/
./qos_auth/
./ucollection/
+3
View File
@@ -64,6 +64,7 @@ Note:If the text contains special characters, please escape them according to th
<policyitem type="compatibility" name="GPL" path="ucollection/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="compatibility" name="GPL" path="code_sign/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="compatibility" name="GPL" path="container_escape_detection/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="compatibility" name="GPL" path="tzdriver/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="compatibility" name="GPL" path="module_sample/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="newip/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="xpm/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
@@ -73,6 +74,8 @@ Note:If the text contains special characters, please escape them according to th
<policyitem type="license" name="GPL" path="code_sign/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="container_escape_detection/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="module_sample/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="license" name="GPL" path="tzdriver/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
<policyitem type="copyright" name="Huawei Technologies Co." path="tzdriver/.*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc="Copyright information"/>
</policy>
</policylist>
<filefilterlist>
+2
View File
@@ -0,0 +1,2 @@
add_device_ko(LOCAL_MODULE tzdriver
KO_SRC_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
+37
View File
@@ -0,0 +1,37 @@
menu "TEE OS"
config TZDRIVER
tristate "Secure Execution Communicator driver"
default n
help
Provides a communication interface between userspace and
TrustZone Operating Environment.
config SECBOOT_IMG
bool "tzdriver split secboot img into modem and ap"
default n
depends on KERNEL_CLIENT
help
Macro defined for splitting modem and ap img
config SECBOOT_IMG_V2
bool "tzdriver split modem and ap for v2"
default n
depends on KERNEL_CLIENT
help
Macro defined for splitting modem and ap img v2
config ASAN_DEBUG
bool "ASAN debug version"
default n
help
Macro defined for ASAN debug version
source "drivers/tzdriver/auth/Kconfig"
source "drivers/tzdriver/core/Kconfig"
source "drivers/tzdriver/tlogger/Kconfig"
source "drivers/tzdriver/agent_rpmb/Kconfig"
source "drivers/tzdriver/ion/Kconfig"
source "drivers/tzdriver/tui/Kconfig"
endmenu
+14
View File
@@ -0,0 +1,14 @@
ifeq ($(CONFIG_TZDRIVER),y)
KERNEL_DIR := $(srctree)
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../third_party/bounds_checking_function/include/
obj-$(CONFIG_TZDRIVER) += agent_rpmb/
obj-$(CONFIG_TZDRIVER) += auth/
obj-$(CONFIG_TZDRIVER) += core/
obj-$(CONFIG_TZDRIVER) += tlogger/
obj-$(CONFIG_TZDRIVER) += ion/
obj-$(CONFIG_TZDRIVER) += tui/
obj-$(CONFIG_TZDRIVER) += whitelist/
endif
+1
View File
@@ -0,0 +1 @@
core/agent.h
+6
View File
@@ -0,0 +1,6 @@
config RPMB_AGENT
bool "Tzdriver Rpmb Agent"
default n
depends on TZDRIVER
help
Tzdriver Rpmb Agent
+35
View File
@@ -0,0 +1,35 @@
KERNEL_DIR := $(srctree)
ifneq ($(TARGET_BUILD_VARIANT),user)
ccflags-y += -DDEF_ENG
endif
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../third_party/bounds_checking_function/include
ifeq ($(CONFIG_MEDIATEK_SOLUTION),y)
MTK_PLATFORM := $(subst ",,$(CONFIG_MTK_PLATFORM))
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/mmc/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/mmc/card
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/misc/mediatek/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/misc/mediatek/include/mt-plat
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/misc/mediatek/base/power/$(MTK_PLATFORM)
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/misc/mediatek/base/power/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/devfreq
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/scsi/ufs
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/mmc/host/mediatek/ComboA
ifeq ($(CONFIG_MTK_PLATFORM), "mt6761")
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/mmc/host/mediatek/ComboA/mt6765
else
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/mmc/host/mediatek/ComboA/$(MTK_PLATFORM)
endif
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/mmc/host/mediatek/$(MTK_PLATFORM)
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/mmc/host/mediatek/$(MTK_PLATFORM)/$(MTK_PLATFORM)
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver/agent_rpmb/mplat
obj-$(CONFIG_RPMB_AGENT) += core/agent_rpmb.o mplat/rpmb_driver.o
else
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver/agent_rpmb/generic
obj-$(CONFIG_RPMB_AGENT) += core/agent_rpmb.o generic/rpmb_driver.o
endif
+331
View File
@@ -0,0 +1,331 @@
/*
* agent_rpmb.c
*
* rpmb agent manager function, such as register
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "agent_rpmb.h"
#include <linux/fs.h>
#include <linux/mmc/ioctl.h> /* for struct mmc_ioc_rpmb */
#include <linux/mmc/card.h> /* for struct mmc_card */
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <securec.h>
#include "teek_client_constants.h"
#include "teek_ns_client.h"
#include "agent.h"
#include "tc_ns_log.h"
#include "smc_smp.h"
#include "rpmb_driver.h"
enum rpmb_cmd {
SEC_GET_DEVINFO,
SEC_SEND_IOCMD,
SEC_RPMB_LOCK,
SEC_RPMB_UNLOCK,
SEC_RPMB_ABNORMAL,
};
#define RPMB_EMMC_CID_SIZE 32
struct rpmb_devinfo {
uint8_t cid[RPMB_EMMC_CID_SIZE]; /* eMMC card ID */
uint8_t rpmb_size_mult; /* EXT CSD-slice 168 "RPMB Size" */
uint8_t rel_wr_sec_cnt; /* EXT CSD-slice 222 "Reliable Write Sector Count" */
uint8_t tmp[2];
uint32_t blk_size; /* RPMB blocksize */
uint32_t max_blk_idx; /* The highest block index supported by current device */
uint32_t access_start_blk_idx; /* The start block index SecureOS can access */
uint32_t access_total_blk; /* The total blocks SecureOS can access */
uint32_t tmp2;
uint32_t mdt; /* 1: EMMC 2: UFS */
/* the device's support bit map, for example, if it support 1,2,32, then the value is 0x80000003 */
uint32_t support_bit_map;
uint32_t version;
uint32_t tmp3;
};
struct rpmb_ioc {
struct storage_blk_ioc_rpmb_data ioc_rpmb; /* sizeof() = 72 */
uint32_t buf_offset[STORAGE_IOC_MAX_RPMB_CMD];
uint32_t tmp;
};
#define RPMB_CTRL_MAGIC 0x5A5A5A5A
struct rpmb_ctrl_t {
uint32_t magic;
uint32_t cmd_sn;
uint8_t lock_flag;
uint8_t tmp[3];
enum rpmb_op_type op_type;
union __args {
struct rpmb_devinfo get_devinfo;
struct rpmb_ioc send_ioccmd;
} args;
enum rpmb_cmd cmd;
uint32_t reserved;
uint32_t buf_len;
int32_t ret;
uint32_t reserved2;
uint32_t buf_start[0];
}; /* sizeof() = 8 * 16 = 128 */
static struct rpmb_ctrl_t *m_rpmb_ctrl = NULL;
/*
* the data_ptr from SecureOS is physical address,
* so, we MUST update to the virtual address,
* otherwise, segment default
*/
static void update_dataptr(struct rpmb_ctrl_t *trans_ctrl)
{
uint32_t i;
uint32_t offset = 0;
uint8_t *dst = NULL;
if (trans_ctrl == NULL)
return;
for (i = 0; i < STORAGE_IOC_MAX_RPMB_CMD; i++) {
offset = trans_ctrl->args.send_ioccmd.buf_offset[i];
if (offset > trans_ctrl->buf_len)
continue;
if (trans_ctrl->args.send_ioccmd.ioc_rpmb.data[i].buf != NULL) {
dst = (uint8_t *)trans_ctrl->buf_start + offset;
/* update the data_prt */
trans_ctrl->args.send_ioccmd.ioc_rpmb.data[i].buf = dst;
}
}
}
struct rpmb_agent_lock_info {
unsigned int dev_id;
bool lock_need_free;
};
static struct rpmb_agent_lock_info lock_info = { 0 };
static u64 g_tee_rpmb_lock_done = 0;
static u64 g_tee_rpmb_lock_release = 0;
#define RPMB_TIMEOUT_TIME_TEE 800000000
static void process_rpmb_lock(const struct tee_agent_kernel_ops *agent_instance)
{
struct smc_event_data *event_data = NULL;
rpmb_driver_counter_lock();
g_tee_rpmb_lock_done = dfx_getcurtime();
tlogd("obtain rpmb device lock\n");
event_data = find_event_control(agent_instance->agent_id);
if (event_data != NULL) {
lock_info.dev_id = event_data->cmd.dev_file_id;
lock_info.lock_need_free = true;
tlogd("rpmb counter lock context: dev_id=%d\n",
lock_info.dev_id);
}
put_agent_event(event_data);
}
static void process_rpmb_unlock(int operation)
{
u64 temp_cost_time;
/* clear the lock info */
lock_info.dev_id = 0;
lock_info.lock_need_free = false;
rpmb_driver_counter_unlock();
g_tee_rpmb_lock_release = dfx_getcurtime();
temp_cost_time = g_tee_rpmb_lock_release - g_tee_rpmb_lock_done;
if (temp_cost_time > RPMB_TIMEOUT_TIME_TEE) {
tloge("rpmb tee cost time is more than 800ms, start[%llu], unlock[%llu], cost[%llu], operation[%d]\n",
g_tee_rpmb_lock_done, g_tee_rpmb_lock_release,
temp_cost_time, operation);
tee_report_rpmb();
}
tlogd("free rpmb device lock\n");
}
#define GET_RPMB_LOCK_MASK 0x01
#define FREE_RPMB_LOCK_MASK 0x02
static void send_ioccmd(const struct tee_agent_kernel_ops *agent_instance)
{
uint8_t lock_flag;
int32_t ret;
if (agent_instance == NULL || m_rpmb_ctrl == NULL) {
tloge("bad parameters\n");
return;
}
lock_flag = m_rpmb_ctrl->lock_flag;
if (lock_flag & GET_RPMB_LOCK_MASK)
process_rpmb_lock(agent_instance);
ret = rpmb_ioctl_cmd(RPMB_FUNC_ID_SECURE_OS, m_rpmb_ctrl->op_type,
&m_rpmb_ctrl->args.send_ioccmd.ioc_rpmb);
if (ret)
tloge("rpmb ioctl failed: %d\n", ret);
if (lock_flag & FREE_RPMB_LOCK_MASK)
process_rpmb_unlock(m_rpmb_ctrl->op_type);
m_rpmb_ctrl->ret = ret;
}
static int rpmb_check_data(struct rpmb_ctrl_t *trans_ctrl)
{
if (trans_ctrl == NULL)
return 0;
if (trans_ctrl->magic != RPMB_CTRL_MAGIC) {
tloge("rpmb check magic error, now is 0x%x\n",
trans_ctrl->magic);
return -1;
}
return 0;
}
static void rpmb_handle_cmd(struct tee_agent_kernel_ops *agent_instance)
{
switch (m_rpmb_ctrl->cmd) {
case SEC_SEND_IOCMD:
tlogd("rpmb agent cmd is send ioc\n");
send_ioccmd(agent_instance);
break;
case SEC_RPMB_LOCK:
tlogd("rpmb agent cmd is lock\n");
process_rpmb_lock(agent_instance);
m_rpmb_ctrl->ret = 0;
break;
case SEC_RPMB_UNLOCK:
tlogd("rpmb agent cmd is unlock\n");
process_rpmb_unlock(SEC_RPMB_UNLOCK);
m_rpmb_ctrl->ret = 0;
break;
default:
tloge("rpmb agent cmd not supported 0x%x\n", m_rpmb_ctrl->cmd);
break;
}
}
static int rpmb_agent_work(struct tee_agent_kernel_ops *agent_instance)
{
struct rpmb_ctrl_t *trans_ctrl = NULL;
errno_t rc = EOK;
uint32_t copy_len;
if (agent_instance == NULL || agent_instance->agent_buff == NULL) {
tloge("agent buff invalid\n");
return -1;
}
trans_ctrl = (struct rpmb_ctrl_t *)agent_instance->agent_buff;
if (rpmb_check_data(trans_ctrl) != 0) {
trans_ctrl->ret = TEEC_ERROR_BAD_FORMAT;
return -1;
}
if (m_rpmb_ctrl == NULL) {
m_rpmb_ctrl = kzalloc(agent_instance->agent_buff_size,
GFP_KERNEL);
if (m_rpmb_ctrl == NULL) {
tloge("memory alloc failed\n");
trans_ctrl->ret = TEEC_ERROR_OUT_OF_MEMORY;
return -1;
}
}
rc = memcpy_s((void *)m_rpmb_ctrl,
agent_instance->agent_buff_size, (void *)trans_ctrl,
sizeof(*m_rpmb_ctrl) + trans_ctrl->buf_len);
if (rc != EOK) {
tloge("memcpy_s failed: 0x%x\n", rc);
trans_ctrl->ret = TEEC_ERROR_SECURITY;
goto clean;
}
update_dataptr(m_rpmb_ctrl);
rpmb_handle_cmd(agent_instance);
copy_len = agent_instance->agent_buff_size -
offsetof(struct rpmb_ctrl_t, buf_start);
rc = memcpy_s((void *)trans_ctrl->buf_start, copy_len,
(void *)m_rpmb_ctrl->buf_start, copy_len);
if (rc != EOK) {
tloge("memcpy_s 2 failed: 0x%x\n", rc);
trans_ctrl->ret = TEEC_ERROR_SECURITY;
goto clean;
}
trans_ctrl->ret = m_rpmb_ctrl->ret;
return 0;
clean:
trans_ctrl->ret = TEEC_ERROR_SECURITY;
kfree(m_rpmb_ctrl);
m_rpmb_ctrl = NULL;
return -1;
}
static int rpmb_agent_exit(struct tee_agent_kernel_ops *agent_instance)
{
tloge("rpmb agent is exit is being invoked\n");
if (m_rpmb_ctrl != NULL) {
kfree(m_rpmb_ctrl);
m_rpmb_ctrl = NULL;
}
return 0;
}
static int rpmb_agent_crash_work(
struct tee_agent_kernel_ops *agent_instance,
struct tc_ns_client_context *context, unsigned int dev_file_id)
{
(void)agent_instance;
(void)context;
tlogd("check free lock or not, dev_id=%d\n", dev_file_id);
if (lock_info.lock_need_free && (lock_info.dev_id == dev_file_id)) {
tloge("CA crash, need to free lock\n");
process_rpmb_unlock(SEC_RPMB_ABNORMAL);
}
return 0;
}
static struct tee_agent_kernel_ops rpmb_agent_ops = {
.agent_name = "rpmb",
.agent_id = TEE_RPMB_AGENT_ID,
.tee_agent_init = NULL,
.tee_agent_work = rpmb_agent_work,
.tee_agent_exit = rpmb_agent_exit,
.tee_agent_crash_work = rpmb_agent_crash_work,
.agent_buff_size = 8 * PAGE_SIZE,
.list = LIST_HEAD_INIT(rpmb_agent_ops.list)
};
int rpmb_agent_register(void)
{
tee_agent_kernel_register(&rpmb_agent_ops);
return 0;
}
EXPORT_SYMBOL(rpmb_agent_register);
+29
View File
@@ -0,0 +1,29 @@
/*
* agent_rpmb.h
*
* rpmb agent manager function, such as register
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 AGENT_RPMB_H
#define AGENT_RPMB_H
#ifdef CONFIG_RPMB_AGENT
int rpmb_agent_register(void);
#else
static inline int rpmb_agent_register(void)
{
return 0;
}
#endif
#endif
+26
View File
@@ -0,0 +1,26 @@
/*
* rpmb_driver.c
*
* rpmb driver function, such as ioctl
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "rpmb_driver.h"
int rpmb_ioctl_cmd(enum func_id id, enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data)
{
if (storage_data == NULL)
return -1;
return vendor_rpmb_ioctl_cmd(id, operation, storage_data);
}
+65
View File
@@ -0,0 +1,65 @@
/*
* rpmb_driver.h
*
* rpmb driver function, such as ioctl
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 __RPMB_DRIVER_H
#define __RPMB_DRIVER_H
#include <linux/rpmb/rpmb.h>
#ifdef CONFIG_VENDOR_RPMB
int vendor_rpmb_ioctl_cmd(enum func_id id, enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data);
static inline void tee_report_rpmb(void)
{
rpmb_dump_io_latency();
}
#else
static inline int vendor_rpmb_ioctl_cmd(enum func_id id, enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data)
{
return 0xFF08;
}
static inline void tee_report_rpmb(void)
{
}
#endif
#if defined(CONFIG_VENDOR_RPMB) && !defined(CONFIG_RPMB_REQ_LOCK_DISABLE)
static inline void rpmb_driver_counter_lock(void)
{
mutex_lock(&rpmb_counter_lock);
}
static inline void rpmb_driver_counter_unlock(void)
{
mutex_unlock(&rpmb_counter_lock);
}
#else
static inline void rpmb_driver_counter_lock(void)
{
}
static inline void rpmb_driver_counter_unlock(void)
{
}
#endif
int rpmb_ioctl_cmd(enum func_id id, enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data);
#endif
+76
View File
@@ -0,0 +1,76 @@
/*
* rpmb.h
*
* rpmb base data and structs defination
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 __RPMB_H__
#define __RPMB_H__
#include <linux/kconfig.h>
#include <uapi/linux/bsg.h>
#define MAX_CDB_CMD_LENGTH 16
#define UFS_IOC_MAX_RPMB_CMD 3
#define STORAGE_IOC_MAX_RPMB_CMD 3
#define MAX_IOC_RPMB_BYTES (4 * 1024)
enum rpmb_op_type {
RPMB_OP_RD = 0,
RPMB_OP_WR_DATA = 1,
RPMB_OP_WR_CNT = 2
};
enum func_id {
RPMB_FUNC_ID_RESERVED,
RPMB_FUNC_ID_SE,
RPMB_FUNC_ID_SECURE_OS,
RPMB_FUNC_ID_MAX,
};
enum rpmb_version {
RPMB_VER_INVALID = 0,
RPMB_VER_UFS_21 = 21,
RPMB_VER_UFS_30 = 30,
RPMB_VER_MAX = 999
};
struct storage_blk_ioc_data {
unsigned char *buf;
u64 buf_bytes;
u32 blocks;
};
struct ufs_blk_ioc_data {
struct sg_io_v4 siv;
unsigned char *buf;
u64 buf_bytes;
};
struct storage_blk_ioc_rpmb_data {
struct storage_blk_ioc_data data[STORAGE_IOC_MAX_RPMB_CMD];
};
struct ufs_blk_ioc_rpmb_data {
struct ufs_blk_ioc_data data[UFS_IOC_MAX_RPMB_CMD];
u8 sdb_command[UFS_IOC_MAX_RPMB_CMD][MAX_CDB_CMD_LENGTH];
};
extern struct mutex rpmb_counter_lock;
extern int vendor_rpmb_ioctl_cmd(
enum func_id id,
enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data);
#endif /* __RPMB_H__ */
+46
View File
@@ -0,0 +1,46 @@
/*
* rpmb_driver.c
*
* rpmb driver function, such as ioctl
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "rpmb_driver.h"
#include <linux/kallsyms.h>
#include "tc_ns_log.h"
typedef int *(rpmb_ioctl_func)(enum func_id id, enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data);
int rpmb_ioctl_cmd(enum func_id id, enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data)
{
static rpmb_ioctl_func *rpmb_ioctl = NULL;
if (storage_data == NULL)
return NULL;
if (rpmb_ioctl == NULL) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
rpmb_ioctl =
(rpmb_ioctl_func *)(uintptr_t)__symbol_get("vendor_rpmb_ioctl_cmd");
#else
rpmb_ioctl =
(rpmb_ioctl_func *)(uintptr_t)kallsyms_lookup_name("vendor_rpmb_ioctl_cmd");
#endif
if (rpmb_ioctl == NULL) {
tloge("fail to find symbol vendor_rpmb_ioctl_cmd\n");
return NULL;
}
}
return rpmb_ioctl(id, operation, storage_data);
}
+34
View File
@@ -0,0 +1,34 @@
/*
* rpmb_driver.h
*
* rpmb driver function, such as ioctl
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 __RPMB_DRIVER_H
#define __RPMB_DRIVER_H
#include "rpmb.h"
static inline void rpmb_driver_counter_lock(void)
{
}
static inline void rpmb_driver_counter_unlock(void)
{
}
int rpmb_ioctl_cmd(enum func_id id, enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data);
#endif
+511
View File
@@ -0,0 +1,511 @@
/*
* rpmb_driver.c
*
* rpmb driver function, such as ioctl
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "rpmb_driver.h"
#include <securec.h>
#include <linux/mmc/card.h> /* for struct mmc_card */
#include <linux/rpmb.h>
#include <linux/mmc/sd.h>
#ifdef CONFIG_MTK_UFS_SUPPORT
#include "ufs-mtk.h"
#endif
#include <mt-plat/mtk_boot.h>
#include "core.h"
#include "card.h"
#include "mmc_ops.h"
#include "mtk_sd.h"
#include "tc_ns_log.h"
#include "queue.h"
#define IOC_CMD_0 0
#define IOC_CMD_1 1
#define IOC_CMD_2 2
#define STORAGE_IOC_MAX_RPMB_CMD 3
#define RPMB_EMMC_CID_SIZE 32
#define RPMB_CTRL_MAGIC 0x5A5A5A5A
#define RPMB_REQ 1 /* RPMB request mark */
#define RPMB_RESP (1 << 1) /* RPMB response mark*/
#define RPMB_PROGRAM_KEY 0x1 /* Program RPMB Authentication Key */
#define RPMB_GET_WRITE_COUNTER 0x2 /* Read RPMB write counter */
#define RPMB_WRITE_DATA 0x3 /* Write data to RPMB partition */
#define RPMB_READ_DATA 0x4 /* Read data from RPMB partition */
#define RPMB_RESULT_READ 0x5 /* Read result request (Internal) */
struct emmc_rpmb_blk_data {
spinlock_t lock;
struct device *parent;
struct gendisk *disk;
struct mmc_queue queue;
struct list_head part;
uint32_t flags;
uint32_t usage;
uint32_t read_only;
uint32_t part_type;
uint32_t reset_done;
uint32_t part_curr; // keep curr partition
struct device_attribute force_ro;
struct device_attribute power_ro_lock;
int32_t area_type;
};
static int32_t emmc_rpmb_switch(struct mmc_card *card,
struct emmc_rpmb_blk_data *md)
{
int32_t ret;
struct emmc_rpmb_blk_data *main_md = NULL;
if (card == NULL)
return -1;
main_md = dev_get_drvdata(&card->dev);
if (main_md == NULL)
return -1;
if (main_md->part_curr == md->part_type)
return 0;
#if defined(CONFIG_MTK_EMMC_CQ_SUPPORT) || defined(CONFIG_MTK_EMMC_HW_CQ)
if (mmc_card_cmdq(card)) {
ret = mmc_cmdq_disable(card);
if (ret) {
tloge("CQ disabled failed!!! ret: 0x%x\n", ret);
return ret;
}
}
#endif
if (mmc_card_mmc(card) != 0) {
uint8_t cfg = card->ext_csd.part_config;
cfg &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
cfg |= md->part_type;
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PART_CONFIG,
cfg, card->ext_csd.part_time);
if (ret)
return ret;
card->ext_csd.part_config = cfg;
}
#if defined(CONFIG_MTK_EMMC_CQ_SUPPORT) || defined(CONFIG_MTK_EMMC_HW_CQ)
/* enable cmdq at user partition */
if (!mmc_card_cmdq(card) && (md->part_type <= 0)) {
ret = mmc_cmdq_enable(card);
if (ret)
tloge("%s enable CMDQ error %d, so just work without\n",
mmc_hostname(card->host), ret);
}
#endif
#if defined(CONFIG_MTK_EMMC_HW_CQ)
card->part_curr = md->part_type;
#endif
main_md->part_curr = md->part_type;
return 0;
}
#define RPMB_BLOCK_SIZE 512
static void set_sbc(__u16 blks, __u16 type, u8 req_type,
struct mmc_command *sbc)
{
sbc->opcode = MMC_SET_BLOCK_COUNT;
sbc->arg = blks;
if ((req_type == RPMB_REQ && type == RPMB_WRITE_DATA) ||
type == RPMB_PROGRAM_KEY)
sbc->arg |= 1 << 31;
sbc->flags = MMC_RSP_R1 | MMC_CMD_AC;
}
static void rpmb_send_req_cmd(struct mmc_card *card,
struct storage_blk_ioc_rpmb_data *storage_data,
__u16 blks, __u16 type, struct mmc_request *request)
{
request->cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
request->data->flags |= MMC_DATA_WRITE;
if (type == RPMB_RESULT_READ) {
/* this is the step2 for write data cmd and write key cmd */
sg_copy_from_buffer(request->data->sg, 1,
storage_data->data[IOC_CMD_1].buf, RPMB_BLOCK_SIZE * blks);
} else {
/* this is step 1 for read data and read counter */
sg_copy_from_buffer(request->data->sg, 1,
storage_data->data[IOC_CMD_0].buf, RPMB_BLOCK_SIZE * blks);
}
mmc_set_data_timeout(request->data, card);
mmc_wait_for_req(card->host, request);
}
static void resp_get_sg(struct storage_blk_ioc_rpmb_data *storage_data,
__u16 blks, __u16 type, struct scatterlist *sg)
{
bool read_type = (type == RPMB_READ_DATA) ||
(type == RPMB_GET_WRITE_COUNTER);
bool write_type = (type == RPMB_WRITE_DATA) ||
(type == RPMB_PROGRAM_KEY);
if (read_type) {
if (storage_data->data[IOC_CMD_1].buf != NULL)
sg_copy_to_buffer(sg, 1, storage_data->data[IOC_CMD_1].buf,
RPMB_BLOCK_SIZE * blks);
else
tloge("invalid data1buff, is null\n");
} else if (write_type) {
if (storage_data->data[IOC_CMD_2].buf != NULL)
sg_copy_to_buffer(sg, 1, storage_data->data[IOC_CMD_2].buf,
RPMB_BLOCK_SIZE * blks);
else
tloge("invalid data1buff, is null\n");
} else {
/* do nothing */
tloge("invalid reqtype %d\n", type);
}
}
static void rpmb_send_resp_cmd(struct mmc_card *card,
struct storage_blk_ioc_rpmb_data *storage_data,
__u16 blks, __u16 type, struct mmc_request *request)
{
request->cmd->opcode = MMC_READ_MULTIPLE_BLOCK;
request->data->flags |= MMC_DATA_READ;
mmc_set_data_timeout(request->data, card);
mmc_wait_for_req(card->host, request);
resp_get_sg(storage_data, blks, type, request->data->sg);
}
static int emmc_rpmb_send_command(struct mmc_card *card,
struct storage_blk_ioc_rpmb_data *storage_data,
__u16 blks, __u16 type, u8 req_type)
{
struct mmc_command cmd = {0};
struct mmc_command sbc = {0};
struct mmc_data data = {0};
struct mmc_request request = {NULL};
struct scatterlist sg;
u8 *transfer_buf = NULL;
if (blks == 0) {
tloge("Invalid blks: 0\n");
return -EINVAL;
}
set_sbc(blks, type, req_type, &sbc);
request.sbc = &sbc;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
request.cmd = &cmd;
data.blksz = RPMB_BLOCK_SIZE;
data.blocks = blks;
data.sg = &sg;
data.sg_len = 1;
request.data = &data;
request.stop = NULL;
transfer_buf = kzalloc(RPMB_BLOCK_SIZE * blks, GFP_KERNEL);
if (transfer_buf == NULL)
return -ENOMEM;
sg_init_one(&sg, transfer_buf, RPMB_BLOCK_SIZE * blks);
if (req_type == RPMB_REQ)
rpmb_send_req_cmd(card, storage_data, blks, type, &request);
else
rpmb_send_resp_cmd(card, storage_data, blks, type, &request);
kfree(transfer_buf);
if (cmd.error)
return cmd.error;
else if (data.error)
return data.error;
else
return 0;
}
static int emmc_rpmb_cmd_proc(struct mmc_card *card, unsigned short type,
struct storage_blk_ioc_rpmb_data *storage_data)
{
int err = 0;
/* STEP 1: send request to RPMB partition */
if (type == RPMB_WRITE_DATA) {
err = emmc_rpmb_send_command(card, storage_data,
storage_data->data[IOC_CMD_0].blocks, type, RPMB_REQ);
} else {
/* assemble the frame */
storage_data->data[IOC_CMD_0].blocks = storage_data->data[IOC_CMD_1].blocks;
err = emmc_rpmb_send_command(card, storage_data,
1, type, RPMB_REQ);
}
if (err != 0) {
tloge("step 1, request failed err-%d\n", err);
goto out;
}
/* STEP 2: check write result. Only for WRITE_DATA or Program key */
if (type == RPMB_WRITE_DATA || type == RPMB_PROGRAM_KEY) {
err = emmc_rpmb_send_command(card, storage_data,
1, RPMB_RESULT_READ, RPMB_REQ);
if (err != 0) {
tloge("step 2, request result failed err-%d\n", err);
goto out;
}
}
/* STEP 3: get response from RPMB partition */
if (type == RPMB_READ_DATA)
err = emmc_rpmb_send_command(card, storage_data,
storage_data->data[IOC_CMD_0].blocks, type, RPMB_RESP);
else
err = emmc_rpmb_send_command(card, storage_data, 1,
type, RPMB_RESP);
if (err != 0)
tloge("step 3, response failed err-%d\n", err);
out:
return err;
}
static int rpmb_operation_emmc(enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data)
{
struct emmc_rpmb_blk_data *part_md = NULL;
int ret;
struct emmc_rpmb_blk_data *md = NULL;
struct mmc_card *card = get_card_from_mtk_msdc_host();
if (card == NULL)
return -1;
md = dev_get_drvdata(&card->dev);
if (md == NULL)
return -1;
list_for_each_entry(part_md, &md->part, part) {
if (part_md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
break;
}
if (part_md->part_type != EXT_CSD_PART_CONFIG_ACC_RPMB)
return -1;
mmc_get_card(card);
ret = emmc_rpmb_switch(card, part_md);
if (ret != 0) {
tloge("emmc switch to rpmb failed ret-%x\n", ret);
goto error;
}
switch (operation) {
case RPMB_OP_RD:
ret = emmc_rpmb_cmd_proc(card, RPMB_READ_DATA, storage_data);
break;
case RPMB_OP_WR_CNT:
ret = emmc_rpmb_cmd_proc(card, RPMB_GET_WRITE_COUNTER,
storage_data);
break;
case RPMB_OP_WR_DATA:
ret = emmc_rpmb_cmd_proc(card, RPMB_WRITE_DATA, storage_data);
break;
default:
tloge("receive an unknown operation %d\n", operation);
goto error;
}
if (ret != 0)
tloge("emmc rpmb cmd proc failed ret-%x\n", ret);
error:
ret = emmc_rpmb_switch(card, dev_get_drvdata(&card->dev));
if (ret != 0)
tloge("emmc switch to main failed ret-%x\n", ret);
mmc_put_card(card);
return ret;
}
static int rpmb_req_read_data_ufs(
struct storage_blk_ioc_rpmb_data *storage_data)
{
struct rpmb_data data;
struct rpmb_dev *rawdev_ufs_rpmb = NULL;
int ret;
uint16_t blk_cnt;
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
blk_cnt = storage_data->data[1].blocks;
tlogd("rpmb read data ufs, blk_cnt: %u\n", blk_cnt);
data.req_type = RPMB_READ_DATA;
data.icmd.nframes = 1;
data.icmd.frames = (struct rpmb_frame *)storage_data->data[IOC_CMD_0].buf;
/*
* We need to fill-in block_count by ourselves for UFS case.
*/
data.icmd.frames->block_count = cpu_to_be16(blk_cnt);
data.ocmd.nframes = blk_cnt;
data.ocmd.frames = (struct rpmb_frame *)storage_data->data[IOC_CMD_1].buf;
ret = rpmb_cmd_req(rawdev_ufs_rpmb, &data);
if (ret != 0)
tloge("rpmb req ufs error, ret:0x%x\n", ret);
tlogd("result 0x%x\n", cpu_to_be16(data.ocmd.frames->result));
return ret;
}
static int rpmb_req_write_data_ufs(
struct storage_blk_ioc_rpmb_data *storage_data)
{
struct rpmb_data data;
struct rpmb_dev *rawdev_ufs_rpmb = NULL;
int ret;
uint16_t blk_cnt;
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
blk_cnt = storage_data->data[IOC_CMD_0].blocks;
tlogd("blk_cnt: %d\n", blk_cnt);
/*
* Alloc output frame to avoid overwriting input frame
* buffer provided by TEE
*/
data.ocmd.frames = kzalloc(sizeof(struct rpmb_frame), 0);
if (data.ocmd.frames == NULL)
return RPMB_ALLOC_ERROR;
data.ocmd.nframes = 1;
data.req_type = RPMB_WRITE_DATA;
data.icmd.nframes = blk_cnt;
data.icmd.frames = (struct rpmb_frame *)storage_data->data[IOC_CMD_0].buf;
ret = rpmb_cmd_req(rawdev_ufs_rpmb, &data);
if (ret != 0)
tloge("rpmb_req write_data_ufs error, ret:0x%x\n", ret);
/*
* Microtrust TEE will check write counter in the first frame,
* thus we copy response frame to the first frame.
*/
if (storage_data->data[IOC_CMD_2].buf == NULL) {
ret = -1;
goto free;
}
ret = memcpy_s(storage_data->data[IOC_CMD_2].buf,
storage_data->data[IOC_CMD_2].buf_bytes,
data.ocmd.frames, sizeof(*(data.ocmd.frames)));
if (ret != EOK)
tloge("frames copy fail, ret:0x%x\n", ret);
tlogd("result 0x%x\n", cpu_to_be16(data.ocmd.frames->result));
free:
kfree(data.ocmd.frames);
return ret;
}
static int rpmb_req_get_wc_ufs(u8 *key, u32 *wc,
struct storage_blk_ioc_rpmb_data *storage_data)
{
struct rpmb_data data;
struct rpmb_dev *rawdev_ufs_rpmb = NULL;
int ret;
tlogd("rpmb_req_get_wc_ufs start!!!\n");
rawdev_ufs_rpmb = ufs_mtk_rpmb_get_raw_dev();
/*
* Initial frame buffers
*/
data.icmd.frames = (struct rpmb_frame *)storage_data->data[IOC_CMD_0].buf;
data.ocmd.frames = (struct rpmb_frame *)storage_data->data[IOC_CMD_1].buf;
/*
* Prepare frame contents.
* Input frame (in view of device) only needs nonce
*/
data.req_type = RPMB_GET_WRITE_COUNTER;
data.icmd.nframes = 1;
/* Output frame (in view of device) */
data.ocmd.nframes = 1;
ret = rpmb_cmd_req(rawdev_ufs_rpmb, &data);
if (ret != 0)
tloge("rpmb_req_get_wc_ufs error!!! ret:0x%x\n", ret);
tlogd("end\n");
return ret;
}
#ifdef CONFIG_MTK_UFS_SUPPORT
static int rpmb_operation_ufs(enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data)
{
int ret = -1;
switch (operation) {
case RPMB_OP_RD:
ret = rpmb_req_read_data_ufs(storage_data);
break;
case RPMB_OP_WR_CNT:
ret = rpmb_req_get_wc_ufs(NULL, NULL, storage_data);
break;
case RPMB_OP_WR_DATA:
ret = rpmb_req_write_data_ufs(storage_data);
break;
default:
tloge("receive an unknown command id %d.\n", operation);
break;
}
return ret;
}
#endif
int rpmb_ioctl_cmd(enum func_id id, enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data)
{
int ret = 0;
int boot_type;
if (storage_data == NULL)
return -1;
boot_type = get_boot_type();
if (boot_type == BOOTDEV_SDMMC)
ret = rpmb_operation_emmc(operation, storage_data);
#ifdef CONFIG_MTK_UFS_SUPPORT
else if (boot_type == BOOTDEV_UFS)
ret = rpmb_operation_ufs(operation, storage_data);
#endif
return ret;
}
+34
View File
@@ -0,0 +1,34 @@
/*
* rpmb_driver.h
*
* rpmb driver function, such as ioctl
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 __RPMB_DRIVER_H
#define __RPMB_DRIVER_H
#include <linux/mmc/rpmb.h>
static inline void rpmb_driver_counter_lock(void)
{
}
static inline void rpmb_driver_counter_unlock(void)
{
}
int rpmb_ioctl_cmd(enum func_id id, enum rpmb_op_type operation,
struct storage_blk_ioc_rpmb_data *storage_data);
#endif
+28
View File
@@ -0,0 +1,28 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022 Huawei Device Co., Ltd.
#
set -e
OHOS_SOURCE_ROOT=$1
KERNEL_BUILD_ROOT=$2
PRODUCT_NAME=$3
KERNEL_VERSION=$4
TZDRIVER_SOURCE_ROOT=$OHOS_SOURCE_ROOT/kernel/linux/common_modules/tzdriver
function main()
{
pushd .
if [ ! -d "$KERNEL_BUILD_ROOT/drivers/tzdriver" ]; then
mkdir $KERNEL_BUILD_ROOT/drivers/tzdriver
fi
cd $KERNEL_BUILD_ROOT/drivers/tzdriver
ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/drivers/tzdriver/ $TZDRIVER_SOURCE_ROOT)/* ./
popd
}
main
+28
View File
@@ -0,0 +1,28 @@
# Auth Configuration
config CLIENT_AUTH
bool "Client Application Hash Auth"
default n
depends on TZDRIVER
help
TEEOS CA code hash auth
config ANDROID_HIDL
bool "Android Hidl Adapt"
default n
depends on CLIENT_AUTH
help
TEEOS hidl proc auth
config CADAEMON_AUTH
bool "Teec Daemon Path Hash Auth"
default n
depends on TZDRIVER
help
TEEOS TEECD path hash auth
config TZDRIVER_OHOS
bool "Is in OH"
default n
depends on TZDRIVER
help
OH Cadaemon uid
+30
View File
@@ -0,0 +1,30 @@
KERNEL_DIR :=$(srctree)
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/tlogger
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../third_party/bounds_checking_function/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../base/security/selinux/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../base/security/selinux
EXTRA_CFLAGS += -DSELINUX_CA_HIDL_LABEL=\"u:r:hal_libteec_default:s0\"
EXTRA_CFLAGS += -DSELINUX_TEECD_LABEL=\"u:r:tee:s0\"
ifneq ($(CONFIG_TZDRIVER_OHOS),y)
EXTRA_CFLAGS += -DCONFIG_SELINUX_AUTH_ENABLE
endif
ifeq ($(CONFIG_CADAEMON_AUTH),y)
EXTRA_CFLAGS += -DCADAEMON_PATH_UID_AUTH_CTX=\"/system/bin/sa_main:6668\"
EXTRA_CFLAGS += -DSELINUX_CADAEMON_LABEL=NULL
endif
ifeq ($(CONFIG_TZDRIVER_OHOS),y)
EXTRA_CFLAGS += -DTEECD_PATH_UID_AUTH_CTX=\"/vendor/bin/teecd:6668\"
else
EXTRA_CFLAGS += -DTEECD_PATH_UID_AUTH_CTX=\"/vendor/bin/teecd:0\"
endif
obj-$(CONFIG_CLIENT_AUTH) += client_hash_auth.o
ifeq ($(findstring y, $(CONFIG_TEECD_AUTH) $(CONFIG_CLIENT_AUTH)), y)
obj-y += auth_base_impl.o
endif
+426
View File
@@ -0,0 +1,426 @@
/*
* auth_base_impl.c
*
* function for base hash operation
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "auth_base_impl.h"
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/rwsem.h>
#include <linux/path.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/dcache.h>
#include <linux/mm_types.h>
#include <linux/highmem.h>
#include <linux/cred.h>
#include <linux/slab.h>
#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
#include <linux/sched/mm.h>
#endif
#if defined (CONFIG_SELINUX_AUTH_ENABLE) && defined (CONFIG_SECURITY_SELINUX)
#include <linux/security.h>
#endif
#include <securec.h>
#include "tc_ns_log.h"
#include "tc_ns_client.h"
#include "agent.h" /* for get_proc_dpath */
#include "ko_adapt.h"
/* for crypto */
struct crypto_shash *g_shash_handle;
bool g_shash_handle_state = false;
struct mutex g_shash_handle_lock;
void init_crypto_hash_lock(void)
{
mutex_init(&g_shash_handle_lock);
}
void mutex_crypto_hash_lock(void)
{
mutex_lock(&g_shash_handle_lock);
}
void mutex_crypto_hash_unlock(void)
{
mutex_unlock(&g_shash_handle_lock);
}
/* begin: prepare crypto context */
struct crypto_shash *get_shash_handle(void)
{
return g_shash_handle;
}
void free_shash_handle(void)
{
if (g_shash_handle) {
crypto_free_shash(g_shash_handle);
g_shash_handle_state = false;
g_shash_handle = NULL;
}
}
int tee_init_shash_handle(char *hash_type)
{
long rc;
if (!hash_type) {
tloge("tee init crypto: error input parameter\n");
return -EFAULT;
}
mutex_crypto_hash_lock();
if (g_shash_handle_state) {
mutex_crypto_hash_unlock();
return 0;
}
g_shash_handle = crypto_alloc_shash(hash_type, 0, 0);
if (IS_ERR_OR_NULL(g_shash_handle)) {
rc = PTR_ERR(g_shash_handle);
tloge("Can not allocate %s reason: %ld\n", hash_type, rc);
mutex_crypto_hash_unlock();
return rc;
}
g_shash_handle_state = true;
mutex_crypto_hash_unlock();
return 0;
}
/* end: prepare crypto context */
/* begin: Calculate the SHA256 file digest */
static int prepare_desc(struct sdesc **desc)
{
size_t size;
size_t shash_size;
shash_size = crypto_shash_descsize(g_shash_handle);
size = sizeof((*desc)->shash) + shash_size;
if (size < sizeof((*desc)->shash) || size < shash_size) {
tloge("size flow\n");
return -ENOMEM;
}
*desc = kzalloc(size, GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)(*desc))) {
tloge("alloc desc failed\n");
return -ENOMEM;
}
return EOK;
}
#define PINED_PAGE_NUMBER 1
static int get_proc_user_pages(struct mm_struct *mm, unsigned long start_code,
struct page **ptr_page, struct task_struct *cur_struct)
{
#if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE)
(void)cur_struct;
return get_user_pages_remote(mm, start_code,
(unsigned long)PINED_PAGE_NUMBER, FOLL_FORCE, ptr_page, NULL, NULL);
#elif (KERNEL_VERSION(4, 9, 0) <= LINUX_VERSION_CODE)
return get_user_pages_remote(cur_struct, mm, start_code,
(unsigned long)PINED_PAGE_NUMBER, FOLL_FORCE, ptr_page, NULL, NULL);
#elif (KERNEL_VERSION(4, 4, 197) == LINUX_VERSION_CODE)
return get_user_pages_locked(cur_struct, mm, start_code,
(unsigned long)PINED_PAGE_NUMBER, FOLL_FORCE, ptr_page, NULL);
#else
return get_user_pages_locked(cur_struct, mm, start_code,
(unsigned long)PINED_PAGE_NUMBER, 0, 1, ptr_page, NULL);
#endif
}
static int update_task_hash(struct mm_struct *mm,
struct task_struct *cur_struct, struct shash_desc *shash)
{
int rc = -1;
unsigned long in_size;
struct page *ptr_page = NULL;
void *ptr_base = NULL;
unsigned long start_code = mm->start_code;
unsigned long end_code = mm->end_code;
unsigned long code_size = end_code - start_code;
if (code_size == 0) {
tloge("bad code size\n");
return -EINVAL;
}
while (start_code < end_code) {
/* Get a handle of the page we want to read */
rc = get_proc_user_pages(mm, start_code, &ptr_page, cur_struct);
if (rc != PINED_PAGE_NUMBER) {
tloge("get user pages error[0x%x]\n", rc);
rc = -EFAULT;
break;
}
ptr_base = kmap_atomic(ptr_page);
if (!ptr_base) {
rc = -EFAULT;
put_page(ptr_page);
break;
}
in_size = (code_size > PAGE_SIZE) ? PAGE_SIZE : code_size;
rc = crypto_shash_update(shash, ptr_base, in_size);
if (rc) {
kunmap_atomic(ptr_base);
put_page(ptr_page);
break;
}
kunmap_atomic(ptr_base);
put_page(ptr_page);
start_code += in_size;
code_size = end_code - start_code;
}
return rc;
}
int calc_task_hash(unsigned char *digest, uint32_t dig_len,
struct task_struct *cur_struct, uint32_t pub_key_len)
{
struct mm_struct *mm = NULL;
struct sdesc *desc = NULL;
bool check_value = false;
int rc;
check_value = (!cur_struct || !digest ||
dig_len != SHA256_DIGEST_LENTH);
if (check_value) {
tloge("tee hash: input param is error\n");
return -EFAULT;
}
mm = get_task_mm(cur_struct);
if (!mm) {
if (memset_s(digest, dig_len, 0, MAX_SHA_256_SZ))
return -EFAULT;
tloge("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;
}
if (prepare_desc(&desc) != EOK) {
mmput(mm);
tloge("prepare desc failed\n");
return -ENOMEM;
}
desc->shash.tfm = g_shash_handle;
if (crypto_shash_init(&desc->shash)) {
tloge("shash init failed\n");
rc = -ENOMEM;
goto free_res;
}
down_read(&mm_sem_lock(mm));
if (update_task_hash(mm, cur_struct, &desc->shash)) {
up_read(&mm_sem_lock(mm));
rc = -ENOMEM;
goto free_res;
}
up_read(&mm_sem_lock(mm));
rc = crypto_shash_final(&desc->shash, digest);
free_res:
mmput(mm);
kfree(desc);
return rc;
}
/* end: Calculate the SHA256 file digest */
#if defined(CONFIG_SELINUX_AUTH_ENABLE) && defined (CONFIG_SECURITY_SELINUX)
static int check_proc_selinux_access(const char * s_ctx)
{
if (s_ctx == NULL) {
tloge("bad params\n");
return CHECK_ACCESS_FAIL;
}
int rc;
u32 sid;
u32 tid;
u32 s_ctx_len = strnlen(s_ctx, MAX_SCTX_LEN);
if (s_ctx_len == 0 || s_ctx_len >= MAX_SCTX_LEN) {
tloge("invalid selinux ctx\n");
return CHECK_ACCESS_FAIL;
}
security_task_getsecid(current, &sid);
rc = security_secctx_to_secid(s_ctx, s_ctx_len, &tid);
if (rc != 0) {
tloge("secctx to sid failed, rc %d", rc);
return CHECK_ACCESS_FAIL;
}
if (sid != tid) {
tloge("check selinux label failed\n");
return CHECK_ACCESS_FAIL;
}
return EOK;
}
#else
static int check_proc_selinux_access(const char * s_ctx)
{
(void)s_ctx;
return 0;
}
#endif
static int get_proc_uid(uid_t *proc_uid)
{
#ifdef CONFIG_LIBLINUX
if (current->cred == NULL) {
tloge("cred is NULL\n");
return CHECK_ACCESS_FAIL;
}
*proc_uid = current->cred->uid.val;
#else
const struct cred *cred = NULL;
get_task_struct(current);
cred = koadpt_get_task_cred(current);
if (cred == NULL) {
tloge("cred is NULL\n");
put_task_struct(current);
return CHECK_ACCESS_FAIL;
}
*proc_uid = cred->uid.val;
put_cred(cred);
put_task_struct(current);
#endif
return CHECK_ACCESS_SUCC;
}
static int check_proc_uid_path(const char *auth_ctx)
{
int ret = 0;
char str_path_uid[MAX_PATH_SIZE] = { 0 };
char *pro_dpath = NULL;
char *k_path = NULL;
u32 auth_ctx_len;
uid_t proc_uid;
if (auth_ctx == NULL) {
tloge("bad params\n");
return CHECK_ACCESS_FAIL;
}
auth_ctx_len = (u32)strnlen(auth_ctx, MAX_PATH_SIZE);
if (auth_ctx_len == 0 || auth_ctx_len >= MAX_PATH_SIZE) {
tloge("invalid uid path\n");
return CHECK_ACCESS_FAIL;
}
k_path = kmalloc(MAX_PATH_SIZE, GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)k_path)) {
tloge("path kmalloc fail\n");
return CHECK_ACCESS_FAIL;
}
pro_dpath = get_proc_dpath(k_path, MAX_PATH_SIZE);
if (IS_ERR_OR_NULL(pro_dpath)) {
kfree(k_path);
return CHECK_ACCESS_FAIL;
}
ret = get_proc_uid(&proc_uid);
if (ret != CHECK_ACCESS_SUCC) {
tloge("get proc uid failed\n");
goto clean;
}
if (snprintf_s(str_path_uid, MAX_PATH_SIZE, MAX_PATH_SIZE - 1, "%s:%u",
pro_dpath, (unsigned int)proc_uid) < 0) {
tloge("snprintf_s path uid failed, ret %d\n", ret);
ret = CHECK_ACCESS_FAIL;
goto clean;
}
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;
clean:
kfree(k_path);
return ret;
}
#ifdef CONFIG_CADAEMON_AUTH
int check_cadaemon_auth(void)
{
int ret = check_proc_uid_path(CADAEMON_PATH_UID_AUTH_CTX);
if (ret != 0) {
tloge("check cadaemon path failed, ret %d\n", ret);
return ret;
}
ret = check_proc_selinux_access(SELINUX_CADAEMON_LABEL);
if (ret != 0) {
tloge("check cadaemon selinux label failed!, ret %d\n", ret);
return -EACCES;
}
return 0;
}
#endif
int check_hidl_auth(void)
{
int ret = check_proc_uid_path(CA_HIDL_PATH_UID_AUTH_CTX);
if (ret != CHECK_ACCESS_SUCC)
return ret;
#if defined(CONFIG_SELINUX_AUTH_ENABLE) && defined (CONFIG_SECURITY_SELINUX)
ret = check_proc_selinux_access(SELINUX_CA_HIDL_LABEL);
if (ret != EOK) {
tloge("check hidl selinux label failed, ret %d\n", ret);
return CHECK_SECLABEL_FAIL;
}
#endif
return CHECK_ACCESS_SUCC;
}
#ifdef CONFIG_TEECD_AUTH
int check_teecd_auth(void)
{
int ret = check_proc_uid_path(TEECD_PATH_UID_AUTH_CTX);
if (ret != 0) {
tloge("check teecd path failed, ret %d\n", ret);
return ret;
}
#if defined(CONFIG_SELINUX_AUTH_ENABLE) && defined (CONFIG_SECURITY_SELINUX)
ret = check_proc_selinux_access(SELINUX_TEECD_LABEL);
if (ret != 0) {
tloge("check teecd selinux label failed!, ret %d\n", ret);
return -EACCES;
}
#endif
return CHECK_ACCESS_SUCC;
}
#endif
+102
View File
@@ -0,0 +1,102 @@
/*
* auth_base_impl.h
*
* function definition for base hash operation
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 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 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 <linux/version.h>
#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
#include <linux/sched/task.h>
#endif
#include <linux/err.h>
#include <crypto/hash.h>
#define CHECK_ACCESS_SUCC 0
#define CHECK_ACCESS_FAIL 0xffff
#define CHECK_PATH_HASH_FAIL 0xff01
#define CHECK_SECLABEL_FAIL 0xff02
#define CHECK_CODE_HASH_FAIL 0xff03
#define ENTER_BYPASS_CHANNEL 0xff04
#define BUF_MAX_SIZE 1024
#define MAX_PATH_SIZE 512
#define SHA256_DIGEST_LENTH 32
#define MAX_SCTX_LEN 128
struct sdesc {
struct shash_desc shash;
char ctx[];
};
int calc_path_hash(bool is_hidl_srvc, unsigned char *digest, unsigned int dig_len);
int calc_task_hash(unsigned char *digest, uint32_t dig_len,
struct task_struct *cur_struct, uint32_t pub_key_len);
int tee_init_shash_handle(char *hash_type);
void free_shash_handle(void);
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
static inline void free_shash_handle(void)
{
return;
}
static void init_crypto_hash_lock(void)
{
return;
}
static inline int check_teecd_auth(void)
{
return 0;
}
#endif /* CLIENT_AUTH || TEECD_AUTH */
#ifdef CONFIG_CADAEMON_AUTH
int check_cadaemon_auth(void);
#endif
#endif
+595
View File
@@ -0,0 +1,595 @@
/*
* client_hash_auth.c
*
* function for CA code hash auth
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "client_hash_auth.h"
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/rwsem.h>
#ifdef CONFIG_AUTH_SUPPORT_UNAME
#include <linux/fs.h>
#endif
#ifdef CONFIG_CLIENT_AUTH
#include <linux/mm.h>
#include <linux/dcache.h>
#include <linux/mm_types.h>
#include <linux/highmem.h>
#include <linux/cred.h>
#include <linux/slab.h>
#include <linux/sched/mm.h>
#endif
#ifdef CONFIG_AUTH_HASH
#include <crypto/hash.h>
#endif
#include <securec.h>
#include "tc_ns_log.h"
#include "auth_base_impl.h"
#ifdef CONFIG_AUTH_HASH
#define SHA256_DIGEST_LENGTH 32
#define FIXED_PKG_NAME_LENGTH 256
struct sdesc_hash {
struct shash_desc shash;
char ctx[];
};
#endif
#if defined (CONFIG_ANDROID_HIDL) || defined (CONFIG_MDC_HAL_AUTH)
static int check_proc_state(bool is_hidl, struct task_struct **hidl_struct,
const struct tc_ns_client_context *context)
{
bool check_value = false;
if (is_hidl) {
rcu_read_lock();
*hidl_struct = pid_task(find_vpid(context->calling_pid),
PIDTYPE_PID);
check_value = !*hidl_struct ||
(*hidl_struct)->state == TASK_DEAD;
if (check_value) {
tloge("task is dead\n");
rcu_read_unlock();
return -EFAULT;
}
get_task_struct(*hidl_struct);
rcu_read_unlock();
return EOK;
}
return EOK;
}
static int get_hidl_client_task(bool is_hidl_task, struct tc_ns_client_context *context,
struct task_struct **cur_struct)
{
int ret;
struct task_struct *hidl_struct = NULL;
ret = check_proc_state(is_hidl_task, &hidl_struct, context);
if (ret)
return ret;
if (hidl_struct)
*cur_struct = hidl_struct;
else
*cur_struct = current;
return EOK;
}
#endif
#ifdef CONFIG_CLIENT_AUTH
#define LIBTEEC_CODE_PAGE_SIZE 8
#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",
#ifndef CONFIG_CMS_CAHASH_AUTH
#ifndef CONFIG_CADAEMON_AUTH
"libteec.huawei.so",
#else
"libteec.so",
#endif
#endif
};
static int find_lib_code_area(struct mm_struct *mm,
struct vm_area_struct **lib_code_area, int so_index)
{
struct vm_area_struct *vma = NULL;
bool is_valid_vma = false;
bool is_so_exists = false;
bool param_check = (!mm || !mm->mmap ||
!lib_code_area || so_index >= KIND_OF_SO);
if (param_check) {
tloge("illegal input params\n");
return -EFAULT;
}
for (vma = mm->mmap; vma; vma = vma->vm_next) {
is_valid_vma = (vma->vm_file &&
vma->vm_file->f_path.dentry &&
vma->vm_file->f_path.dentry->d_name.name);
if (is_valid_vma) {
is_so_exists = !strcmp(g_libso[so_index],
vma->vm_file->f_path.dentry->d_name.name);
if (is_so_exists && (vma->vm_flags & VM_EXEC)) {
*lib_code_area = vma;
tlogd("so name is %s\n",
vma->vm_file->f_path.dentry->d_name.name);
return EOK;
}
}
}
return -EFAULT;
}
struct get_code_info {
unsigned long code_start;
unsigned long code_end;
unsigned long code_size;
};
static int update_so_hash(struct mm_struct *mm,
struct task_struct *cur_struct, struct shash_desc *shash, int so_index)
{
struct vm_area_struct *vma = NULL;
int rc = -EFAULT;
struct get_code_info code_info;
unsigned long in_size;
struct page *ptr_page = NULL;
void *ptr_base = NULL;
if (find_lib_code_area(mm, &vma, so_index)) {
tlogd("get lib code vma area failed\n");
return -EFAULT;
}
code_info.code_start = vma->vm_start;
code_info.code_end = vma->vm_end;
code_info.code_size = code_info.code_end - code_info.code_start;
while (code_info.code_start < code_info.code_end) {
// Get a handle of the page we want to read
#if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE)
rc = get_user_pages_remote(mm, code_info.code_start,
1, FOLL_FORCE, &ptr_page, NULL, NULL);
#else
rc = get_user_pages_remote(cur_struct, mm, code_info.code_start,
1, FOLL_FORCE, &ptr_page, NULL, NULL);
#endif
if (rc != 1) {
tloge("get user pages locked error[0x%x]\n", rc);
rc = -EFAULT;
break;
}
ptr_base = kmap_atomic(ptr_page);
if (!ptr_base) {
rc = -EFAULT;
put_page(ptr_page);
break;
}
in_size = (code_info.code_size > PAGE_SIZE) ? PAGE_SIZE : code_info.code_size;
rc = crypto_shash_update(shash, ptr_base, in_size);
if (rc) {
kunmap_atomic(ptr_base);
put_page(ptr_page);
break;
}
kunmap_atomic(ptr_base);
put_page(ptr_page);
code_info.code_start += in_size;
code_info.code_size = code_info.code_end - code_info.code_start;
}
return rc;
}
/* Calculate the SHA256 library digest */
static int calc_task_so_hash(unsigned char *digest, uint32_t dig_len,
struct task_struct *cur_struct, int so_index)
{
struct mm_struct *mm = NULL;
int rc;
size_t size;
size_t shash_size;
struct sdesc *desc = NULL;
if (!digest || dig_len != SHA256_DIGEST_LENTH) {
tloge("tee hash: digest is NULL\n");
return -EFAULT;
}
shash_size = crypto_shash_descsize(get_shash_handle());
size = sizeof(desc->shash) + shash_size;
if (size < sizeof(desc->shash) || size < shash_size) {
tloge("size overflow\n");
return -ENOMEM;
}
desc = kzalloc(size, GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)desc)) {
tloge("alloc desc failed\n");
return -ENOMEM;
}
desc->shash.tfm = get_shash_handle();
if (crypto_shash_init(&desc->shash)) {
kfree(desc);
return -EFAULT;
}
mm = get_task_mm(cur_struct);
if (!mm) {
tloge("so does not have mm struct\n");
if (memset_s(digest, MAX_SHA_256_SZ, 0, dig_len))
tloge("memset digest failed\n");
kfree(desc);
return -EFAULT;
}
down_read(&mm_sem_lock(mm));
rc = update_so_hash(mm, cur_struct, &desc->shash, so_index);
up_read(&mm_sem_lock(mm));
mmput(mm);
if (!rc)
rc = crypto_shash_final(&desc->shash, digest);
kfree(desc);
return rc;
}
static int proc_calc_hash(uint8_t kernel_api, struct tc_ns_session *session,
struct task_struct *cur_struct, uint32_t pub_key_len)
{
int rc, i;
int so_found = 0;
mutex_crypto_hash_lock();
if (kernel_api == TEE_REQ_FROM_USER_MODE) {
for (i = 0; so_found < NUM_OF_SO && i < KIND_OF_SO; i++) {
rc = calc_task_so_hash(session->auth_hash_buf + MAX_SHA_256_SZ * so_found,
(uint32_t)SHA256_DIGEST_LENTH, cur_struct, i);
if (!rc)
so_found++;
}
if (so_found != NUM_OF_SO)
tlogd("so library found: %d\n", so_found);
} else {
tlogd("request from kernel\n");
}
#ifdef CONFIG_ASAN_DEBUG
tloge("so auth disabled for ASAN debug\n");
uint32_t so_hash_len = MAX_SHA_256_SZ * NUM_OF_SO;
errno_t sret = memset_s(session->auth_hash_buf, so_hash_len, 0, so_hash_len);
if (sret) {
mutex_crypto_hash_unlock();
tloge("memset so hash failed\n");
return -EFAULT;
}
#endif
rc = calc_task_hash(session->auth_hash_buf + MAX_SHA_256_SZ * NUM_OF_SO,
(uint32_t)SHA256_DIGEST_LENTH, cur_struct, pub_key_len);
if (rc) {
mutex_crypto_hash_unlock();
tloge("tee calc ca hash failed\n");
return -EFAULT;
}
mutex_crypto_hash_unlock();
return EOK;
}
int calc_client_auth_hash(struct tc_ns_dev_file *dev_file,
struct tc_ns_client_context *context, struct tc_ns_session *session)
{
int ret;
struct task_struct *cur_struct = NULL;
bool check = false;
#if defined(CONFIG_ANDROID_HIDL) || defined(CONFIG_MDC_HAL_AUTH)
bool is_hidl_srvc = false;
#endif
check = (!dev_file || !context || !session);
if (check) {
tloge("bad params\n");
return -EFAULT;
}
if (tee_init_shash_handle("sha256")) {
tloge("init code hash error\n");
return -EFAULT;
}
#if defined(CONFIG_ANDROID_HIDL) || defined(CONFIG_MDC_HAL_AUTH)
if(!current->mm) {
tlogd("kernel thread need not check\n");
ret = ENTER_BYPASS_CHANNEL;
} else {
#ifdef CONFIG_CADAEMON_AUTH
/* for OH */
ret = check_cadaemon_auth();
#else
/* for HO and MDC/DC */
ret = check_hidl_auth();
#endif
}
if (ret != CHECK_ACCESS_SUCC) {
if (ret != ENTER_BYPASS_CHANNEL) {
tloge("hidl service may be exploited ret 0x%x\n", ret);
return -EACCES;
}
/* native\kernel ca task this branch */
} else {
/* android hidl\mdc secmgr(libteec\kms) task this branch */
is_hidl_srvc = true;
}
ret = get_hidl_client_task(is_hidl_srvc, context, &cur_struct);
if (ret)
return -EFAULT;
#else
cur_struct = current;
#endif
ret = proc_calc_hash(dev_file->kernel_api, session, cur_struct, dev_file->pub_key_len);
#if defined(CONFIG_ANDROID_HIDL) || defined(CONFIG_MDC_HAL_AUTH)
if (is_hidl_srvc)
put_task_struct(cur_struct);
#endif
return ret;
}
#endif
#ifdef CONFIG_AUTH_HASH
#define UID_LEN 16
static int construct_hashdata(struct tc_ns_dev_file *dev_file,
uint8_t *buf, uint32_t buf_len)
{
int ret;
ret = memcpy_s(buf, buf_len, dev_file->pkg_name, dev_file->pkg_name_len);
if (ret) {
tloge("memcpy_s failed\n");
goto error;
}
buf += dev_file->pkg_name_len;
buf_len -= dev_file->pkg_name_len;
ret = memcpy_s(buf, buf_len, dev_file->pub_key, dev_file->pub_key_len);
if (ret) {
tloge("memcpy_s failed\n");
goto error;
}
return 0;
error:
return -EFAULT;
}
static struct sdesc_hash *init_sdesc(struct crypto_shash *alg)
{
struct sdesc_hash *sdesc;
size_t size;
size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
sdesc = kmalloc(size, GFP_KERNEL);
if (sdesc == NULL)
return ERR_PTR(-ENOMEM);
sdesc->shash.tfm = alg;
return sdesc;
}
static int calc_hash(struct crypto_shash *alg,
const unsigned char *data, unsigned int datalen, unsigned char *digest)
{
struct sdesc_hash *sdesc;
int ret;
sdesc = init_sdesc(alg);
if (IS_ERR(sdesc)) {
pr_info("can't alloc sdesc\n");
return PTR_ERR(sdesc);
}
ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
kfree(sdesc);
return ret;
}
static int do_sha256(const unsigned char *data, uint32_t datalen,
unsigned char *out_digest, uint8_t digest_len)
{
int ret;
struct crypto_shash *alg;
const char *hash_alg_name = "sha256";
if (digest_len != SHA256_DIGEST_LENGTH) {
tloge("error digest_len\n");
return -1;
}
alg = crypto_alloc_shash(hash_alg_name, 0, 0);
if(IS_ERR_OR_NULL(alg)) {
tloge("can't alloc alg %s, PTR_ERR alg is %ld\n", hash_alg_name, PTR_ERR(alg));
return PTR_ERR(alg);
}
ret = calc_hash(alg, data, datalen, out_digest);
if (ret != 0) {
tloge("calc hash failed\n");
crypto_free_shash(alg);
alg = NULL;
return -1;
}
crypto_free_shash(alg);
alg = NULL;
return 0;
}
int set_login_information_hash(struct tc_ns_dev_file *hash_dev_file)
{
int ret = 0;
uint8_t *indata = NULL;
if (hash_dev_file == NULL) {
tloge("wrong caller info, cal hash stopped\n");
return -1;
}
mutex_lock(&hash_dev_file->cainfo_hash_setup_lock);
if (!(hash_dev_file->cainfo_hash_setup)) {
unsigned char digest[SHA256_DIGEST_LENGTH] = {0};
uint8_t digest_len = sizeof(digest);
uint32_t indata_len;
#ifdef CONFIG_AUTH_SUPPORT_UNAME
/* username using fixed length to cal hash */
if (hash_dev_file->pub_key_len >= FIXED_PKG_NAME_LENGTH) {
tloge("username is too loog\n");
ret = -1;
goto error;
}
indata_len = hash_dev_file->pkg_name_len + FIXED_PKG_NAME_LENGTH;
#else
indata_len = hash_dev_file->pkg_name_len + hash_dev_file->pub_key_len;
#endif
indata = kzalloc(indata_len, GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)indata)) {
tloge("indata kmalloc fail\n");
ret = -1;
goto error;
}
ret = construct_hashdata(hash_dev_file, indata, indata_len);
if (ret != 0) {
tloge("construct hashdata failed\n");
goto error;
}
ret = do_sha256((unsigned char *)indata, indata_len, digest, digest_len);
if (ret != 0) {
tloge("do sha256 failed\n");
goto error;
}
ret = memcpy_s(hash_dev_file->pkg_name, MAX_PACKAGE_NAME_LEN, digest, digest_len);
if (ret != 0) {
tloge("memcpy_s failed\n");
goto error;
}
hash_dev_file->pkg_name_len = SHA256_DIGEST_LENGTH;
hash_dev_file->cainfo_hash_setup = true;
}
error:
if (!ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)indata))
kfree(indata);
mutex_unlock(&hash_dev_file->cainfo_hash_setup_lock);
return ret;
}
#endif
#ifdef CONFIG_AUTH_SUPPORT_UNAME
#define PASSWD_FILE "/etc/passwd"
#define UID_POS 2U
#define DECIMAL 10
static int uid_compare(uint32_t uid, const char* uid_str, uint32_t uid_len)
{
uint32_t uid_num = 0;
for (uint32_t i = 0; i < uid_len; i++) {
bool is_number = uid_str[i] >= '0' && uid_str[i] <= '9';
if (!is_number) {
tloge("passwd info wrong format: uid missing\n");
return -1;
}
uid_num = DECIMAL * uid_num + (uid_str[i] - '0');
}
return (uid_num == uid) ? 0 : -1;
}
/* "username:[encrypted password]:uid:gid:[comments]:home directory:login shell" */
static uint32_t parse_uname(uint32_t uid, char *username, int buffer_len)
{
char *str = username;
char *token = strsep(&str, ":");
char *temp_name = token; // first tokon is username, need to check uid
int index = 0;
while(token != NULL && index < UID_POS) {
token = strsep(&str, ":");
index++;
}
if (token == NULL)
return -1;
if (uid_compare(uid, token, strlen(token)) != 0)
return -1;
if (strcpy_s(username, buffer_len, temp_name) != EOK)
return -1;
return strlen(temp_name);
}
static int read_line(char *buf, int buf_len, struct file *fp, loff_t *offset)
{
if (offset == NULL) {
tloge("offset is null while read file\n");
return -1;
}
ssize_t ret = kernel_read(fp, buf, buf_len, offset);
if (ret < 0)
return -1;
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++;
}
if (i < ret)
*offset -= (loff_t)(ret - i);
if (i < buf_len)
buf[i] = '\0';
return 0;
}
/* get username by uid,
* on linux, user info is stored in system file "/etc/passwd",
* each line represents a user, fields are separated by ':',
* formatted as such: "username:[encrypted password]:uid:gid:[comments]:home directory:login shell"
*/
int tc_ns_get_uname(uint32_t uid, char *username, int buffer_len, uint32_t *out_len)
{
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);
if (ret >= 0) {
*out_len = ret;
filp_close(f, NULL);
return 0;
}
}
filp_close(f, NULL);
return -1;
}
#endif
+53
View File
@@ -0,0 +1,53 @@
/*
* client_hash_auth.h
*
* function definition for CA code hash auth
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 CLIENT_HASH_CALC_H
#define CLIENT_HASH_CALC_H
#include "tc_ns_client.h"
#include "teek_ns_client.h"
#ifdef CONFIG_CLIENT_AUTH
#include "auth_base_impl.h"
int calc_client_auth_hash(struct tc_ns_dev_file *dev_file,
struct tc_ns_client_context *context, struct tc_ns_session *session);
#else
static inline int calc_client_auth_hash(struct tc_ns_dev_file *dev_file,
struct tc_ns_client_context *context, struct tc_ns_session *session)
{
(void)dev_file;
(void)context;
(void)session;
return 0;
}
#endif
#ifdef CONFIG_AUTH_SUPPORT_UNAME
#define MAX_NAME_LENGTH 256
int tc_ns_get_uname(uint32_t uid, char *username, int buffer_len, uint32_t *out_len);
#endif
#ifdef CONFIG_AUTH_HASH
int set_login_information_hash(struct tc_ns_dev_file *hash_dev_file);
#endif
#endif
+70
View File
@@ -0,0 +1,70 @@
# Framework Configuration
config CPU_AFF_NR
int "Default Cpu Affinity"
default 0
depends on TZDRIVER
help
Default Cpu Affinity
config DRM_ADAPT
bool "Drm Feature Adapt"
default n
depends on TZDRIVER
help
Drm Feature Adapt
config TA_AFFINITY
bool "TA affinity"
default n
depends on TZDRIVER
help
TA Cpu Affinity bind range, consistent with CONFIG_MAX_NUM_NODES in TEE
config TA_AFFINITY_CPU_NUMS
int "TA affinity max support cpus"
default 8
depends on TA_AFFINITY
help
consistent with CONFIG_MAX_NUM_NODES in TEE
config TEECD_AUTH
bool "Teec Daemon Path Hash Auth"
default n
depends on TZDRIVER
help
TEEOS TEECD path hash auth
config TEE_AUDIT
bool "Audit TA"
default n
depends on AUTH_ENHANCE
help
Audit TA in case of evil TA
config KERNEL_CLIENT
bool "Kernel Client Interface"
default n
depends on TZDRIVER
help
Kernel Client Interface
config BIG_SESSION
bool "open more sessions"
default n
depends on TZDRIVER
help
TEEOS open more sessions
config FFA_SUPPORT
bool "FFA Support Enable"
default n
depends on TZDRIVER
help
FFA Support Enable
config THIRDPARTY_COMPATIBLE
bool "Compatible with OPTEE"
default n
depends on TZDRIVER
help
Compatible with OPTEE
+32
View File
@@ -0,0 +1,32 @@
KERNEL_DIR := $(srctree)
ifneq ($(TARGET_BUILD_VARIANT), user)
ccflags-y += -DDEF_ENG
endif
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../third_party/bounds_checking_function/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/agent_rpmb/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/auth
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/tlogger
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/tui
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/ion
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/include
ifeq ($(CONFIG_TZDRIVER_INTERNAL), y)
include $(KERNEL_DIR)/drivers/tzdriver/tzdriver_internal/internal.mk
endif
obj-y += teek_client_api.o
obj-y += smc_smp.o tc_client_driver.o session_manager.o mailbox_mempool.o teek_app_load.o
obj-y += agent.o gp_ops.o mem.o cmdmonitor.o tzdebug.o tz_spi_notify.o tz_pm.o tee_compat_check.o
obj-y += reserved_mempool.o
obj-y += teek_client_ext.o
obj-y += shared_mem.o
ifdef CONFIG_FFA_SUPPORT
obj-y += ffa_abi.o
else
obj-y += smc_abi.o
endif
File diff suppressed because it is too large Load Diff
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: agent manager function definition, such as register and send cmd
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 AGENT_H
#define AGENT_H
#include <linux/fs.h>
#include "teek_ns_client.h"
#define MAX_PATH_SIZE 512
#define AGENT_FS_ID 0x46536673 /* FSfs */
#define AGENT_MISC_ID 0x4d495343 /* MISC */
#ifdef CONFIG_RPMB_AGENT
#define TEE_RPMB_AGENT_ID 0x4abe6198 /* RPMB */
#endif
#define AGENT_SOCKET_ID 0x69e85664 /* socket */
#define SECFILE_LOAD_AGENT_ID 0x4c4f4144 /* SECFILE-LOAD-AGENT */
#define TEE_SECE_AGENT_ID 0x53656345 /* npu agent id */
#define TEE_FACE_AGENT1_ID 0x46616365 /* face agent id */
#define TEE_FACE_AGENT2_ID 0x46616345 /* face agent id */
#define TEE_VLTMM_AGENT_ID 0x564c544d /* vltmm agent id */
#define SYSTEM_UID 1000
#define MS_TO_NS 1000000
enum agent_state_type {
AGENT_CRASHED = 0,
AGENT_REGISTERED,
AGENT_READY,
};
enum agent_status {
AGENT_ALIVE = 1,
AGENT_DEAD = 0,
};
/* for secure agent */
struct smc_event_data {
unsigned int agent_id;
atomic_t agent_ready;
wait_queue_head_t wait_event_wq;
int ret_flag; /* indicate whether agent is returned from TEE */
wait_queue_head_t send_response_wq;
struct list_head head;
struct tc_ns_smc_cmd cmd;
struct tc_ns_dev_file *owner;
void *agent_buff_kernel;
void *agent_buff_user; /* used for unmap */
unsigned int agent_buff_size;
atomic_t usage;
wait_queue_head_t ca_pending_wq;
/* indicate whether agent is allowed to return to TEE */
atomic_t ca_run;
};
struct tee_agent_kernel_ops {
const char *agent_name;
unsigned int agent_id;
int (*tee_agent_init)(struct tee_agent_kernel_ops *agent_instance);
int (*tee_agent_run)(struct tee_agent_kernel_ops *agent_instance);
int (*tee_agent_work)(struct tee_agent_kernel_ops *agent_instance);
int (*tee_agent_stop)(struct tee_agent_kernel_ops *agent_instance);
int (*tee_agent_exit)(struct tee_agent_kernel_ops *agent_instance);
int (*tee_agent_crash_work)(
struct tee_agent_kernel_ops *agent_instance,
struct tc_ns_client_context *context,
unsigned int dev_file_id);
struct task_struct *agent_thread;
void *agent_data;
void *agent_buff;
unsigned int agent_buff_size;
struct list_head list;
};
struct ca_info {
char path[MAX_PATH_SIZE];
uint32_t uid;
uint32_t agent_id;
};
static inline void get_agent_event(struct smc_event_data *event_data)
{
if (event_data)
atomic_inc(&event_data->usage);
}
static inline void put_agent_event(struct smc_event_data *event_data)
{
if (event_data) {
if (atomic_dec_and_test(&event_data->usage))
kfree(event_data);
}
}
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);
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);
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 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,
unsigned int dev_file_id);
int tee_agent_kernel_register(struct tee_agent_kernel_ops *new_agent);
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);
#endif
+613
View File
@@ -0,0 +1,613 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: cmdmonitor function, monitor every cmd which is sent to TEE.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "cmdmonitor.h"
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/pid.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <securec.h>
#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
#include <linux/sched/task.h>
#endif
#ifdef CONFIG_TEE_LOG_EXCEPTION
#include <huawei_platform/log/imonitor.h>
#define IMONITOR_TA_CRASH_EVENT_ID 901002003
#define IMONITOR_MEMSTAT_EVENT_ID 940007001
#define IMONITOR_TAMEMSTAT_EVENT_ID 940007002
#endif
#include "tc_ns_log.h"
#include "smc_smp.h"
#include "internal_functions.h"
#include "mailbox_mempool.h"
#include "tlogger.h"
#include "log_cfg_api.h"
#include "tui.h"
static int g_cmd_need_archivelog;
static LIST_HEAD(g_cmd_monitor_list);
static int g_cmd_monitor_list_size;
/* report 2 hours */
static const long long g_memstat_report_freq = 2 * 60 * 60 * 1000;
#define MAX_CMD_MONITOR_LIST 200
#define MAX_AGENT_CALL_COUNT 5000
static DEFINE_MUTEX(g_cmd_monitor_lock);
/* independent wq to avoid block system_wq */
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 struct delayed_work g_mem_stat;
static int g_tee_detect_ta_crash;
static struct tc_uuid g_crashed_ta_uuid;
void get_time_spec(struct time_spec *time)
{
if (!time)
return;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0))
time->ts = current_kernel_time();
#else
ktime_get_coarse_ts64(&time->ts);
#endif
}
static void schedule_memstat_work(struct delayed_work *work,
unsigned long delay)
{
schedule_delayed_work(work, delay);
}
static void schedule_cmd_monitor_work(struct delayed_work *work,
unsigned long delay)
{
if (g_cmd_monitor_wq)
queue_delayed_work(g_cmd_monitor_wq, work, delay);
else
schedule_delayed_work(work, delay);
}
void tzdebug_memstat(void)
{
schedule_memstat_work(&g_mem_stat, usecs_to_jiffies(S_TO_MS));
}
void tzdebug_archivelog(void)
{
schedule_cmd_monitor_work(&g_cmd_monitor_work_archive,
usecs_to_jiffies(0));
}
void cmd_monitor_ta_crash(int32_t type, const uint8_t *ta_uuid, uint32_t uuid_len)
{
g_tee_detect_ta_crash = type;
if (g_tee_detect_ta_crash != TYPE_CRASH_TEE &&
ta_uuid != NULL && uuid_len == sizeof(struct tc_uuid))
(void)memcpy_s(&g_crashed_ta_uuid, sizeof(g_crashed_ta_uuid),
ta_uuid, uuid_len);
tzdebug_archivelog();
fault_monitor_start(type);
}
static int get_pid_name(pid_t pid, char *comm, size_t size)
{
struct task_struct *task = NULL;
int sret;
if (size <= TASK_COMM_LEN - 1 || !comm)
return -1;
rcu_read_lock();
#ifndef CONFIG_TZDRIVER_MODULE
task = find_task_by_vpid(pid);
#else
task = pid_task(find_vpid(pid), PIDTYPE_PID);
#endif
if (task)
get_task_struct(task);
rcu_read_unlock();
if (!task) {
tloge("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);
put_task_struct(task);
return sret;
}
bool is_thread_reported(pid_t tid)
{
bool ret = false;
struct cmd_monitor *monitor = NULL;
mutex_lock(&g_cmd_monitor_lock);
list_for_each_entry(monitor, &g_cmd_monitor_list, list) {
if (monitor->tid == tid && !is_tui_in_use(monitor->tid)) {
ret = (monitor->is_reported ||
monitor->agent_call_count >
MAX_AGENT_CALL_COUNT);
break;
}
}
mutex_unlock(&g_cmd_monitor_lock);
return ret;
}
#ifdef CONFIG_TEE_LOG_EXCEPTION
#define FAIL_RET (-1)
#define SUCC_RET 0
static int send_memstat_packet(const struct tee_mem *meminfo)
{
struct imonitor_eventobj *memstat = NULL;
uint32_t result = 0;
struct time_spec nowtime;
int ret;
get_time_spec(&nowtime);
memstat = imonitor_create_eventobj(IMONITOR_MEMSTAT_EVENT_ID);
if (!memstat) {
tloge("create eventobj failed\n");
return FAIL_RET;
}
result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "totalmem", meminfo->total_mem);
result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "mem", meminfo->pmem);
result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "freemem", meminfo->free_mem);
result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "freememmin", meminfo->free_mem_min);
result |= (uint32_t)imonitor_set_param_integer_v2(memstat, "tanum", meminfo->ta_num);
result |= (uint32_t)imonitor_set_time(memstat, nowtime.ts.tv_sec);
if (result) {
tloge("set param integer1 failed ret=%u\n", result);
imonitor_destroy_eventobj(memstat);
return FAIL_RET;
}
ret = imonitor_send_event(memstat);
imonitor_destroy_eventobj(memstat);
if (ret <= 0) {
tloge("imonitor send memstat packet failed\n");
return FAIL_RET;
}
return SUCC_RET;
}
void report_imonitor(const struct tee_mem *meminfo)
{
int ret;
uint32_t result = 0;
uint32_t i;
struct imonitor_eventobj *pamemobj = NULL;
struct time_spec nowtime;
get_time_spec(&nowtime);
if (!meminfo)
return;
if (meminfo->ta_num > MEMINFO_TA_MAX)
return;
if (send_memstat_packet(meminfo))
return;
for (i = 0; i < meminfo->ta_num; i++) {
pamemobj = imonitor_create_eventobj(IMONITOR_TAMEMSTAT_EVENT_ID);
if (!pamemobj) {
tloge("create obj failed\n");
break;
}
result |= (uint32_t)imonitor_set_param_string_v2(pamemobj, "NAME", meminfo->ta_mem_info[i].ta_name);
result |= (uint32_t)imonitor_set_param_integer_v2(pamemobj, "MEM", meminfo->ta_mem_info[i].pmem);
result |= (uint32_t)imonitor_set_param_integer_v2(pamemobj, "MEMMAX", meminfo->ta_mem_info[i].pmem_max);
result |= (uint32_t)imonitor_set_param_integer_v2(pamemobj, "MEMLIMIT", meminfo->ta_mem_info[i].pmem_limit);
result |= (uint32_t)imonitor_set_time(pamemobj, nowtime.ts.tv_sec);
if (result) {
tloge("set param integer2 failed ret=%d\n", result);
imonitor_destroy_eventobj(pamemobj);
return;
}
ret = imonitor_send_event(pamemobj);
imonitor_destroy_eventobj(pamemobj);
if (ret <= 0) {
tloge("imonitor send pamem packet failed\n");
break;
}
}
}
#endif
static 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);
#ifdef CONFIG_TEE_LOG_EXCEPTION
if (ret == 0) {
tlogd("report imonitor\n");
report_imonitor(meminfo);
}
#endif
if (ret != 0)
tlogd("get meminfo failed\n");
mailbox_free(meminfo);
}
static void memstat_work(struct work_struct *work)
{
(void)(work);
memstat_report();
}
void cmd_monitor_reset_context(void)
{
struct cmd_monitor *monitor = NULL;
pid_t pid = current->tgid;
pid_t tid = current->pid;
mutex_lock(&g_cmd_monitor_lock);
list_for_each_entry(monitor, &g_cmd_monitor_list, list) {
if (monitor->pid == pid && monitor->tid == tid) {
get_time_spec(&monitor->sendtime);
if (monitor->agent_call_count + 1 < 0)
tloge("agent call count add overflow\n");
else
monitor->agent_call_count++;
break;
}
}
mutex_unlock(&g_cmd_monitor_lock);
}
#ifdef CONFIG_TEE_LOG_EXCEPTION
static struct time_spec g_memstat_check_time;
static bool g_after_loader = false;
static void auto_report_memstat(void)
{
long long timedif;
struct time_spec nowtime;
get_time_spec(&nowtime);
/*
* get time value D (timedif=nowtime-sendtime),
* we do not care about overflow
* 1 year means 1000 * (60*60*24*365) = 0x757B12C00
* only 5bytes, will not overflow
*/
timedif = S_TO_MS * (nowtime.ts.tv_sec - g_memstat_check_time.ts.tv_sec) +
(nowtime.ts.tv_nsec - g_memstat_check_time.ts.tv_nsec) / S_TO_US;
if (timedif > g_memstat_report_freq && g_after_loader) {
tlogi("cmdmonitor auto report memstat\n");
memstat_report();
g_memstat_check_time = nowtime;
}
if (!g_after_loader) {
g_memstat_check_time = nowtime;
g_after_loader = true;
}
}
#endif
/*
* if one session timeout, monitor will print timedifs every step[n] in seconds,
* if lasted more then 360s, monitor will print timedifs every 360s.
*/
const int32_t g_timer_step[] = {1, 1, 1, 2, 5, 10, 40, 120, 180, 360};
const int32_t g_timer_nums = sizeof(g_timer_step) / sizeof(int32_t);
static void show_timeout_cmd_info(struct cmd_monitor *monitor)
{
long long timedif, timedif2;
struct time_spec nowtime;
int32_t time_in_sec;
get_time_spec(&nowtime);
/*
* 1 year means 1000 * (60*60*24*365) = 0x757B12C00
* only 5bytes, so timedif (timedif=nowtime-sendtime) will not overflow
*/
timedif = S_TO_MS * (nowtime.ts.tv_sec - monitor->sendtime.ts.tv_sec) +
(nowtime.ts.tv_nsec - monitor->sendtime.ts.tv_nsec) / S_TO_US;
/* timeout to 10s, we log the teeos log, and report */
if ((timedif > CMD_MAX_EXECUTE_TIME * S_TO_MS) && (!monitor->is_reported)) {
monitor->is_reported = true;
tloge("[cmd_monitor_tick] pid=%d,pname=%s,tid=%d, "
"tname=%s, lastcmdid=%u, agent call count:%d, "
"running with timedif=%lld ms and report\n",
monitor->pid, monitor->pname, monitor->tid,
monitor->tname, monitor->lastcmdid,
monitor->agent_call_count, timedif);
/* threads out of white table need info dump */
tloge("monitor: pid-%d", monitor->pid);
if (!is_tui_in_use(monitor->tid)) {
show_cmd_bitmap();
g_cmd_need_archivelog = 1;
wakeup_tc_siq(SIQ_DUMP_TIMEOUT);
}
}
timedif2 = S_TO_MS * (nowtime.ts.tv_sec - monitor->lasttime.ts.tv_sec) +
(nowtime.ts.tv_nsec - monitor->lasttime.ts.tv_nsec) / S_TO_US;
time_in_sec = monitor->timer_index >= g_timer_nums ?
g_timer_step[g_timer_nums - 1] : g_timer_step[monitor->timer_index];
if (timedif2 > time_in_sec * S_TO_MS) {
monitor->lasttime = nowtime;
monitor->timer_index = monitor->timer_index >= (int32_t)sizeof(g_timer_step) ?
(int32_t)sizeof(g_timer_step) : (monitor->timer_index + 1);
tlogi("[cmd_monitor_tick] pid=%d,pname=%s,tid=%d, "
"lastcmdid=%u,agent call count:%d,timedif=%lld ms\n",
monitor->pid, monitor->pname, monitor->tid,
monitor->lastcmdid, monitor->agent_call_count,
timedif);
}
}
static void cmd_monitor_tick(void)
{
struct cmd_monitor *monitor = NULL;
struct cmd_monitor *tmp = NULL;
mutex_lock(&g_cmd_monitor_lock);
list_for_each_entry_safe(monitor, tmp, &g_cmd_monitor_list, list) {
if (monitor->returned) {
g_cmd_monitor_list_size--;
tlogd("[cmd_monitor_tick] pid=%d,pname=%s,tid=%d, "
"tname=%s,lastcmdid=%u,count=%d,agent call count=%d, "
"timetotal=%lld us returned, remained command(s)=%d\n",
monitor->pid, monitor->pname, monitor->tid, monitor->tname,
monitor->lastcmdid, monitor->count, monitor->agent_call_count,
monitor->timetotal, g_cmd_monitor_list_size);
list_del(&monitor->list);
kfree(monitor);
continue;
}
show_timeout_cmd_info(monitor);
}
/* if have cmd in monitor list, we need tick */
if (g_cmd_monitor_list_size > 0)
schedule_cmd_monitor_work(&g_cmd_monitor_work, usecs_to_jiffies(S_TO_US));
mutex_unlock(&g_cmd_monitor_lock);
#ifdef CONFIG_TEE_LOG_EXCEPTION
auto_report_memstat();
#endif
}
static void cmd_monitor_tickfn(struct work_struct *work)
{
(void)(work);
cmd_monitor_tick();
/* check tlogcat if have new log */
tz_log_write();
}
#define MAX_CRASH_INFO_LEN 100
static void cmd_monitor_archivefn(struct work_struct *work)
{
(void)(work);
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");
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) {
#ifdef CONFIG_TEE_LOG_EXCEPTION
const char crash_prefix[] = "ta crash: ";
const char killed_prefix[] = "ta timeout and killed: ";
const char crash_info_get_failed[] = "ta crash: get uuid failed";
char buffer[MAX_CRASH_INFO_LEN] = {0};
const char *crash_info = buffer;
int ret = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1,
"%s%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
(g_tee_detect_ta_crash == TYPE_CRASH_TA) ? crash_prefix : killed_prefix,
g_crashed_ta_uuid.time_low, g_crashed_ta_uuid.time_mid,
g_crashed_ta_uuid.timehi_and_version,
g_crashed_ta_uuid.clockseq_and_node[0], g_crashed_ta_uuid.clockseq_and_node[1],
g_crashed_ta_uuid.clockseq_and_node[2], g_crashed_ta_uuid.clockseq_and_node[3],
g_crashed_ta_uuid.clockseq_and_node[4], g_crashed_ta_uuid.clockseq_and_node[5],
g_crashed_ta_uuid.clockseq_and_node[6], g_crashed_ta_uuid.clockseq_and_node[7]);
if (ret <= 0) {
tlogw("append crash info failed\n");
crash_info = crash_info_get_failed;
}
if (teeos_log_exception_archive(IMONITOR_TA_CRASH_EVENT_ID, crash_info) < 0)
tloge("log exception archive failed\n");
(void)memset_s(&g_crashed_ta_uuid, sizeof(g_crashed_ta_uuid), 0, sizeof(g_crashed_ta_uuid));
#endif
}
g_tee_detect_ta_crash = 0;
}
static struct cmd_monitor *init_monitor_locked(void)
{
struct cmd_monitor *newitem = NULL;
newitem = kzalloc(sizeof(*newitem), GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)newitem)) {
tloge("[cmd_monitor_tick]kzalloc failed\n");
return NULL;
}
get_time_spec(&newitem->sendtime);
newitem->lasttime = newitem->sendtime;
newitem->timer_index = 0;
newitem->count = 1;
newitem->agent_call_count = 0;
newitem->returned = false;
newitem->is_reported = false;
newitem->pid = current->tgid;
newitem->tid = current->pid;
if (get_pid_name(newitem->pid, newitem->pname,
sizeof(newitem->pname)) != 0)
newitem->pname[0] = '\0';
if (get_pid_name(newitem->tid, newitem->tname,
sizeof(newitem->tname)) != 0)
newitem->tname[0] = '\0';
INIT_LIST_HEAD(&newitem->list);
list_add_tail(&newitem->list, &g_cmd_monitor_list);
g_cmd_monitor_list_size++;
return newitem;
}
struct cmd_monitor *cmd_monitor_log(const struct tc_ns_smc_cmd *cmd)
{
bool found_flag = false;
pid_t pid;
pid_t tid;
struct cmd_monitor *monitor = NULL;
if (!cmd)
return NULL;
pid = current->tgid;
tid = current->pid;
mutex_lock(&g_cmd_monitor_lock);
do {
list_for_each_entry(monitor, &g_cmd_monitor_list, list) {
if (monitor->pid == pid && monitor->tid == tid) {
found_flag = true;
/* restart */
get_time_spec(&monitor->sendtime);
monitor->lasttime = monitor->sendtime;
monitor->timer_index = 0;
monitor->count++;
monitor->returned = false;
monitor->is_reported = false;
monitor->lastcmdid = cmd->cmd_id;
monitor->agent_call_count = 0;
monitor->timetotal = 0;
break;
}
}
if (!found_flag) {
#ifndef CONFIG_BIG_SESSION
if (g_cmd_monitor_list_size > MAX_CMD_MONITOR_LIST - 1) {
tloge("monitor reach max node num\n");
monitor = NULL;
break;
}
#endif
monitor = init_monitor_locked();
if (!monitor) {
tloge("init monitor failed\n");
break;
}
monitor->lastcmdid = cmd->cmd_id;
/* the first cmd will cause timer */
if (g_cmd_monitor_list_size == 1)
schedule_cmd_monitor_work(&g_cmd_monitor_work,
usecs_to_jiffies(S_TO_US));
}
} while (0);
mutex_unlock(&g_cmd_monitor_lock);
return monitor;
}
void cmd_monitor_logend(struct cmd_monitor *item)
{
struct time_spec nowtime;
long long timedif;
if (!item)
return;
get_time_spec(&nowtime);
/*
* get time value D (timedif=nowtime-sendtime),
* we do not care about overflow
* 1 year means 1000000 * (60*60*24*365) = 0x1CAE8C13E000
* only 6bytes, will not overflow
*/
timedif = S_TO_US * (nowtime.ts.tv_sec - item->sendtime.ts.tv_sec) +
(nowtime.ts.tv_nsec - item->sendtime.ts.tv_nsec) / S_TO_MS;
item->timetotal += timedif;
item->returned = true;
}
void do_cmd_need_archivelog(void)
{
if (g_cmd_need_archivelog == 1) {
g_cmd_need_archivelog = 0;
schedule_cmd_monitor_work(&g_cmd_monitor_work_archive,
usecs_to_jiffies(S_TO_US));
}
}
void init_cmd_monitor(void)
{
g_cmd_monitor_wq = alloc_workqueue("tz_cmd_monitor_wq",
WQ_UNBOUND, TZ_WQ_MAX_ACTIVE);
if (!g_cmd_monitor_wq)
tloge("alloc cmd monitor wq failed\n");
else
tz_workqueue_bind_mask(g_cmd_monitor_wq, 0);
INIT_DEFERRABLE_WORK((struct delayed_work *)
(uintptr_t)&g_cmd_monitor_work, cmd_monitor_tickfn);
INIT_DEFERRABLE_WORK((struct delayed_work *)
(uintptr_t)&g_cmd_monitor_work_archive, cmd_monitor_archivefn);
INIT_DEFERRABLE_WORK((struct delayed_work *)
(uintptr_t)&g_mem_stat, memstat_work);
}
void free_cmd_monitor(void)
{
struct cmd_monitor *monitor = NULL;
struct cmd_monitor *tmp = NULL;
mutex_lock(&g_cmd_monitor_lock);
list_for_each_entry_safe(monitor, tmp, &g_cmd_monitor_list, list) {
list_del(&monitor->list);
kfree(monitor);
}
mutex_unlock(&g_cmd_monitor_lock);
flush_delayed_work(&g_cmd_monitor_work);
flush_delayed_work(&g_cmd_monitor_work_archive);
flush_delayed_work(&g_mem_stat);
if (g_cmd_monitor_wq) {
flush_workqueue(g_cmd_monitor_wq);
destroy_workqueue(g_cmd_monitor_wq);
g_cmd_monitor_wq = NULL;
}
}
+76
View File
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: cmdmonitor function declaration
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 CMD_MONITOR_H
#define CMD_MONITOR_H
#include "tzdebug.h"
#include "teek_ns_client.h"
#include "smc_smp.h"
#include <linux/version.h>
#if (KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE)
#define TASK_COMM_LEN 16
#endif
enum {
TYPE_CRASH_TEE = 1,
TYPE_CRASH_TA = 2,
TYPE_KILLED_TA = 3,
};
/*
* when cmd execute more than 25s in tee,
* it will be terminated when CA is killed
*/
#define CMD_MAX_EXECUTE_TIME 10U
#define S_TO_MS 1000
#define S_TO_US 1000000
struct time_spec {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0))
struct timespec ts;
#else
struct timespec64 ts;
#endif
};
struct cmd_monitor {
struct list_head list;
struct time_spec sendtime;
struct time_spec lasttime;
int32_t timer_index;
int count;
bool returned;
bool is_reported;
pid_t pid;
pid_t tid;
char pname[TASK_COMM_LEN];
char tname[TASK_COMM_LEN];
unsigned int lastcmdid;
long long timetotal;
int agent_call_count;
};
struct cmd_monitor *cmd_monitor_log(const struct tc_ns_smc_cmd *cmd);
void cmd_monitor_reset_context(void);
void cmd_monitor_logend(struct cmd_monitor *item);
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, const uint8_t *ta_uuid, uint32_t uuid_len);
void tzdebug_memstat(void);
void get_time_spec(struct time_spec *time);
#endif
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: functions for ffa settings
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 <linux/arm_ffa.h>
#include "ffa_abi.h"
#include "teek_ns_client.h"
#include "tz_pm.h"
#include "smc_call.h"
const struct ffa_ops *g_ffa_ops = NULL;
struct ffa_device *g_ffa_dev = NULL;
static void ffa_remove(struct ffa_device *ffa_dev)
{
tlogd("stub remove ffa driver!\n");
}
static int ffa_probe(struct ffa_device *ffa_dev)
{
g_ffa_ops = ffa_dev->ops;
g_ffa_dev = ffa_dev;
if (!g_ffa_ops) {
tloge("failed to get ffa_ops!\n");
return -ENOENT;
}
g_ffa_ops->mode_32bit_set(ffa_dev);
return 0;
}
/* two sp uuid can be the same */
const struct ffa_device_id tz_ffa_device_id[] = {
/* uuid = <0xe0786148 0xe311f8e7 0x02005ebc 0x1bc5d5a5> */
{0x48, 0x61, 0x78, 0xe0, 0xe7, 0xf8, 0x11, 0xe3, 0xbc, 0x5e, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b},
{}
};
static struct ffa_driver tz_ffa_driver = {
.name = "iTrustee",
.probe = ffa_probe,
.remove = ffa_remove,
.id_table = tz_ffa_device_id,
};
int ffa_abi_register(void)
{
return ffa_register(&tz_ffa_driver);
}
void ffa_abi_unregister(void)
{
ffa_unregister(&tz_ffa_driver);
}
void smc_req(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait)
{
ffa_forward_call(in, out, wait);
}
static void convert_smc_param_to_ffa_param(struct smc_in_params *in_param, struct ffa_send_direct_data *ffa_param)
{
ffa_param->data0 = in_param->x1;
ffa_param->data1 = in_param->x2;
ffa_param->data2 = in_param->x3;
ffa_param->data3 = in_param->x4;
/* x0(smc id) need to be transported for tee dealing it directly */
ffa_param->data4 = in_param->x0;
}
static void convert_ffa_param_to_smc_param(struct ffa_send_direct_data *ffa_param, struct smc_out_params *out_param)
{
out_param->ret = ffa_param->data4;
out_param->exit_reason = ffa_param->data0;
out_param->ta = ffa_param->data1;
out_param->target = ffa_param->data2;
}
int ffa_forward_call(struct smc_in_params *in_param, struct smc_out_params *out_param, uint8_t wait)
{
if (in_param == NULL || out_param == NULL) {
tloge("invalid parameter ffa forward!\n");
return -1;
}
int ret;
struct ffa_send_direct_data ffa_param = {};
convert_smc_param_to_ffa_param(in_param, &ffa_param);
do {
ret = g_ffa_ops->sync_send_receive(g_ffa_dev, &ffa_param);
convert_ffa_param_to_smc_param(&ffa_param, out_param);
} while (out_param->ret == TSP_REQUEST && wait != 0);
if (ret != 0)
tloge("failed to call! ret is %d\n", ret);
return ret;
}
+161
View File
@@ -0,0 +1,161 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: declarations for ffa functions and useful macros
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 FFA_ABI_H
#define FFA_ABI_H
#include <linux/arm_ffa.h>
#include "smc_smp.h"
#include "smc_call.h"
/*
* Normal world sends requests with FFA_MSG_SEND_DIRECT_REQ and
* responses are returned with FFA_MSG_SEND_DIRECT_RESP for normal
* messages.
*
* All requests with FFA_MSG_SEND_DIRECT_REQ and FFA_MSG_SEND_DIRECT_RESP
* are using the AArch32 SMC calling convention with register usage as
* defined in FF-A specification:
* w0: Function ID (0x8400006F or 0x84000070)
* w1: Source/Destination IDs
* w2: Reserved (MBZ)
* w3-w7: Implementation defined, free to be used below
*/
#define TZ_FFA_VERSION_MAJOR 1
#define TZ_FFA_VERSION_MINOR 0
#define TZ_FFA_BLOCKING_CALL(id) (id)
#define TZ_FFA_YIELDING_CALL_BIT 31
#define TZ_FFA_YIELDING_CALL(id) ((id) | BIT(TZ_FFA_YIELDING_CALL_BIT))
/*
* Returns the API version implemented, currently follows the FF-A version.
* Call register usage:
* w3: Service ID, TZ_FFA_GET_API_VERSION
* w4-w7: Not used (MBZ)
*
* Return register usage:
* w3: TZ_FFA_VERSION_MAJOR
* w4: TZ_FFA_VERSION_MINOR
* w5-w7: Not used (MBZ)
*/
#define TZ_FFA_GET_API_VERSION TZ_FFA_BLOCKING_CALL(0)
/*
* Returns the revision of iTrustee
*
* Used by non-secure world to figure out which version of the Trusted OS
* is installed. Note that the returned revision is the revision of the
* Trusted OS, not of the API.
*
* Call register usage:
* w3: Service ID, TZ_FFA_GET_OS_VERSION
* w4-w7: Unused (MBZ)
*
* Return register usage:
* w3: CFG_TZ_REVISION_MAJOR
* w4: CFG_TZ_REVISION_MINOR
* w5: TEE_IMPL_GIT_SHA1 (or zero if not supported)
*/
#define TZ_FFA_GET_OS_VERSION TZ_FFA_BLOCKING_CALL(1)
/*
* Exchange capabilities between normal world and secure world.
*
* Currently, there are no defined capabilities. When features are added new
* capabilities may be added.
*
* Call register usage:
* w3: Service ID, TZ_FFA_EXCHANGE_CAPABILITIES
* w4-w7: Not used (MBZ)
*
* Return register usage:
* w3: Error code, 0 on success
* w4: Bit[7:0]: Number of parameters needed for RPC to be supplied
* as the second MSG arg struct for
* TZ_FFA_YIELDING_CALL_WITH_ARG.
* Bit[31:8]: Reserved (MBZ)
* w5-w7: Not used (MBZ)
*/
#define TZ_FFA_EXCHANGE_CAPABILITIES TZ_FFA_BLOCKING_CALL(2)
/*
* Unregister shared memory
*
* Call register usage:
* w3: Service ID, TZ_FFA_YIELDING_CALL_UNREGISTER_SHM
* w4: Shared memory handle, lower bits
* w5: Shared memory handle, higher bits
* w6-w7: Not used (MBZ)
*
* Return register usage:
* w3: Error code, 0 on success
* w4-w7: Not used (MBZ)
*/
#define TZ_FFA_UNREGISTER_SHM TZ_FFA_BLOCKING_CALL(3)
/*
* Call with struct TZ_msg_arg as argument in the supplied shared memory
* with a zero internal offset and normal cached memory attributes
* Register usage:
* w3: Service ID, TZ_FFA_YIELDING_CALL_WITH_ARG
* w4: Lower 32 bits of a 64-bit Shared memory handle
* w5: Upper 32 bits of a 64-bit Shared memory handle
* w6: Offset into shared memory pointing to a struct TZ_msg_arg
* right after the parameters of this struct (at offset
* TZ_MSG_GET_ARG_SIZE(num_params) follows a struct TZ_msg_arg
* for RPC, this struct has reserved space for the number of RPC
* parameters as returned by TZ_FFA_EXCHANGE_CAPABILITIES.
* w7: Not used (MBZ)
* Resume from RPC. Register usage:
* w3: Service ID, TZ_FFA_YIELDING_CALL_RESUME
* w4-w6: Not used (MBZ)
* w7: Resume info
*
* Normal return (yielding call is completed). Register usage:
* w3: Error code, 0 on success
* w4: TZ_FFA_YIELDING_CALL_RETURN_DONE
* w5-w7: Not used (MBZ)
*
* RPC interrupt return (RPC from secure world). Register usage:
* w3: Error code == 0
* w4: Any defined RPC code but TZ_FFA_YIELDING_CALL_RETURN_DONE
* w5-w6: Not used (MBZ)
* w7: Resume info
*
* Possible error codes in register w3:
* 0: Success
* FFA_DENIED: w4 isn't one of TZ_FFA_YIELDING_CALL_START
* TZ_FFA_YIELDING_CALL_RESUME
*
* Possible error codes for TZ_FFA_YIELDING_CALL_START
* FFA_BUSY: Number of OP-TEE OS threads exceeded,
* try again later
* FFA_DENIED: RPC shared memory object not found
* FFA_INVALID_PARAMETER: Bad shared memory handle or offset into the memory
*
* Possible error codes for TZ_FFA_YIELDING_CALL_RESUME
* FFA_INVALID_PARAMETER: Bad resume info
*/
#define TZ_FFA_YIELDING_CALL_WITH_ARG TZ_FFA_YIELDING_CALL(0)
#define TZ_FFA_YIELDING_CALL_RESUME TZ_FFA_YIELDING_CALL(1)
#define TZ_FFA_YIELDING_CALL_RETURN_DONE 0
#define TZ_FFA_YIELDING_CALL_RETURN_RPC_CMD 1
#define TZ_FFA_YIELDING_CALL_RETURN_INTERRUPT 2
int ffa_abi_register(void);
void ffa_abi_unregister(void);
int ffa_forward_call(struct smc_in_params *in_param, struct smc_out_params *out_param, uint8_t wait);
#endif
File diff suppressed because it is too large Load Diff
+37
View File
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function declaration for alloc global operation and pass params to TEE.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 GP_OPS_H
#define GP_OPS_H
#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,
const void __user *src, size_t size, uint8_t kernel_api);
bool tc_user_param_valid(struct tc_ns_client_context *client_context,
unsigned int index);
int tc_client_call(const struct tc_call_params *call_params);
bool is_tmp_mem(uint32_t param_type);
bool is_ref_mem(uint32_t param_type);
bool is_val_param(uint32_t param_type);
#endif
+644
View File
@@ -0,0 +1,644 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: mailbox memory managing for sharing memory with TEE.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "mailbox_mempool.h"
#include "shared_mem.h"
#include <linux/list.h>
#include <linux/sizes.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <securec.h>
#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
#include <linux/vmalloc.h>
#endif
#include "teek_client_constants.h"
#include "tc_ns_log.h"
#include "smc_smp.h"
#include "ko_adapt.h"
#include "internal_functions.h"
#define MAILBOX_PAGE_MAX (MAILBOX_POOL_SIZE >> PAGE_SHIFT)
static int g_max_oder;
#define OPT_MODE 0660U
#define STATE_MODE 0440U
struct mb_page_t {
struct list_head node;
mailbox_page_t *page;
int order;
unsigned int count; /* whether be used */
};
struct mb_free_area_t {
struct list_head page_list;
int order;
};
struct mb_zone_t {
mailbox_page_t *all_pages;
struct mb_page_t pages[MAILBOX_PAGE_MAX];
struct mb_free_area_t free_areas[0];
};
static struct mb_zone_t *g_m_zone;
static struct mutex g_mb_lock;
static void mailbox_show_status(void)
{
unsigned int i;
struct mb_page_t *pos = NULL;
struct list_head *head = NULL;
unsigned int used = 0;
if (!g_m_zone) {
tloge("zone struct is NULL\n");
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);
}
}
tloge("total usage:%u/%u\n", used, MAILBOX_PAGE_MAX);
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);
}
}
mutex_unlock(&g_mb_lock);
tloge("########################################\n");
}
#define MB_SHOW_LINE 64
#define BITS_OF_BYTE 8
static void mailbox_show_details(void)
{
unsigned int i;
unsigned int used = 0;
unsigned int left = 0;
unsigned int order = 0;
if (!g_m_zone) {
tloge("zone struct is NULL\n");
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);
}
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 (left != 0) {
left--;
tloge("%01d", order);
} else {
tloge("X");
}
if (i > 1 && (i + 1) % (MB_SHOW_LINE / BITS_OF_BYTE) == 0)
tloge(" ");
}
tloge("total usage:%u/%u\n", used, MAILBOX_PAGE_MAX);
mutex_unlock(&g_mb_lock);
}
void *mailbox_alloc(size_t size, unsigned int flag)
{
unsigned int i;
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;
}
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;
pos = list_first_entry(head, struct mb_page_t, node);
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;
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);
}
list_del(&pos->node);
addr = (void *)mailbox_page_address(pos->page);
break;
}
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) {
tloge("clean mailbox failed\n");
mailbox_free(addr);
return NULL;
}
}
return addr;
}
static void add_max_order_block(unsigned int idex)
{
struct mb_page_t *self = NULL;
if (idex != (unsigned int)g_max_oder || !g_m_zone)
return;
/*
* when idex 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];
list_add_tail(&self->node,
&g_m_zone->free_areas[g_max_oder].page_list);
}
static bool is_ptr_valid(const mailbox_page_t *page)
{
if (!g_m_zone)
return false;
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;
}
return true;
}
void mailbox_free(const void *ptr)
{
unsigned int i;
mailbox_page_t *page = NULL;
struct mb_page_t *self = NULL;
struct mb_page_t *buddy = NULL;
unsigned int self_idx;
unsigned int buddy_idx;
if (!ptr || !g_m_zone) {
tloge("invalid ptr or zone struct is NULL\n");
return;
}
page = mailbox_virt_to_page((uint64_t)(uintptr_t)ptr);
if (!is_ptr_valid(page))
return;
mutex_lock(&g_mb_lock);
self_idx = page - g_m_zone->all_pages;
self = &g_m_zone->pages[self_idx];
if (self->count == 0) {
tloge("already freed in mailbox\n");
mutex_unlock(&g_mb_lock);
return;
}
for (i = (unsigned int)self->order; i <
(unsigned int)g_max_oder; i++) {
self_idx = page - g_m_zone->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->count = 0;
/* is buddy free */
if ((unsigned int)buddy->order == i && buddy->count == 0) {
/* release buddy */
list_del(&buddy->node);
/* combine self and buddy */
if (self_idx > buddy_idx) {
page = buddy->page;
buddy->order = (int)i + 1;
self->order = -1;
} else {
self->order = (int)i + 1;
buddy->order = -1;
}
} else {
/* release self */
list_add_tail(&self->node,
&g_m_zone->free_areas[i].page_list);
mutex_unlock(&g_mb_lock);
return;
}
}
add_max_order_block(i);
mutex_unlock(&g_mb_lock);
}
struct mb_cmd_pack *mailbox_alloc_cmd_pack(void)
{
void *pack = mailbox_alloc(SZ_4K, MB_FLAG_ZERO);
if (!pack)
tloge("alloc mb cmd pack failed\n");
return (struct mb_cmd_pack *)pack;
}
void *mailbox_copy_alloc(const void *src, size_t size)
{
void *mb_ptr = NULL;
if (!src || !size) {
tloge("invali src to alloc mailbox copy\n");
return NULL;
}
mb_ptr = mailbox_alloc(size, 0);
if (!mb_ptr) {
tloge("alloc size %zu mailbox failed\n", size);
return NULL;
}
if (memcpy_s(mb_ptr, size, src, size) != 0) {
tloge("memcpy to mailbox failed\n");
mailbox_free(mb_ptr);
return NULL;
}
return mb_ptr;
}
struct mb_dbg_entry {
struct list_head node;
unsigned int idx;
void *ptr;
};
static LIST_HEAD(mb_dbg_list);
static DEFINE_MUTEX(mb_dbg_lock);
static unsigned int g_mb_dbg_entry_count = 1;
static unsigned int g_mb_dbg_last_res; /* only cache 1 opt result */
static struct dentry *g_mb_dbg_dentry;
static unsigned int mb_dbg_add_entry(void *ptr)
{
struct mb_dbg_entry *new_entry = NULL;
unsigned int index = 0;
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)new_entry)) {
tloge("alloc entry failed\n");
return 0;
}
INIT_LIST_HEAD(&new_entry->node);
new_entry->ptr = ptr;
mutex_lock(&mb_dbg_lock);
new_entry->idx = g_mb_dbg_entry_count;
if ((g_mb_dbg_entry_count++) == 0)
g_mb_dbg_entry_count++;
list_add_tail(&new_entry->node, &mb_dbg_list);
index = new_entry->idx;
mutex_unlock(&mb_dbg_lock);
return index;
}
static void mb_dbg_remove_entry(unsigned int idx)
{
struct mb_dbg_entry *pos = NULL;
struct mb_dbg_entry *temp = NULL;
mutex_lock(&mb_dbg_lock);
list_for_each_entry_safe(pos, temp, &mb_dbg_list, node) {
if (pos->idx == idx) {
mailbox_free(pos->ptr);
list_del(&pos->node);
kfree(pos);
mutex_unlock(&mb_dbg_lock);
return;
}
}
mutex_unlock(&mb_dbg_lock);
tloge("entry %u invalid\n", idx);
}
static void mb_dbg_reset(void)
{
struct mb_dbg_entry *pos = NULL;
struct mb_dbg_entry *tmp = NULL;
mutex_lock(&mb_dbg_lock);
list_for_each_entry_safe(pos, tmp, &mb_dbg_list, node) {
mailbox_free(pos->ptr);
list_del(&pos->node);
kfree(pos);
}
g_mb_dbg_entry_count = 0;
mutex_unlock(&mb_dbg_lock);
}
#define MB_WRITE_SIZE 64
static bool is_opt_write_param_valid(const struct file *filp,
const char __user *ubuf, size_t cnt, const loff_t *ppos)
{
if (!filp || !ppos || !ubuf)
return false;
if (cnt >= MB_WRITE_SIZE || cnt == 0)
return false;
return true;
}
static void alloc_dbg_entry(unsigned int alloc_size)
{
unsigned int idx;
void *ptr = NULL;
ptr = mailbox_alloc(alloc_size, 0);
if (!ptr) {
tloge("alloc order=%u in mailbox failed\n", alloc_size);
return;
}
idx = mb_dbg_add_entry(ptr);
if (idx == 0)
mailbox_free(ptr);
g_mb_dbg_last_res = idx;
}
static ssize_t mb_dbg_opt_write(struct file *filp,
const char __user *ubuf, size_t cnt, loff_t *ppos)
{
char buf[MB_WRITE_SIZE] = {0};
char *cmd = NULL;
char *value = NULL;
unsigned int alloc_size;
unsigned int free_idx;
if (!is_opt_write_param_valid(filp, ubuf, cnt, ppos))
return -EINVAL;
if (copy_from_user(buf, ubuf, cnt) != 0)
return -EFAULT;
buf[cnt] = 0;
value = buf;
if (strncmp(value, "reset", strlen("reset")) == 0) {
tlogi("mb dbg reset\n");
mb_dbg_reset();
return (ssize_t)cnt;
}
cmd = strsep(&value, ":");
if (!cmd || !value) {
tloge("no valid cmd or value for mb dbg\n");
return -EFAULT;
}
if (strncmp(cmd, "alloc", strlen("alloc")) == 0) {
if (kstrtou32(value, 10, &alloc_size) == 0)
alloc_dbg_entry(alloc_size);
else
tloge("invalid value format for mb dbg\n");
} else if (strncmp(cmd, "free", strlen("free")) == 0) {
if (kstrtou32(value, 10, &free_idx) == 0)
mb_dbg_remove_entry(free_idx);
else
tloge("invalid value format for mb dbg\n");
} else {
tloge("invalid format for mb dbg\n");
}
return (ssize_t)cnt;
}
static ssize_t mb_dbg_opt_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
char buf[16] = {0};
ssize_t ret;
(void)(filp);
ret = snprintf_s(buf, sizeof(buf), 15, "%u\n", g_mb_dbg_last_res);
if (ret < 0) {
tloge("snprintf idx failed\n");
return -EINVAL;
}
return simple_read_from_buffer(ubuf, cnt, ppos, buf, ret);
}
static const struct file_operations g_mb_dbg_opt_fops = {
.owner = THIS_MODULE,
.read = mb_dbg_opt_read,
.write = mb_dbg_opt_write,
};
static ssize_t mb_dbg_state_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
(void)cnt;
(void)(filp);
(void)(ubuf);
(void)(ppos);
mailbox_show_status();
mailbox_show_details();
return 0;
}
static const struct file_operations g_mb_dbg_state_fops = {
.owner = THIS_MODULE,
.read = mb_dbg_state_read,
};
static int mailbox_register(const void *mb_pool, unsigned int size)
{
struct tc_ns_operation *operation = NULL;
struct tc_ns_smc_cmd *smc_cmd = NULL;
int ret = 0;
smc_cmd = kzalloc(sizeof(*smc_cmd), GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)smc_cmd)) {
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");
ret = -EIO;
goto free_smc_cmd;
}
operation->paramtypes = TEE_PARAM_TYPE_VALUE_INPUT |
(TEE_PARAM_TYPE_VALUE_INPUT << 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;
operation->params[1].value.a = size;
smc_cmd->cmd_type = CMD_TYPE_GLOBAL;
smc_cmd->cmd_id = GLOBAL_CMD_ID_REGISTER_MAILBOX;
smc_cmd->operation_phys = mailbox_virt_to_phys((uintptr_t)operation);
smc_cmd->operation_h_phys =
(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);
else
ret= tc_ns_smc(smc_cmd);
if (ret != 0) {
tloge("resigter mailbox failed\n");
ret = -EIO;
}
free_operation((uint64_t)(uintptr_t)operation);
operation = NULL;
free_smc_cmd:
kfree(smc_cmd);
smc_cmd = NULL;
return ret;
}
static void mailbox_debug_init(void)
{
#ifdef DEF_ENG
g_mb_dbg_dentry = debugfs_create_dir("tz_mailbox", NULL);
debugfs_create_file("opt", OPT_MODE, g_mb_dbg_dentry, NULL, &g_mb_dbg_opt_fops);
debugfs_create_file("state", STATE_MODE, g_mb_dbg_dentry, NULL, &g_mb_dbg_state_fops);
#endif
}
int re_register_mailbox(void)
{
if (!g_m_zone)
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;
}
}
return 0;
}
int mailbox_mempool_init(void)
{
int i;
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);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)g_m_zone)) {
tloge("fail to alloc zone struct\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;
return -ENOMEM;
}
if (mailbox_register((const void *) mailbox_page_address(all_pages), MAILBOX_POOL_SIZE) != 0) {
tloge("register mailbox failed\n");
mailbox_free_pages(all_pages, g_max_oder);
kfree(g_m_zone);
g_m_zone = NULL;
return -EIO;
}
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];
}
g_m_zone->pages[0].order = g_max_oder;
for (i = 0; i <= g_max_oder; i++) {
area = &g_m_zone->free_areas[i];
INIT_LIST_HEAD(&area->page_list);
area->order = i;
}
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;
}
void free_mailbox_mempool(void)
{
mailbox_free_pages(g_m_zone->all_pages, g_max_oder);
g_m_zone->all_pages = NULL;
kfree(g_m_zone);
g_m_zone = NULL;
if (!g_mb_dbg_dentry)
return;
debugfs_remove_recursive(g_mb_dbg_dentry);
g_mb_dbg_dentry = NULL;
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: mailbox memory managing for sharing memory with TEE.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 MAILBOX_MEMPOOOL_H
#define MAILBOX_MEMPOOOL_H
#include <linux/kernel.h>
#include <linux/types.h>
#include "teek_ns_client.h"
#ifndef MAILBOX_POOL_SIZE
#define MAILBOX_POOL_SIZE SZ_4M
#endif
/* alloc options */
#define MB_FLAG_ZERO 0x1 /* set 0 after alloc page */
#define GLOBAL_UUID_LEN 17 /* first char represent global cmd */
void *mailbox_alloc(size_t size, unsigned int flag);
void mailbox_free(const void *ptr);
int mailbox_mempool_init(void);
void free_mailbox_mempool(void);
struct mb_cmd_pack *mailbox_alloc_cmd_pack(void);
void *mailbox_copy_alloc(const void *src, size_t size);
int re_register_mailbox(void);
uintptr_t mailbox_virt_to_phys(uintptr_t addr);
#endif
+109
View File
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: memory operation for gp sharedmem.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "mem.h"
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <linux/module.h>
#include <linux/mempool.h>
#include <linux/vmalloc.h>
#include <linux/of_reserved_mem.h>
#include <securec.h>
#include "smc_smp.h"
#include "tc_ns_client.h"
#include "teek_ns_client.h"
#include "agent.h"
#include "tc_ns_log.h"
#include "mailbox_mempool.h"
#include "internal_functions.h"
#include "reserved_mempool.h"
void tc_mem_free(struct tc_ns_shared_mem *shared_mem)
{
if (!shared_mem)
return;
if (shared_mem->mem_type == RESERVED_TYPE) {
reserved_mem_free(shared_mem->kernel_addr);
kfree(shared_mem);
return;
}
if (shared_mem->kernel_addr) {
#ifndef CONFIG_LIBLINUX
vfree(shared_mem->kernel_addr);
#else
kfree(shared_mem->kernel_addr);
#endif
shared_mem->kernel_addr = NULL;
}
kfree(shared_mem);
}
static void init_shared_mem(struct tc_ns_shared_mem *sh, void *addr, size_t len)
{
sh->kernel_addr = addr;
sh->len = (uint32_t)len;
sh->user_addr = INVALID_MAP_ADDR;
sh->user_addr_ca = INVALID_MAP_ADDR;
atomic_set(&sh->usage, 0);
}
struct tc_ns_shared_mem *tc_mem_allocate(size_t len)
{
struct tc_ns_shared_mem *shared_mem = NULL;
void *addr = NULL;
shared_mem = kmalloc(sizeof(*shared_mem), GFP_KERNEL | __GFP_ZERO);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)shared_mem)) {
tloge("shared_mem kmalloc failed\n");
return ERR_PTR(-ENOMEM);
}
shared_mem->mem_type = VMALLOC_TYPE;
len = ALIGN(len, SZ_4K);
if (exist_res_mem()) {
if (len > get_res_mem_slice_size()) {
tloge("allocate reserved mem size too large\n");
kfree(shared_mem);
return ERR_PTR(-EINVAL);
}
addr = reserved_mem_alloc(len);
if (addr) {
shared_mem->mem_type = RESERVED_TYPE;
init_shared_mem(shared_mem, addr, len);
return shared_mem;
} else {
tlogw("no more reserved memory to alloc so we use system vmalloc.\n");
}
}
if (len > MAILBOX_POOL_SIZE) {
tloge("alloc sharemem size %zu is too large\n", len);
kfree(shared_mem);
return ERR_PTR(-EINVAL);
}
#ifndef CONFIG_LIBLINUX
addr = vmalloc_user(len);
#else
addr = kzalloc(len, GFP_KERNEL);
#endif
if (!addr) {
tloge("alloc mailbox failed\n");
kfree(shared_mem);
return ERR_PTR(-ENOMEM);
}
init_shared_mem(shared_mem, addr, len);
return shared_mem;
}
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: memory operation for gp sharedmem.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 MEM_H
#define MEM_H
#include <linux/types.h>
#include "teek_ns_client.h"
#define PRE_ALLOCATE_SIZE (1024*1024)
#define MEM_POOL_ELEMENT_SIZE (64*1024)
#define MEM_POOL_ELEMENT_NR (8)
#define MEM_POOL_ELEMENT_ORDER (4)
struct tc_ns_shared_mem *tc_mem_allocate(size_t len);
void tc_mem_free(struct tc_ns_shared_mem *shared_mem);
static inline void get_sharemem_struct(struct tc_ns_shared_mem *sharemem)
{
if (sharemem != NULL)
atomic_inc(&sharemem->usage);
}
static inline void put_sharemem_struct(struct tc_ns_shared_mem *sharemem)
{
if (sharemem != NULL) {
if (atomic_dec_and_test(&sharemem->usage))
tc_mem_free(sharemem);
}
}
#endif
+523
View File
@@ -0,0 +1,523 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: memory managering for reserved memory with TEE.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "reserved_mempool.h"
#include <linux/list.h>
#include <linux/sizes.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <securec.h>
#include <linux/vmalloc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <asm/io.h>
#include "teek_client_constants.h"
#include "tc_ns_log.h"
#include "smc_smp.h"
#define STATE_MODE 0440U
#define SLICE_RATE 4
#define MAX_SLICE 0x400000
#define MIN_RES_MEM_SIZE 0x400000
struct virt_page {
unsigned long start;
};
struct reserved_page_t {
struct list_head node;
struct virt_page *page;
int order;
unsigned int count; /* whether be used */
};
struct reserved_free_area_t {
struct list_head page_list;
int order;
};
struct reserved_zone_t {
struct virt_page *all_pages;
struct reserved_page_t *pages;
struct reserved_free_area_t free_areas[0];
};
static struct reserved_zone_t *g_res_zone;
static struct mutex g_res_lock;
static int g_res_max_order;
static unsigned long g_start_vaddr = 0;
static unsigned long g_start_paddr;
static struct dentry *g_res_mem_dbg_dentry;
static unsigned int g_res_mem_size = 0;
static unsigned int get_res_page_size(void)
{
return g_res_mem_size >> PAGE_SHIFT;
}
static unsigned int calc_res_mem_size(unsigned int rsize)
{
unsigned int size = rsize;
unsigned int idx = 0;
if (size == 0 || (size & (size - 1)) == 0)
return size;
while (size != 0) {
size = size >> 1;
idx++;
}
return (1 << (idx - 1));
}
unsigned int get_res_mem_slice_size(void)
{
unsigned int size = (g_res_mem_size >> SLICE_RATE);
return (size > MAX_SLICE) ? MAX_SLICE : size;
}
bool exist_res_mem(void)
{
return (g_start_vaddr != 0) && (g_res_mem_size != 0);
}
unsigned long res_mem_virt_to_phys(unsigned long vaddr)
{
return vaddr - g_start_vaddr + g_start_paddr;
}
int load_reserved_mem(void)
{
struct device_node *np = NULL;
struct resource r;
unsigned int res_size;
int rc;
void *p = NULL;
np = of_find_compatible_node(NULL, NULL, "tz_reserved");
if (np == NULL) {
tlogd("can not find reserved memory.\n");
return 0;
}
rc = of_address_to_resource(np, 0, &r);
if (rc != 0) {
tloge("of_address_to_resource error\n");
return -ENODEV;
}
res_size = (unsigned int)resource_size(&r);
if (res_size < MIN_RES_MEM_SIZE) {
tloge("reserved memory size is too small\n");
return -EINVAL;
}
p = ioremap(r.start, res_size);
if (p == NULL) {
tloge("io remap for reserved memory failed\n");
return -ENOMEM;
}
g_start_vaddr = (unsigned long)(uintptr_t)p;
g_start_paddr = (unsigned long)r.start;
g_res_mem_size = calc_res_mem_size(res_size);
return 0;
}
void unmap_res_mem(void)
{
if (exist_res_mem()) {
iounmap((void __iomem *)g_start_vaddr);
g_start_vaddr = 0;
g_res_mem_size = 0;
}
}
static int create_zone(void)
{
size_t zone_len;
g_res_max_order = get_order(g_res_mem_size);
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 (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 (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;
return -ENOMEM;
}
return 0;
}
static struct virt_page *create_virt_pages(void)
{
unsigned int i = 0;
struct virt_page *pages = NULL;
pages = kzalloc(get_res_page_size() * sizeof(struct virt_page), GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)pages)) {
tloge("alloc pages failed\n");
return NULL;
}
for (i = 0; i < get_res_page_size(); i++)
pages[i].start = g_start_vaddr + i * PAGE_SIZE;
return pages;
}
void free_reserved_mempool(void)
{
if (!exist_res_mem())
return;
if (g_res_zone->all_pages != NULL) {
kfree(g_res_zone->all_pages);
g_res_zone->all_pages = NULL;
}
if (g_res_zone->pages != NULL) {
kfree(g_res_zone->pages);
g_res_zone->pages = NULL;
}
if (g_res_zone != NULL) {
kfree(g_res_zone);
g_res_zone = NULL;
}
if (!g_res_mem_dbg_dentry)
return;
debugfs_remove_recursive(g_res_mem_dbg_dentry);
g_res_mem_dbg_dentry = NULL;
}
static void show_res_mem_info(void)
{
unsigned int i;
struct reserved_page_t *pos = NULL;
struct list_head *head = NULL;
unsigned int used = 0;
if (g_res_zone == NULL) {
tloge("res zone is NULL\n");
return;
}
tloge("################## reserved memory info ######################\n");
mutex_lock(&g_res_lock);
for (i = 0; i < get_res_page_size(); i++) {
if (g_res_zone->pages[i].count != 0) {
tloge("page[%02d], order=%02d, count=%d\n",
i, g_res_zone->pages[i].order,
g_res_zone->pages[i].count);
used += (1 << (uint32_t)g_res_zone->pages[i].order);
}
}
tloge("reserved memory total usage:%u/%u\n", used, get_res_page_size());
tloge("--------------------------------------------------------------\n");
for (i = 0; i < (unsigned int)g_res_max_order; i++) {
head = &g_res_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);
}
}
mutex_unlock(&g_res_lock);
tloge("#############################################################\n");
}
static ssize_t mb_res_mem_state_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
(void)(filp);
(void)(ubuf);
(void)cnt;
(void)(ppos);
show_res_mem_info();
return 0;
}
static const struct file_operations g_res_mem_dbg_state_fops = {
.owner = THIS_MODULE,
.read = mb_res_mem_state_read,
};
static void init_res_mem_dentry(void)
{
#ifdef DEF_ENG
g_res_mem_dbg_dentry = debugfs_create_dir("tz_res_mem", NULL);
debugfs_create_file("state", STATE_MODE, g_res_mem_dbg_dentry, NULL, &g_res_mem_dbg_state_fops);
#endif
}
static int res_mem_register(unsigned long paddr, unsigned int size)
{
struct tc_ns_operation *operation = NULL;
struct tc_ns_smc_cmd *smc_cmd = NULL;
int ret = 0;
smc_cmd = kzalloc(sizeof(*smc_cmd), GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)smc_cmd)) {
tloge("alloc smc_cmd failed\n");
return -ENOMEM;
}
operation = kzalloc(sizeof(*operation), GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)operation)) {
tloge("alloc operation failed\n");
ret = -ENOMEM;
goto free_smc_cmd;
}
operation->paramtypes = TEE_PARAM_TYPE_VALUE_INPUT |
(TEE_PARAM_TYPE_VALUE_INPUT << TEE_PARAM_NUM);
operation->params[0].value.a = paddr;
operation->params[0].value.b = paddr >> ADDR_TRANS_NUM;
operation->params[1].value.a = size;
smc_cmd->cmd_type = CMD_TYPE_GLOBAL;
smc_cmd->cmd_id = GLOBAL_CMD_ID_REGISTER_RESMEM;
smc_cmd->operation_phys = virt_to_phys(operation);
smc_cmd->operation_h_phys = virt_to_phys(operation) >> ADDR_TRANS_NUM;
if (tc_ns_smc(smc_cmd) != 0) {
tloge("resigter res mem failed\n");
ret = -EIO;
}
kfree(operation);
operation = NULL;
free_smc_cmd:
kfree(smc_cmd);
smc_cmd = NULL;
return ret;
}
static void zone_init(struct virt_page *all_pages)
{
int i;
struct reserved_free_area_t *area = NULL;
int max_order_cnt;
struct reserved_page_t *res_page = NULL;
for (i = 0; i < (int)get_res_page_size(); i++) {
g_res_zone->pages[i].order = -1;
g_res_zone->pages[i].count = 0;
g_res_zone->pages[i].page = &all_pages[i];
}
for (i = 0; i <= g_res_max_order; i++) {
area = &g_res_zone->free_areas[i];
INIT_LIST_HEAD(&area->page_list);
area->order = i;
}
max_order_cnt = (int)(get_res_page_size() / (1 << (unsigned int)g_res_max_order));
g_res_zone->all_pages = all_pages;
for (i = 0; i < max_order_cnt; i++) {
int idx = i * (1 << (unsigned int)g_res_max_order);
g_res_zone->pages[idx].order = g_res_max_order;
res_page = &g_res_zone->pages[idx];
list_add_tail(&res_page->node, &area->page_list);
}
}
int reserved_mempool_init(void)
{
struct virt_page *all_pages = NULL;
int ret = 0;
unsigned long paddr;
if (!exist_res_mem())
return 0;
ret = create_zone();
if (ret != 0)
return ret;
all_pages = create_virt_pages();
if (all_pages == NULL) {
kfree(g_res_zone->pages);
g_res_zone->pages = NULL;
kfree(g_res_zone);
g_res_zone = NULL;
return -ENOMEM;
}
paddr = g_start_paddr;
ret = res_mem_register(paddr, g_res_mem_size);
if (ret != 0) {
kfree(all_pages);
all_pages = NULL;
kfree(g_res_zone->pages);
g_res_zone->pages = NULL;
kfree(g_res_zone);
g_res_zone = NULL;
return -EIO;
}
zone_init(all_pages);
mutex_init(&g_res_lock);
init_res_mem_dentry();
return 0;
}
void *reserved_mem_alloc(size_t size)
{
int i, j;
struct reserved_page_t *pos = NULL;
struct list_head *head = NULL;
int order = get_order(ALIGN(size, SZ_4K));
unsigned long addr = 0;
bool valid_param = (size > 0 && order <= g_res_max_order && order >= 0);
if (!valid_param) {
tloge("invalid alloc param, size %d, order %d, max %d\n",(int)size, order, g_res_max_order);
return NULL;
}
mutex_lock(&g_res_lock);
for (i = order; i <= g_res_max_order; i++) {
head = &g_res_zone->free_areas[i].page_list;
if (list_empty(head) != 0)
continue;
pos = list_first_entry(head, struct reserved_page_t, node);
pos->count = 1;
pos->order = order;
for (j = order; j < i; j++) {
struct reserved_page_t *new_page = NULL;
new_page = pos + (1 << (unsigned int)j);
new_page->count = 0;
new_page->order = j;
list_add_tail(&new_page->node, &g_res_zone->free_areas[j].page_list);
}
list_del(&pos->node);
addr = pos->page->start;
break;
}
mutex_unlock(&g_res_lock);
return (void *)(uintptr_t)addr;
}
static int get_virt_page_index(const void *ptr)
{
unsigned long vaddr = (unsigned long)(uintptr_t)ptr;
unsigned long offset = vaddr - g_start_vaddr;
int pg_idx = offset / (1 << PAGE_SHIFT);
if ((unsigned int)pg_idx >= get_res_page_size() || pg_idx < 0)
return -1;
return pg_idx;
}
static int buddy_merge(struct virt_page *vpage, int order, unsigned int *page_index)
{
int i;
unsigned int cur_idx;
unsigned int buddy_idx;
struct reserved_page_t *self = NULL;
struct reserved_page_t *buddy = NULL;
for (i = order; i < g_res_max_order; i++) {
cur_idx = vpage - g_res_zone->all_pages;
buddy_idx = cur_idx ^ (1 << (unsigned int)i);
self = &g_res_zone->pages[cur_idx];
buddy = &g_res_zone->pages[buddy_idx];
self->count = 0;
/* is buddy free */
if (buddy->order == i && buddy->count == 0) {
/* release buddy */
list_del(&buddy->node);
/* combine self and buddy */
if (cur_idx > buddy_idx) {
vpage = buddy->page;
buddy->order = i + 1;
self->order = -1;
} else {
self->order = i + 1;
buddy->order = -1;
}
} else {
/* release self */
list_add_tail(&self->node,
&g_res_zone->free_areas[i].page_list);
return -1;
}
}
if (order == g_res_max_order) {
cur_idx = vpage - g_res_zone->all_pages;
tlogd("no need to find buddy, cur is %u\n", cur_idx);
*page_index = cur_idx;
return 0;
}
*page_index = (cur_idx > buddy_idx) ? buddy_idx : cur_idx;
return 0;
}
void reserved_mem_free(const void *ptr)
{
struct reserved_page_t *self = NULL;
int self_idx;
unsigned int page_index;
struct reserved_page_t *max_order_page = NULL;
if (ptr == NULL) {
tloge("invalid ptr\n");
return;
}
mutex_lock(&g_res_lock);
self_idx = get_virt_page_index(ptr);
if (self_idx < 0) {
mutex_unlock(&g_res_lock);
tloge("invalid page\n");
return;
}
self = &g_res_zone->pages[self_idx];
if (self->count == 0) {
tloge("already free in reserved mempool\n");
mutex_unlock(&g_res_lock);
return;
}
if (buddy_merge(self->page, self->order, &page_index) < 0) {
mutex_unlock(&g_res_lock);
return;
}
max_order_page = &g_res_zone->pages[page_index];
list_add_tail(&max_order_page->node,
&g_res_zone->free_areas[g_res_max_order].page_list);
mutex_unlock(&g_res_lock);
}
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: reserved memory managing for sharing memory with TEE.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 RESERVED_MEMPOOOL_H
#define RESERVED_MEMPOOOL_H
#include <linux/kernel.h>
#include <linux/types.h>
int load_reserved_mem(void);
void unmap_res_mem(void);
void *reserved_mem_alloc(size_t size);
void free_reserved_mempool(void);
int reserved_mempool_init(void);
void reserved_mem_free(const void *ptr);
bool exist_res_mem(void);
unsigned long res_mem_virt_to_phys(unsigned long vaddr);
unsigned int get_res_mem_slice_size(void);
#endif
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function declaration for secs power ctrl.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 SECS_POWER_CTRL_H
#define SECS_POWER_CTRL_H
#include <tc_ns_log.h>
#ifdef CONFIG_HISI_SECS_CTRL
#include <platform_include/see/secs_power_ctrl.h>
#define SECS_SUSPEND_STATUS 0xA5A5
unsigned long get_secs_suspend_status(void);
static int power_on_cc(void)
{
return hisi_secs_power_on();
}
static int power_down_cc(void)
{
return hisi_secs_power_down();
}
static void secs_suspend_status(uint64_t target)
{
if (get_secs_suspend_status() == SECS_SUSPEND_STATUS)
tloge("WARNING irq during suspend! No = %lld\n", target);
}
#else
static int power_on_cc(void)
{
return 0;
}
static int power_down_cc(void)
{
return 0;
}
static void secs_suspend_status(uint64_t target)
{
(void)target;
return;
}
#endif
#endif
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function declaration for session management.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 SESSION_MANAGER_H
#define SESSION_MANAGER_H
#include <linux/fs.h>
#include "tc_ns_client.h"
#include "teek_ns_client.h"
int tc_client_session_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
int tc_ns_open_session(struct tc_ns_dev_file *dev_file,
struct tc_ns_client_context *context);
int tc_ns_close_session(struct tc_ns_dev_file *dev_file,
struct tc_ns_client_context *context);
int tc_ns_send_cmd(struct tc_ns_dev_file *dev_file,
struct tc_ns_client_context *context);
int tc_ns_load_image(struct tc_ns_dev_file *dev, const char *file_buffer,
struct sec_file_info *sec_file_info, struct tc_ns_client_return *tee_ret);
int tc_ns_load_image_with_lock(struct tc_ns_dev_file *dev,
const char *file_buffer, unsigned int file_size, enum secfile_type_t type);
void close_unclosed_session_in_kthread(struct tc_ns_dev_file *dev);
struct tc_ns_session *tc_find_session_by_uuid(unsigned int dev_file_id,
const struct tc_ns_smc_cmd *cmd);
struct tc_ns_service *tc_find_service_in_dev(const struct tc_ns_dev_file *dev,
const unsigned char *uuid, int uuid_size);
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);
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);
void put_service_struct(struct tc_ns_service *service);
void get_session_struct(struct tc_ns_session *session);
void put_session_struct(struct tc_ns_session *session);
void dump_services_status(const char *param);
void init_srvc_list(void);
void free_all_session(void);
#endif
+406
View File
@@ -0,0 +1,406 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "shared_mem.h"
#include <securec.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <asm/io.h>
#include "tc_ns_log.h"
#include "tc_ns_client.h"
#include "teek_ns_client.h"
#include "smc_smp.h"
#include "internal_functions.h"
#include "mailbox_mempool.h"
#include "ko_adapt.h"
uint64_t get_reserved_cmd_vaddr_of(phys_addr_t cmd_phys, uint64_t cmd_size)
{
if (cmd_phys == 0 || cmd_size == 0) {
tloge("cmd phy or cmd size is error\n");
return 0;
}
uint64_t 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_SHARED_MEM_RESERVED
#define CMD_MEM_MIN_SIZE 0x1000
#define SPI_MEM_MIN_SIZE 0x1000
#define OPERATION_MEM_MIN_SIZE 0x1000
uint64_t g_cmd_mem_paddr;
uint64_t g_cmd_mem_size;
uint64_t g_mailbox_paddr;
uint64_t g_mailbox_size;
uint64_t g_log_mem_paddr;
uint64_t g_log_mem_size;
uint64_t g_spi_mem_paddr;
uint64_t g_spi_mem_size;
static mailbox_page_t *g_mailbox_page;
static uintptr_t g_shmem_start_virt;
static uintptr_t g_page_offset;
int load_tz_shared_mem(struct device_node *np)
{
int rc;
rc = of_property_read_u64(np, "tz_shmem_cmd_addr", &g_cmd_mem_paddr);
if (rc != 0) {
tloge("read tz_shmem_cmd_addr failed\n");
return -ENODEV;
}
rc = of_property_read_u64(np, "tz_shmem_cmd_size", &g_cmd_mem_size);
if (rc != 0 || g_cmd_mem_size < CMD_MEM_MIN_SIZE) {
tloge("read tz_shmem_cmd_size failed or size too short\n");
return -ENODEV;
}
rc = of_property_read_u64(np, "tz_shmem_mailbox_addr", &g_mailbox_paddr);
if (rc != 0) {
tloge("read tz_shmem_mailbox_addr failed\n");
return -ENODEV;
}
rc = of_property_read_u64(np, "tz_shmem_mailbox_size", &g_mailbox_size);
if (rc != 0 || g_mailbox_size < MAILBOX_POOL_SIZE + OPERATION_MEM_MIN_SIZE) {
tloge("read tz_shmem_mailbox_size failed or size too short\n");
return -ENODEV;
}
rc = of_property_read_u64(np, "tz_shmem_spi_addr", &g_spi_mem_paddr);
if (rc != 0) {
tloge("read tz_shmem_spi_addr failed\n");
return -ENODEV;
}
rc = of_property_read_u64(np, "tz_shmem_spi_size", &g_spi_mem_size);
if (rc != 0 || g_spi_mem_size < SPI_MEM_MIN_SIZE) {
tloge("read tz_shmem_spi_size failed or size too short\n");
return -ENODEV;
}
rc = of_property_read_u64(np, "tz_shmem_log_addr", &g_log_mem_paddr);
if (rc != 0) {
tloge("read tz_shmem_log_addr failed\n");
return -ENODEV;
}
rc = of_property_read_u64(np, "tz_shmem_log_size", &g_log_mem_size);
if (rc != 0 || g_log_mem_size < PAGES_LOG_MEM_LEN) {
tloge("read tz_shmem_log_size failed or size too short\n");
return -ENODEV;
}
return 0;
}
mailbox_page_t *mailbox_alloc_pages(int order)
{
uint32_t i;
uint32_t page_num = 1 << (unsigned int)order;
uint32_t page_size = page_num * sizeof(mailbox_page_t);
g_page_offset = MAILBOX_POOL_SIZE / page_num;
g_mailbox_page = kmalloc(page_size, GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)g_mailbox_page)) {
tloge("Failed to allocate mailbox page\n");
return NULL;
}
g_shmem_start_virt = (uintptr_t)ioremap_cache(g_mailbox_paddr, g_mailbox_size);
if (g_shmem_start_virt == 0) {
tloge("io remap for mailbox page failed\n");
kfree(g_mailbox_page);
g_mailbox_page = NULL;
return NULL;
}
(void)memset_s((void *)g_shmem_start_virt, g_mailbox_size, 0, g_mailbox_size);
g_mailbox_page[0] = (mailbox_page_t)g_shmem_start_virt;
for (i = 1; i < page_num; i++)
g_mailbox_page[i] = g_mailbox_page[i - 1] + g_page_offset;
return g_mailbox_page;
}
void mailbox_free_pages(mailbox_page_t *pages, int order)
{
if (!pages || pages != g_mailbox_page)
return;
(void)order;
kfree(pages);
g_mailbox_page = NULL;
}
uintptr_t mailbox_page_address(mailbox_page_t *page)
{
if (!page)
return 0;
return *page;
}
uintptr_t mailbox_virt_to_phys(uintptr_t addr)
{
if (addr < g_shmem_start_virt || addr > g_shmem_start_virt + g_mailbox_size)
return 0;
return g_mailbox_paddr + (addr - g_shmem_start_virt);
}
mailbox_page_t *mailbox_virt_to_page(uint64_t ptr)
{
if (ptr < g_shmem_start_virt || ptr > g_shmem_start_virt + g_mailbox_size)
return 0;
return &g_mailbox_page[(ptr - g_shmem_start_virt) / g_page_offset];
}
uint64_t get_operation_vaddr(void)
{
return g_shmem_start_virt + MAILBOX_POOL_SIZE;
}
void free_operation(uint64_t op_vaddr)
{
(void)op_vaddr;
}
/*
* This function only for wireless platform, CONFIG_LOG_POOL
* macro cnotrols the log retention of soft reset feature.
* Enable CONFIG_LOG_POOL macro, this function won't memset
* log pool memory, and the old log before reset can be retention.
*/
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);
if (log_vaddr == 0) {
tloge("ioremap for log buffer failed\n");
return 0;
}
#ifndef CONFIG_LOG_POOL
(void)memset_s((void *)(uintptr_t)log_vaddr, g_log_mem_size, 0, g_log_mem_size);
#endif
return log_vaddr;
}
uint64_t get_log_mem_paddr(uint64_t log_vaddr)
{
(void)log_vaddr;
return g_log_mem_paddr;
}
uint64_t get_log_mem_size(void)
{
return g_log_mem_size;
}
void free_log_mem(uint64_t log_vaddr)
{
iounmap((void __iomem*)(uintptr_t)log_vaddr);
}
uint64_t get_cmd_mem_vaddr(void)
{
return get_reserved_cmd_vaddr_of(g_cmd_mem_paddr, g_cmd_mem_size);
}
uint64_t get_cmd_mem_paddr(uint64_t cmd_vaddr)
{
(void)cmd_vaddr;
return g_cmd_mem_paddr;
}
void free_cmd_mem(uint64_t cmd_vaddr)
{
iounmap((void __iomem*)(uintptr_t)cmd_vaddr);
}
uint64_t get_spi_mem_vaddr(void)
{
uint64_t spi_vaddr = (uint64_t)(uintptr_t)ioremap_cache(g_spi_mem_paddr, g_spi_mem_size);
if (spi_vaddr == 0) {
tloge("io remap for spi buffer failed\n");
return 0;
}
(void)memset_s((void *)(uintptr_t)spi_vaddr, g_spi_mem_size, 0, g_spi_mem_size);
return spi_vaddr;
}
uint64_t get_spi_mem_paddr(uintptr_t spi_vaddr)
{
(void)spi_vaddr;
return g_spi_mem_paddr;
}
void free_spi_mem(uint64_t spi_vaddr)
{
iounmap((void __iomem*)(uintptr_t)spi_vaddr);
}
#else
int load_tz_shared_mem(struct device_node *np)
{
(void)np;
return 0;
}
mailbox_page_t *mailbox_alloc_pages(int order)
{
return koadpt_alloc_pages(GFP_KERNEL, order);
}
void mailbox_free_pages(mailbox_page_t *pages, int order)
{
if (!pages)
return;
__free_pages(pages, order);
}
uintptr_t mailbox_page_address(mailbox_page_t *page)
{
if (!page)
return 0;
return page_address(page);
}
uintptr_t mailbox_virt_to_phys(uintptr_t addr)
{
if (!addr)
return 0;
return virt_to_phys(addr);
}
mailbox_page_t *mailbox_virt_to_page(uint64_t ptr)
{
if (!ptr)
return NULL;
return virt_to_page(ptr);
}
uint64_t get_operation_vaddr(void)
{
return kzalloc(sizeof(struct tc_ns_operation), GFP_KERNEL);
}
void free_operation(uint64_t op_vaddr)
{
if (!op_vaddr)
return;
kfree(op_vaddr);
}
uint64_t get_log_mem_vaddr(void)
{
return __get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(PAGES_LOG_MEM_LEN));
}
uint64_t get_log_mem_paddr(uint64_t log_vaddr)
{
if (!log_vaddr)
return 0;
return virt_to_phys((void *)(uintptr_t)log_vaddr);
}
uint64_t get_log_mem_size(void)
{
return 0;
}
void free_log_mem(uint64_t log_vaddr)
{
if (!log_vaddr)
return;
free_pages(log_vaddr, get_order(PAGES_LOG_MEM_LEN));
}
#define PAGES_BIG_SESSION_CMD_LEN 6
uint64_t get_cmd_mem_vaddr(void)
{
#ifdef CONFIG_BIG_SESSION
/* we should map at least 64 pages for 1000 sessions, 2^6 > 40 */
return (uint64_t)__get_free_pages(GFP_KERNEL | __GFP_ZERO, PAGES_BIG_SESSION_CMD_LEN);
#else
return (uint64_t)__get_free_page(GFP_KERNEL | __GFP_ZERO);
#endif
}
uint64_t get_cmd_mem_paddr(uint64_t cmd_vaddr)
{
if (!cmd_vaddr)
return 0;
return virt_to_phys((void *)(uintptr_t)cmd_vaddr);
}
void free_cmd_mem(uint64_t cmd_vaddr)
{
if (!cmd_vaddr)
return;
#ifdef CONFIG_BIG_SESSION
free_pages(cmd_vaddr, PAGES_BIG_SESSION_CMD_LEN);
#else
free_page(cmd_vaddr);
#endif
}
uint64_t get_spi_mem_vaddr(void)
{
#ifdef CONFIG_BIG_SESSION
/* we should map at least 3 pages for 100 sessions, 2^2 > 3 */
return (uint64_t)__get_free_pages(GFP_KERNEL | __GFP_ZERO, CONFIG_NOTIFY_PAGE_ORDER);
#else
return (uint64_t)__get_free_page(GFP_KERNEL | __GFP_ZERO);
#endif
}
uint64_t get_spi_mem_paddr(uintptr_t spi_vaddr)
{
if (spi_vaddr == 0)
return 0;
return virt_to_phys((void *)spi_vaddr);
}
void free_spi_mem(uint64_t spi_vaddr)
{
if (!spi_vaddr)
return;
#ifdef CONFIG_BIG_SESSION
free_pages(spi_vaddr, CONFIG_NOTIFY_PAGE_ORDER);
#else
free_page(spi_vaddr);
#endif
}
#endif
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 SHARED_MEM_H
#define SHARED_MEM_H
#include <linux/types.h>
#include <linux/of.h>
#ifdef CONFIG_512K_LOG_PAGES_MEM
#define PAGES_LOG_MEM_LEN (512 * SZ_1K) /* mem size: 512 k */
#else
#define PAGES_LOG_MEM_LEN (256 * SZ_1K) /* mem size: 256 k */
#endif
#ifndef CONFIG_SHARED_MEM_RESERVED
typedef struct page mailbox_page_t;
#else
typedef uintptr_t mailbox_page_t;
#endif
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);
void mailbox_free_pages(mailbox_page_t *pages, int order);
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_log_mem_vaddr(void);
uint64_t get_log_mem_paddr(uint64_t log_vaddr);
uint64_t get_log_mem_size(void);
void free_log_mem(uint64_t log_vaddr);
uint64_t get_cmd_mem_vaddr(void);
uint64_t get_cmd_mem_paddr(uint64_t cmd_vaddr);
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);
#endif
+116
View File
@@ -0,0 +1,116 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 <linux/arm-smccc.h>
#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"
SMCCC_SMC_INST"\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"
SMCCC_SMC_INST"\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
#ifdef CONFIG_THIRDPARTY_COMPATIBLE
static void fix_params_offset(struct smc_out_params *out_param)
{
out_param->target = out_param->ta;
out_param->ta = out_param->exit_reason;
out_param->exit_reason = out_param->ret;
out_param->ret = TSP_RESPONSE;
if (out_param->exit_reason == TEE_EXIT_REASON_CRASH) {
union crash_inf temp_info;
temp_info.crash_reg[0] = out_param->ta;
temp_info.crash_reg[1] = 0;
temp_info.crash_reg[2] = out_param->target;
temp_info.crash_msg.far = temp_info.crash_msg.elr;
temp_info.crash_msg.elr = 0;
out_param->ret = TSP_CRASH;
out_param->exit_reason = temp_info.crash_reg[0];
out_param->ta = temp_info.crash_reg[1];
out_param->target = temp_info.crash_reg[2];
}
}
#endif
void smc_req(struct smc_in_params *in, struct smc_out_params *out, uint8_t wait)
{
do_smc_transport(in, out, wait);
#ifdef CONFIG_THIRDPARTY_COMPATIBLE
fix_params_offset(out);
#endif
}
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 <linux/types.h>
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
File diff suppressed because it is too large Load Diff
+153
View File
@@ -0,0 +1,153 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function declaration for sending smc cmd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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_SMP_H
#define SMC_SMP_H
#include <linux/of_device.h>
#include "teek_client_constants.h"
#include "teek_ns_client.h"
#if (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE)
#define CURRENT_CPUS_ALLOWED (&current->cpus_mask)
#else
#define CURRENT_CPUS_ALLOWED (&current->cpus_allowed)
#endif
enum tc_ns_cmd_type {
TC_NS_CMD_TYPE_INVALID = 0,
TC_NS_CMD_TYPE_NS_TO_SECURE,
TC_NS_CMD_TYPE_SECURE_TO_NS,
TC_NS_CMD_TYPE_SECURE_TO_SECURE,
TC_NS_CMD_TYPE_SECURE_CONFIG = 0xf,
TC_NS_CMD_TYPE_MAX
};
struct pending_entry {
atomic_t users;
struct task_struct *task;
#ifdef CONFIG_TA_AFFINITY
struct cpumask ca_mask;
struct cpumask ta_mask;
#endif
pid_t pid;
wait_queue_head_t wq;
atomic_t run;
struct list_head list;
};
#ifdef CONFIG_BIG_SESSION
#define MAX_SMC_CMD CONFIG_BIG_SESSION
#else
#define MAX_SMC_CMD 18
#endif
#ifdef DIV_ROUND_UP
#undef DIV_ROUND_UP
#endif
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8
#ifdef BITS_TO_LONGS
#undef BITS_TO_LONGS
#endif
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint64_t))
#ifdef BIT_MASK
#undef BIT_MASK
#endif
#define BIT_MASK(nr) (1UL << (((uint64_t)(nr)) % sizeof(uint64_t)))
#ifdef BIT_WORD
#undef BIT_WORD
#endif
#define BIT_WORD(nr) ((nr) / sizeof(uint64_t))
#ifdef DECLARE_BITMAP
#undef DECLARE_BITMAP
#endif
#define DECLARE_BITMAP(name, bits) uint64_t name[BITS_TO_LONGS(bits)]
#define SIQ_DUMP_TIMEOUT 1U
#define SIQ_DUMP_SHELL 2U
typedef uint32_t smc_buf_lock_t;
struct tc_ns_smc_queue {
/* set when CA send cmd_in, clear after cmd_out return */
DECLARE_BITMAP(in_bitmap, MAX_SMC_CMD);
/* set when gtask get cmd_in, clear after cmd_out return */
DECLARE_BITMAP(doing_bitmap, MAX_SMC_CMD);
/* set when gtask get cmd_out, clear after cmd_out return */
DECLARE_BITMAP(out_bitmap, MAX_SMC_CMD);
smc_buf_lock_t smc_lock;
volatile uint32_t last_in;
struct tc_ns_smc_cmd in[MAX_SMC_CMD];
volatile uint32_t last_out;
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);
int smc_context_init(const struct device *class_dev);
void free_smc_data(void);
int tc_ns_smc(struct tc_ns_smc_cmd *cmd);
int tc_ns_smc_with_no_nr(struct tc_ns_smc_cmd *cmd);
int teeos_log_exception_archive(unsigned int eventid, const char *exceptioninfo);
void set_cmd_send_state(void);
int init_smc_svc_thread(void);
int smc_wakeup_ca(pid_t ca);
int smc_wakeup_broadcast(void);
int smc_shadow_exit(pid_t ca);
int smc_queue_shadow_worker(uint64_t target);
void fiq_shadow_work_func(uint64_t target);
struct pending_entry *find_pending_entry(pid_t pid);
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);
#endif
File diff suppressed because it is too large Load Diff
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function declaration for proc open,close session and invoke.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TC_CLIENT_DRIVER_H
#define TC_CLIENT_DRIVER_H
#include <linux/list.h>
#include <linux/cdev.h>
#include "teek_ns_client.h"
struct dev_node {
struct class *driver_class;
struct cdev char_dev;
dev_t devt;
struct device *class_dev;
const struct file_operations *fops;
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);
#ifdef CONFIG_ACPI
int get_acpi_tz_irq(void);
#endif
#endif
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: check compatibility between tzdriver and tee.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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_compat_check.h"
#include <linux/types.h>
#include <linux/err.h>
#include "teek_ns_client.h"
#include "tc_ns_log.h"
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;
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]);
return -EPERM;
}
if (buffer[1] != major) {
tloge("check major ver failed, tzdriver expect teeos version=%u, actual teeos version=%u\n",
major, buffer[1]);
return -EPERM;
}
/* just print warning */
if (buffer[2] != minor)
tlogw("check minor ver failed, tzdriver expect teeos minor version=%u, actual minor teeos version=%u\n",
minor, buffer[2]);
return 0;
}
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: check compatibility between tzdriver and teeos.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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_COMPAT_CHECK_H
#define TEE_COMPAT_CHECK_H
#include <linux/types.h>
/*
* 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_MINOR 0
#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);
#endif
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function declaration for load app operations for kernel CA.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "teek_app_load.h"
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include "session_manager.h"
#include "ko_adapt.h"
static int32_t teek_open_app_file(struct file *fp, char **file_buf, uint32_t total_img_len)
{
loff_t pos = 0;
uint32_t read_size;
char *file_buffer = NULL;
if (total_img_len == 0 || total_img_len > MAX_IMAGE_LEN) {
tloge("img len is invalied %u\n", total_img_len);
return TEEC_ERROR_BAD_PARAMETERS;
}
file_buffer = vmalloc(total_img_len);
if (!file_buffer) {
tloge("alloc TA file buffer(size=%u) failed\n", total_img_len);
return TEEC_ERROR_GENERIC;
}
read_size = (uint32_t)kernel_read(fp, file_buffer, total_img_len, &pos);
if (read_size != total_img_len) {
tloge("read ta file failed, read size/total size=%u/%u\n", read_size, total_img_len);
vfree(file_buffer);
return TEEC_ERROR_GENERIC;
}
*file_buf = file_buffer;
return TEEC_SUCCESS;
}
static int32_t teek_read_app(const char *load_file, char **file_buf, uint32_t *file_len)
{
int32_t ret;
struct file *fp = NULL;
fp = filp_open(load_file, O_RDONLY, 0);
if (!fp || IS_ERR(fp)) {
tloge("open file error %ld\n", PTR_ERR(fp));
return TEEC_ERROR_BAD_PARAMETERS;
}
if (!fp->f_inode) {
tloge("node is NULL\n");
filp_close(fp, 0);
return TEEC_ERROR_BAD_PARAMETERS;
}
*file_len = (uint32_t)(fp->f_inode->i_size);
ret = teek_open_app_file(fp, file_buf, *file_len);
if (ret != TEEC_SUCCESS)
tloge("do read app fail\n");
if (fp != NULL) {
filp_close(fp, 0);
fp = NULL;
}
return ret;
}
void teek_free_app(bool load_app_flag, char **file_buf)
{
if (load_app_flag && file_buf != NULL && *file_buf != NULL) {
vfree(*file_buf);
*file_buf = NULL;
}
}
int32_t teek_get_app(const char *ta_path, char **file_buf, uint32_t *file_len)
{
int32_t ret;
/* ta path is NULL means no need to load TA */
if (!ta_path)
return TEEC_SUCCESS;
if (!file_buf || !file_len) {
tloge("load app params invalied\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
ret = teek_read_app(ta_path, file_buf, file_len);
if (ret != TEEC_SUCCESS)
tloge("teec load app error %d\n", ret);
return ret;
}
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function declaration for load app operations for kernel CA.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TEEK_APP_LOAD_H
#define TEEK_APP_LOAD_H
#include "teek_client_api.h"
#include "tc_ns_client.h"
#define MAX_IMAGE_LEN 0x800000 /* max image len */
int32_t teek_get_app(const char *ta_path, char **file_buf, uint32_t *file_len);
void teek_free_app(bool load_app_flag, char **file_buf);
#endif
+800
View File
@@ -0,0 +1,800 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function definition for libteec interface for kernel CA.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "teek_client_api.h"
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <asm/cacheflush.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/kernel.h>
#include <securec.h>
#include "tc_ns_log.h"
#include "tc_ns_client.h"
#include "gp_ops.h"
#include "internal_functions.h"
#include "session_manager.h"
#include "tc_client_driver.h"
#include "teek_app_load.h"
#include "dynamic_ion_mem.h"
static void encode_for_part_mem(struct tc_ns_client_context *context,
const struct teec_operation *oper, uint32_t idex, uint32_t *param_type)
{
uint32_t diff = (uint32_t)TEEC_MEMREF_PARTIAL_INPUT -
(uint32_t)TEEC_MEMREF_TEMP_INPUT;
uint64_t size_addr, buffer_addr;
if (idex >= TEE_PARAM_NUM)
return;
if (param_type[idex] == TEEC_MEMREF_WHOLE) {
context->params[idex].memref.offset = 0;
size_addr = (__u64)(uintptr_t)(&(oper->params[idex].memref.parent->size));
} else {
context->params[idex].memref.offset = oper->params[idex].memref.offset;
size_addr = (__u64)(uintptr_t)(&(oper->params[idex].memref.size));
}
context->params[idex].memref.size_addr = (__u32)size_addr;
context->params[idex].memref.size_h_addr = (__u32)(size_addr >> ADDR_TRANS_NUM);
if (oper->params[idex].memref.parent->is_allocated) {
buffer_addr = (__u64)(uintptr_t)oper->params[idex].memref.parent->buffer;
} else {
buffer_addr = (__u64)(uintptr_t)
oper->params[idex].memref.parent->buffer +
oper->params[idex].memref.offset;
context->params[idex].memref.offset = 0;
}
context->params[idex].memref.buffer = (__u32)buffer_addr;
context->params[idex].memref.buffer_h_addr = (__u32)(buffer_addr >> ADDR_TRANS_NUM);
/* translate the paramType to know the driver */
if (param_type[idex] == TEEC_MEMREF_WHOLE) {
switch (oper->params[idex].memref.parent->flags) {
case TEEC_MEM_INPUT:
param_type[idex] = TEEC_MEMREF_PARTIAL_INPUT;
break;
case TEEC_MEM_OUTPUT:
param_type[idex] = TEEC_MEMREF_PARTIAL_OUTPUT;
break;
case TEEC_MEM_INOUT:
param_type[idex] = TEEC_MEMREF_PARTIAL_INOUT;
break;
default:
param_type[idex] = TEEC_MEMREF_PARTIAL_INOUT;
break;
}
}
/* if not allocated, trans PARTIAL_XXX to MEMREF_TEMP_XXX */
if (!oper->params[idex].memref.parent->is_allocated)
param_type[idex] = param_type[idex] - diff;
}
static uint32_t proc_teek_encode(struct tc_ns_client_context *cli_context,
const struct teec_operation *operation)
{
uint32_t param_type[TEE_PARAM_NUM];
uint32_t idex;
uint64_t buffer_addr, size_addr, a_addr, b_addr;
param_type[0] =
teec_param_type_get(operation->paramtypes, 0);
param_type[1] =
teec_param_type_get(operation->paramtypes, 1);
param_type[2] =
teec_param_type_get(operation->paramtypes, 2);
param_type[3] =
teec_param_type_get(operation->paramtypes, 3);
for (idex = 0; idex < TEE_PARAM_NUM; idex++) {
if (is_tmp_mem(param_type[idex])) {
buffer_addr = (__u64)(uintptr_t)(operation->params[idex].tmpref.buffer);
size_addr = (__u64)(uintptr_t)(&operation->params[idex].tmpref.size);
cli_context->params[idex].memref.buffer = (__u32)buffer_addr;
cli_context->params[idex].memref.buffer_h_addr = (__u32)(buffer_addr >> ADDR_TRANS_NUM);
cli_context->params[idex].memref.size_addr = (__u32)size_addr;
cli_context->params[idex].memref.size_h_addr = (__u32)(size_addr >> ADDR_TRANS_NUM);
} else if (is_ref_mem(param_type[idex])) {
encode_for_part_mem(cli_context, operation,
idex, param_type);
} else if (is_val_param(param_type[idex])) {
a_addr = (__u64)(uintptr_t)(&(operation->params[idex].value.a));
b_addr = (__u64)(uintptr_t)(&(operation->params[idex].value.b));
cli_context->params[idex].value.a_addr = (__u32)a_addr;
cli_context->params[idex].value.a_h_addr = (__u32)(a_addr >> ADDR_TRANS_NUM);
cli_context->params[idex].value.b_addr = (__u32)b_addr;
cli_context->params[idex].value.b_h_addr = (__u32)(b_addr >> ADDR_TRANS_NUM);
} else if (is_ion_param(param_type[idex])) {
a_addr = (__u64)(uintptr_t)(&(operation->params[idex].ionref.ion_share_fd));
b_addr = (__u64)(uintptr_t)(&(operation->params[idex].ionref.ion_size));
cli_context->params[idex].value.a_addr = (__u32)a_addr;
cli_context->params[idex].value.a_h_addr = (__u32)(a_addr >> ADDR_TRANS_NUM);
cli_context->params[idex].value.b_addr = (__u32)b_addr;
cli_context->params[idex].value.b_h_addr = (__u32)(b_addr >> ADDR_TRANS_NUM);
} else if (param_type[idex] == TEEC_NONE) {
/* do nothing */
} else {
tloge("param_type[%u]=%u not correct\n", idex,
param_type[idex]);
return TEEC_ERROR_BAD_PARAMETERS;
}
}
cli_context->param_types = teec_param_types(param_type[0],
param_type[1], param_type[2], param_type[3]);
tlogv("cli param type %u\n", cli_context->param_types);
return TEEC_SUCCESS;
}
static uint32_t teek_init_context(struct tc_ns_client_context *cli_context,
struct teec_uuid service_id, uint32_t session_id, uint32_t cmd_id,
const struct tc_ns_client_login *cli_login)
{
uint32_t diff;
diff = (uint32_t)TEEC_MEMREF_PARTIAL_INPUT -
(uint32_t)TEEC_MEMREF_TEMP_INPUT;
if (memset_s(cli_context, sizeof(*cli_context),
0x00, sizeof(*cli_context)) != 0) {
tloge("memset error, init cli context failed\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
cli_context->returns.origin = TEEC_ORIGIN_COMMS;
if (memcpy_s(cli_context->uuid, sizeof(cli_context->uuid),
(uint8_t *)&service_id, sizeof(service_id)) != 0) {
tloge("memcpy error, init cli context failed\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
cli_context->session_id = session_id;
cli_context->cmd_id = cmd_id;
cli_context->returns.code = 0;
cli_context->login.method = cli_login->method;
cli_context->login.mdata = cli_login->mdata;
return TEEC_SUCCESS;
}
static uint32_t teek_check_tmp_mem(
const struct teec_tempmemory_reference *tmpref)
{
if (!tmpref->buffer || (tmpref->size == 0)) {
tloge("tmpref buffer is null, or size is zero\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
return TEEC_SUCCESS;
}
static bool is_partical_mem(uint32_t param_type)
{
if (param_type == TEEC_MEMREF_PARTIAL_INPUT ||
param_type == TEEC_MEMREF_PARTIAL_OUTPUT ||
param_type == TEEC_MEMREF_PARTIAL_INOUT)
return true;
return false;
}
static bool is_offset_invalid(
const struct teec_registeredmemory_reference *memref)
{
if ((memref->offset + memref->size > memref->parent->size) ||
(memref->offset + memref->size < memref->offset) ||
(memref->offset + memref->size < memref->size))
return true;
return false;
}
static uint32_t teek_check_ref_mem(
const struct teec_registeredmemory_reference *memref,
uint32_t param_type)
{
if (!memref->parent || !memref->parent->buffer) {
tloge("parent of memref is null, or the buffer is zero\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
if (param_type == TEEC_MEMREF_PARTIAL_INPUT) {
if ((memref->parent->flags & TEEC_MEM_INPUT) == 0)
return TEEC_ERROR_BAD_PARAMETERS;
} else if (param_type == TEEC_MEMREF_PARTIAL_OUTPUT) {
if ((memref->parent->flags & TEEC_MEM_OUTPUT) == 0)
return TEEC_ERROR_BAD_PARAMETERS;
} else if (param_type == TEEC_MEMREF_PARTIAL_INOUT) {
if ((memref->parent->flags & TEEC_MEM_INPUT) == 0)
return TEEC_ERROR_BAD_PARAMETERS;
if ((memref->parent->flags & TEEC_MEM_OUTPUT) == 0)
return TEEC_ERROR_BAD_PARAMETERS;
} else if (param_type == TEEC_MEMREF_WHOLE) {
/* if type is TEEC_MEMREF_WHOLE, ignore it */
} else {
return TEEC_ERROR_BAD_PARAMETERS;
}
if (is_partical_mem(param_type)) {
if (is_offset_invalid(memref)) {
tloge("offset + size exceed the parent size\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
}
return TEEC_SUCCESS;
}
/*
* This function checks a operation is valid or not.
*/
uint32_t teek_check_operation(const struct teec_operation *operation)
{
uint32_t param_type[TEE_PARAM_NUM] = {0};
uint32_t idex;
uint32_t ret = TEEC_SUCCESS;
/*
* GP Support operation is NULL
* operation: a pointer to a Client Application initialized struct,
* or NULL if there is no payload to send or
* if the Command does not need to support cancellation.
*/
if (!operation)
return TEEC_SUCCESS;
if (operation->started == 0) {
tloge("sorry, cancellation not support\n");
return TEEC_ERROR_NOT_IMPLEMENTED;
}
param_type[0] =
teec_param_type_get(operation->paramtypes, 0);
param_type[1] =
teec_param_type_get(operation->paramtypes, 1);
param_type[2] =
teec_param_type_get(operation->paramtypes, 2);
param_type[3] =
teec_param_type_get(operation->paramtypes, 3);
for (idex = 0; idex < TEE_PARAM_NUM; idex++) {
if (is_tmp_mem(param_type[idex])) {
ret = teek_check_tmp_mem(
&(operation->params[idex].tmpref));
if (ret != TEEC_SUCCESS)
break;
} else if (is_ref_mem(param_type[idex])) {
ret = teek_check_ref_mem(
&(operation->params[idex].memref),
param_type[idex]);
if (ret != TEEC_SUCCESS)
break;
} else if (is_val_param(param_type[idex])) {
/* do nothing */
} else if (is_ion_param(param_type[idex])) {
if (operation->params[idex].ionref.ion_share_fd < 0) {
tloge("ion_handle is invalid!\n");
ret = TEEC_ERROR_BAD_PARAMETERS;
break;
}
} else if (param_type[idex] == TEEC_NONE) {
/* do nothing */
} else {
tloge("paramType[%u]=%x is not support\n", idex,
param_type[idex]);
ret = TEEC_ERROR_BAD_PARAMETERS;
break;
}
}
return ret;
}
/*
* This function check if the special agent is launched.Used For HDCP key.
* e.g. If sfs agent is not alive, you can not do HDCP key write to SRAM.
*/
int teek_is_agent_alive(unsigned int agent_id)
{
return is_agent_alive(agent_id);
}
/*
* This function initializes a new TEE Context,
* forming a connection between this Client Application
* and the TEE identified by the string identifier name.
*/
uint32_t teek_initialize_context(const char *name,
struct teec_context *context)
{
int32_t ret;
/* name current not used */
(void)(name);
if (!get_tz_init_flag()) return (uint32_t)TEEC_ERROR_BUSY;
tlogd("teek_initialize_context Started:\n");
/* First, check parameters is valid or not */
if (!context) {
tloge("context is null, not correct\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
context->dev = NULL;
context->ta_path = NULL;
/* Paramters right, start execution */
ret = tc_ns_client_open((struct tc_ns_dev_file **)&context->dev,
TEE_REQ_FROM_KERNEL_MODE);
if (ret != TEEC_SUCCESS) {
tloge("open device failed\n");
return TEEC_ERROR_GENERIC;
}
tlogd("open device success\n");
return TEEC_SUCCESS;
}
EXPORT_SYMBOL(teek_initialize_context);
/*
* This function finalizes an initialized TEE 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");
return;
}
tlogd("close device\n");
tc_ns_client_close(context->dev);
context->dev = NULL;
}
EXPORT_SYMBOL(teek_finalize_context);
static bool is_oper_param_valid(const struct teec_operation *operation)
{
uint32_t param_type[TEE_PARAM_NUM] = {0};
param_type[3] =
teec_param_type_get(operation->paramtypes, 3);
param_type[2] =
teec_param_type_get(operation->paramtypes, 2);
if (param_type[3] != TEEC_MEMREF_TEMP_INPUT ||
param_type[2] != TEEC_MEMREF_TEMP_INPUT) {
tloge("invalid param type 0x%x\n", operation->paramtypes);
return false;
}
if (!operation->params[3].tmpref.buffer ||
!operation->params[2].tmpref.buffer ||
operation->params[3].tmpref.size == 0 ||
operation->params[2].tmpref.size == 0) {
tloge("invalid operation params(NULL)\n");
return false;
}
return true;
}
static uint32_t check_open_sess_params(struct teec_context *context,
const struct teec_operation *operation, const struct teec_uuid *destination,
uint32_t connection_method)
{
struct tc_ns_dev_file *dev_file = NULL;
uint32_t teec_ret;
if (!context || !operation || !destination ||
connection_method != TEEC_LOGIN_IDENTIFY) {
tloge("invalid input params\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
if (!is_oper_param_valid(operation))
return TEEC_ERROR_BAD_PARAMETERS;
dev_file = (struct tc_ns_dev_file *)(context->dev);
if (!dev_file) {
tloge("invalid context->dev (NULL)\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
dev_file->pkg_name_len = operation->params[3].tmpref.size;
if (operation->params[3].tmpref.size > MAX_PACKAGE_NAME_LEN - 1) {
return TEEC_ERROR_BAD_PARAMETERS;
} else {
if (memset_s(dev_file->pkg_name, sizeof(dev_file->pkg_name),
0, MAX_PACKAGE_NAME_LEN) != 0) {
tloge("memset error\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
if (memcpy_s(dev_file->pkg_name, sizeof(dev_file->pkg_name),
operation->params[3].tmpref.buffer,
operation->params[3].tmpref.size) != 0) {
tloge("memcpy error\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
}
dev_file->pub_key_len = 0;
dev_file->login_setup = 1;
teec_ret = teek_check_operation(operation);
if (teec_ret != TEEC_SUCCESS) {
tloge("operation is invalid\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
return teec_ret;
}
static uint32_t open_session_and_switch_ret(struct teec_session *session,
struct teec_context *context, const struct teec_uuid *destination,
struct tc_ns_client_context *cli_context, uint32_t *origin)
{
int32_t ret;
uint32_t teec_ret;
ret = tc_ns_open_session(context->dev, cli_context);
if (ret == 0) {
tlogd("open session success\n");
session->session_id = cli_context->session_id;
session->service_id = *destination;
session->ops_cnt = 0;
session->context = context;
return TEEC_SUCCESS;
} else if (ret < 0) {
tloge("open session failed, ioctl errno = %d\n", ret);
if (ret == -EFAULT)
teec_ret = TEEC_ERROR_ACCESS_DENIED;
else if (ret == -ENOMEM)
teec_ret = TEEC_ERROR_OUT_OF_MEMORY;
else if (ret == -EINVAL)
teec_ret = TEEC_ERROR_BAD_PARAMETERS;
else if (ret == -ERESTARTSYS)
teec_ret = TEEC_CLIENT_INTR;
else
teec_ret = TEEC_ERROR_GENERIC;
*origin = TEEC_ORIGIN_COMMS;
return teec_ret;
} else {
tloge("open session failed, code=0x%x, origin=%u\n",
cli_context->returns.code,
cli_context->returns.origin);
teec_ret = (uint32_t)cli_context->returns.code;
*origin = cli_context->returns.origin;
}
return teec_ret;
}
static uint32_t proc_teek_open_session(struct teec_context *context,
struct teec_session *session, const struct teec_uuid *destination,
uint32_t connection_method, const void *connection_data,
const struct teec_operation *operation, uint32_t *return_origin)
{
uint32_t teec_ret;
uint32_t origin = TEEC_ORIGIN_API;
struct tc_ns_client_context cli_context;
struct tc_ns_client_login cli_login = {0};
bool load_app_flag = false;
char *file_buffer = NULL;
/* connectionData current not used */
(void)(connection_data);
if (return_origin)
*return_origin = origin;
/* First, check parameters is valid or not */
if (!session) {
tloge("invalid session\n");
teec_ret = TEEC_ERROR_BAD_PARAMETERS;
goto set_ori;
}
/*
* ca may call closesession even if opensession failed,
* we set session->context here to avoid receive a illegal ptr,
* same as libteec_vendor
*/
session->context = context;
cli_login.method = TEEC_LOGIN_IDENTIFY;
teec_ret = check_open_sess_params(context, operation, destination, connection_method);
if (teec_ret != TEEC_SUCCESS)
goto set_ori;
teec_ret = teek_init_context(&cli_context, *destination, 0,
GLOBAL_CMD_ID_OPEN_SESSION, &cli_login);
if (teec_ret != TEEC_SUCCESS)
goto set_ori;
/* support when operation is null */
if (operation) {
cli_context.started = operation->cancel_flag;
teec_ret = proc_teek_encode(&cli_context, operation);
if (teec_ret != TEEC_SUCCESS)
goto set_ori;
}
teec_ret = (uint32_t)teek_get_app(context->ta_path, &file_buffer,
&cli_context.file_size);
if (teec_ret != TEEC_SUCCESS)
goto set_ori;
cli_context.memref.file_addr = (uint32_t)(uintptr_t)file_buffer;
cli_context.memref.file_h_addr = (uint32_t)(((uint64_t)(uintptr_t)file_buffer) >> ADDR_TRANS_NUM);
load_app_flag = true;
livepatch_down_read_sem();
teec_ret = open_session_and_switch_ret(session, context,
destination, &cli_context, &origin);
livepatch_up_read_sem();
set_ori:
if (teec_ret != TEEC_SUCCESS && return_origin != NULL)
*return_origin = origin;
teek_free_app(load_app_flag, &file_buffer);
return teec_ret;
}
#define RETRY_TIMES 5
uint32_t teek_open_session(struct teec_context *context,
struct teec_session *session, const struct teec_uuid *destination,
uint32_t connection_method, const void *connection_data,
const struct teec_operation *operation, uint32_t *return_origin)
{
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,
operation, return_origin);
if (ret != (uint32_t)TEEC_CLIENT_INTR)
return ret;
}
return ret;
}
EXPORT_SYMBOL(teek_open_session);
/*
* This function closes an opened Session.
*/
static bool is_close_sess_param_valid(const struct teec_session *session)
{
tlogd("teek_close_session started\n");
if (!session || !session->context || !session->context->dev) {
tloge("input invalid param\n");
return false;
}
return true;
}
void teek_close_session(struct teec_session *session)
{
int32_t ret;
struct tc_ns_client_context cli_context;
struct tc_ns_client_login cli_login = {0};
if (!get_tz_init_flag()) return;
if (!is_close_sess_param_valid(session))
return;
if (teek_init_context(&cli_context, session->service_id,
session->session_id, GLOBAL_CMD_ID_CLOSE_SESSION,
&cli_login) != TEEC_SUCCESS) {
tloge("init cli context failed just return\n");
return;
}
livepatch_down_read_sem();
ret = tc_ns_close_session(session->context->dev, &cli_context);
livepatch_up_read_sem();
if (ret == 0) {
session->session_id = 0;
if (memset_s((uint8_t *)(&session->service_id),
sizeof(session->service_id), 0x00, UUID_LEN) != 0)
tloge("memset error\n");
session->ops_cnt = 0;
session->context = NULL;
} else {
tloge("close session failed\n");
}
}
EXPORT_SYMBOL(teek_close_session);
static uint32_t proc_invoke_cmd(struct teec_session *session,
struct tc_ns_client_context *cli_context, uint32_t *origin)
{
int32_t ret;
uint32_t teec_ret;
livepatch_down_read_sem();
ret = tc_ns_send_cmd(session->context->dev, cli_context);
livepatch_up_read_sem();
if (ret == 0) {
tlogd("invoke cmd success\n");
teec_ret = TEEC_SUCCESS;
} else if (ret < 0) {
tloge("invoke cmd failed, ioctl errno = %d\n", ret);
if (ret == -EFAULT)
teec_ret = TEEC_ERROR_ACCESS_DENIED;
else if (ret == -ENOMEM)
teec_ret = TEEC_ERROR_OUT_OF_MEMORY;
else if (ret == -EINVAL)
teec_ret = TEEC_ERROR_BAD_PARAMETERS;
else
teec_ret = TEEC_ERROR_GENERIC;
*origin = TEEC_ORIGIN_COMMS;
} else {
tloge("invoke cmd failed, code=0x%x, origin=%d\n",
cli_context->returns.code,
cli_context->returns.origin);
teec_ret = (uint32_t)cli_context->returns.code;
*origin = cli_context->returns.origin;
}
return teec_ret;
}
/* This function invokes a Command within the specified Session. */
uint32_t teek_invoke_command(struct teec_session *session, uint32_t cmd_id,
struct teec_operation *operation, uint32_t *return_origin)
{
uint32_t teec_ret = TEEC_ERROR_BAD_PARAMETERS;
uint32_t origin = TEEC_ORIGIN_API;
struct tc_ns_client_context cli_context;
struct tc_ns_client_login cli_login = { 0, 0 };
if (!get_tz_init_flag()) return (uint32_t)TEEC_ERROR_BUSY;
/* First, check parameters is valid or not */
if (!session || !session->context) {
tloge("input invalid session or session->context is null\n");
goto set_ori;
}
teec_ret = teek_check_operation(operation);
if (teec_ret != 0) {
tloge("operation is invalid\n");
goto set_ori;
}
/* Paramters all right, start execution */
teec_ret = teek_init_context(&cli_context, session->service_id,
session->session_id, cmd_id, &cli_login);
if (teec_ret != 0) {
tloge("init cli context failed\n");
goto set_ori;
}
/* support when operation is null */
if (operation) {
cli_context.started = operation->cancel_flag;
teec_ret = proc_teek_encode(&cli_context, operation);
if (teec_ret != 0) {
goto set_ori;
}
}
teec_ret = proc_invoke_cmd(session, &cli_context, &origin);
set_ori:
if ((teec_ret != 0) && return_origin)
*return_origin = origin;
return teec_ret;
}
EXPORT_SYMBOL(teek_invoke_command);
uint32_t teek_send_secfile(struct teec_session *session,
const char *file_buffer, unsigned int file_size)
{
uint32_t ret;
if (!get_tz_init_flag()) return (uint32_t)TEEC_ERROR_BUSY;
if (!file_buffer || (file_size == 0) || !session ||
!session->context || !session->context->dev) {
tloge("params error!\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
livepatch_down_read_sem();
ret = (uint32_t)tc_ns_load_image_with_lock(session->context->dev,
file_buffer, file_size, LOAD_TA);
livepatch_up_read_sem();
return ret;
}
EXPORT_SYMBOL(teek_send_secfile);
TEEC_Result TEEK_SendSecfile(TEEC_Session *session,
const char *file_buffer, unsigned int file_size)
{
return (TEEC_Result)teek_send_secfile((struct teec_session *)session,
file_buffer, file_size);
}
EXPORT_SYMBOL(TEEK_SendSecfile);
/*
* This function registers a block of existing Client Application memory
* as a block of Shared Memory within the scope of the specified TEE Context.
*/
uint32_t teek_register_shared_memory(struct teec_context *context,
struct teec_sharedmemory *sharedmem)
{
(void)context;
(void)sharedmem;
tloge("teek_register_shared_memory not supported\n");
return TEEC_ERROR_NOT_SUPPORTED;
}
/* begin: for KERNEL-HAL out interface */
int TEEK_IsAgentAlive(unsigned int agent_id)
{
return teek_is_agent_alive(agent_id);
}
EXPORT_SYMBOL(TEEK_IsAgentAlive);
TEEC_Result TEEK_InitializeContext(const char *name, TEEC_Context *context)
{
return (TEEC_Result)teek_initialize_context(name,
(struct teec_context *)context);
}
EXPORT_SYMBOL(TEEK_InitializeContext);
void TEEK_FinalizeContext(TEEC_Context *context)
{
teek_finalize_context((struct teec_context *)context);
}
EXPORT_SYMBOL(TEEK_FinalizeContext);
/*
* Function: TEEK_OpenSession
* Description: This function opens a new Session
* Parameters: context: a pointer to an initialized TEE Context.
* session: a pointer to a Session structure to open.
* destination: a pointer to a UUID structure.
* connectionMethod: the method of connection to use.
* connectionData: any necessary data required to support the connection method chosen.
* operation: a pointer to an Operation containing a set of Parameters.
* returnOrigin: a pointer to a variable which will contain the return origin.
* Return: TEEC_SUCCESS: success other: failure
*/
TEEC_Result TEEK_OpenSession(TEEC_Context *context, TEEC_Session *session,
const TEEC_UUID *destination, uint32_t connectionMethod,
const void *connectionData, TEEC_Operation *operation,
uint32_t *returnOrigin)
{
return (TEEC_Result)teek_open_session(
(struct teec_context *)context, (struct teec_session *)session,
(const struct teec_uuid *)destination, connectionMethod, connectionData,
(struct teec_operation *)operation, returnOrigin);
}
EXPORT_SYMBOL(TEEK_OpenSession);
void TEEK_CloseSession(TEEC_Session *session)
{
teek_close_session((struct teec_session *)session);
}
EXPORT_SYMBOL(TEEK_CloseSession);
TEEC_Result TEEK_InvokeCommand(TEEC_Session *session, uint32_t commandID,
TEEC_Operation *operation, uint32_t *returnOrigin)
{
return (TEEC_Result)teek_invoke_command(
(struct teec_session *)session, commandID,
(struct teec_operation *)operation, returnOrigin);
}
EXPORT_SYMBOL(TEEK_InvokeCommand);
/* end: for KERNEL-HAL out interface */
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: exported funcs for teek client ext.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "teek_client_ext.h"
#include "smc_smp.h"
#include "mailbox_mempool.h"
#include "teek_client_constants.h"
#include "tz_update_crl.h"
#include "internal_functions.h"
#include "tc_client_driver.h"
#ifdef CONFIG_CMS_SIGNATURE
/* update crl */
uint32_t teek_update_crl(uint8_t *crl, uint32_t crl_len)
{
if (!get_tz_init_flag()) return EFAULT;
if (crl == NULL || crl_len == 0 || crl_len > DEVICE_CRL_MAX) {
tloge("bad params\n");
return -EINVAL;
}
livepatch_down_read_sem();
int ret = send_crl_to_tee(crl, crl_len, NULL);
livepatch_up_read_sem();
if (ret != 0)
tloge("update crl failed, ret %d\n", ret);
return ret;
}
EXPORT_SYMBOL(teek_update_crl);
#endif
+240
View File
@@ -0,0 +1,240 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function for proc open,close session and invoke.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "tz_pm.h"
#include <securec.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/dma-mapping.h>
#include <asm/cacheflush.h>
#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
#define RESERVED_SECOS_PHYMEM_SIZE (0x3000000)
#define RESERVED_SECOS_S4_BASE 0x27760000
#define RESERVED_SECOS_S4_SIZE (0x100000)
static char *g_s4_kernel_mem_addr;
static char *g_s4_buffer_vaddr;
static uint64_t g_s4_buffer_paddr;
static uint32_t g_s4_buffer_size;
static void *tc_vmap(phys_addr_t paddr, size_t size)
{
uint32_t i;
void *vaddr = NULL;
pgprot_t pgprot = PAGE_KERNEL;
uintptr_t offset;
uint32_t pages_count;
struct page **pages = NULL;
offset = paddr & ~PAGE_MASK;
paddr &= PAGE_MASK;
pages_count = (uint32_t)(PAGE_ALIGN(size + offset) / PAGE_SIZE);
pages = kzalloc(sizeof(struct page *) * pages_count, GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)pages))
return NULL;
for (i = 0; i < pages_count; i++)
*(pages + i) = phys_to_page((uintptr_t)(paddr + PAGE_SIZE * i));
vaddr = vmap(pages, pages_count, VM_MAP, pgprot);
kfree(pages);
if (vaddr == NULL)
return NULL;
return offset + (char *)vaddr;
}
static int tc_s4_alloc_crypto_buffer(struct device *dev,
char **kernel_mem_addr)
{
(void)dev;
if (RESERVED_SECOS_S4_BASE > S4_ADDR_4G) {
tloge("addr is invalid\n");
return -EFAULT;
}
g_s4_buffer_vaddr = tc_vmap(RESERVED_SECOS_S4_BASE, RESERVED_SECOS_S4_SIZE);
if (g_s4_buffer_vaddr == NULL) {
tloge("vmap failed for s4\n");
return -EFAULT;
}
g_s4_buffer_paddr = RESERVED_SECOS_S4_BASE;
g_s4_buffer_size = RESERVED_SECOS_S4_SIZE;
*kernel_mem_addr = vmalloc(RESERVED_SECOS_PHYMEM_SIZE);
if (*kernel_mem_addr == NULL) {
vunmap(g_s4_buffer_vaddr);
g_s4_buffer_paddr = 0;
g_s4_buffer_vaddr = NULL;
g_s4_buffer_size = 0;
tloge("vmalloc failed for s4\n");
return -ENOMEM;
}
return 0;
}
static void free_resource(const char *kernel_mem_addr)
{
vunmap(g_s4_buffer_vaddr);
vfree(kernel_mem_addr);
g_s4_kernel_mem_addr = NULL;
g_s4_buffer_paddr = 0;
g_s4_buffer_vaddr = NULL;
g_s4_buffer_size = 0;
}
static uint64_t tc_s4_suspend_or_resume(uint32_t power_op)
{
u64 smc_id = (u64)power_op;
u64 smc_ret = 0xffff;
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;
}
static uint64_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)
{
u64 smc_id = (u64)crypt_op;
u64 arg0 = (u64)middle_mem_addr;
u64 arg1 = (u64)secos_mem;
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 };
smc_req(&in_param, &out_param, 0);
smc_ret = out_param.ret;
return smc_ret;
}
static int tc_s4_transfer_data(char *kernel_mem_addr, uint32_t crypt_op)
{
uint32_t index = 0;
uint32_t copied_size = 0;
while (copied_size < RESERVED_SECOS_PHYMEM_SIZE) {
if (crypt_op == TSP_S4_DECRYPT_AND_COPY) {
if (memcpy_s(g_s4_buffer_vaddr, g_s4_buffer_size,
kernel_mem_addr + copied_size,
g_s4_buffer_size) != EOK) {
tloge("mem copy for decrypt failed\n");
return -EFAULT;
}
}
if (tc_s4_crypto_and_copy(crypt_op, g_s4_buffer_paddr,
RESERVED_SECOS_PHYMEM_BASE + copied_size,
g_s4_buffer_size, index) != 0) {
tloge("crypto and copy failed\n");
return -EFAULT;
}
if (crypt_op == TSP_S4_ENCRYPT_AND_COPY) {
if (memcpy_s(kernel_mem_addr + copied_size,
g_s4_buffer_size, g_s4_buffer_vaddr,
g_s4_buffer_size) != EOK) {
tloge("mem copy for encrypt failed\n");
return -EFAULT;
}
}
copied_size += g_s4_buffer_size;
index++;
}
return 0;
}
static int tc_s4_pm_ops(struct device *dev, uint32_t power_op,
uint32_t crypt_op, char *kernel_mem_addr)
{
int ret;
(void)dev;
if (power_op == TSP_S4_SUSPEND)
g_s4_kernel_mem_addr = kernel_mem_addr;
else
kernel_mem_addr = g_s4_kernel_mem_addr;
/* notify TEEOS to suspend all pm driver */
if (power_op == TSP_S4_SUSPEND) {
ret = (int)tc_s4_suspend_or_resume(power_op);
if (ret != 0) {
tloge("tc s4 suspend failed\n");
return ret;
}
}
ret = tc_s4_transfer_data(kernel_mem_addr, crypt_op);
if (ret != 0) {
tloge("transfer data failed, power_op=0x%x\n", power_op);
return ret;
}
/* notify TEEOS to resume all pm driver */
if (power_op == TSP_S4_RESUME) {
ret = (int)tc_s4_suspend_or_resume(power_op);
if (ret != 0) {
tloge("tc s4 resume failed\n");
return ret;
}
}
return 0;
}
int tc_s4_pm_suspend(struct device *dev)
{
int ret;
char *kernel_mem_addr = NULL;
ret = tc_s4_alloc_crypto_buffer(dev, &kernel_mem_addr);
if (ret != 0) {
tloge("alloc buffer failed\n");
return ret;
}
ret = tc_s4_pm_ops(dev, TSP_S4_SUSPEND, TSP_S4_ENCRYPT_AND_COPY, kernel_mem_addr);
if (ret != 0) {
free_resource(kernel_mem_addr);
tloge("s4 suspend failed\n");
}
return ret;
}
int tc_s4_pm_resume(struct device *dev)
{
int ret;
ret = tc_s4_pm_ops(dev, TSP_S4_RESUME, TSP_S4_DECRYPT_AND_COPY, g_s4_kernel_mem_addr);
if (ret != 0)
tloge("s4 resume failed\n");
free_resource(g_s4_kernel_mem_addr);
return ret;
}
+28
View File
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: suspend or freeze func declaration for tzdriver.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TZ_PM_H
#define TZ_PM_H
#include <linux/platform_device.h>
#define TSP_S4_SUSPEND 0xB200000C
#define TSP_S4_RESUME 0xB200000D
#define TSP_S4_ENCRYPT_AND_COPY 0xB2000010
#define TSP_S4_DECRYPT_AND_COPY 0xB2000011
int tc_s4_pm_suspend(struct device *dev);
int tc_s4_pm_resume(struct device *dev);
#endif
+731
View File
@@ -0,0 +1,731 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: exported funcs for spi interrupt actions.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "tz_spi_notify.h"
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <asm/cacheflush.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/of_reserved_mem.h>
#include <linux/atomic.h>
#include <linux/interrupt.h>
#include <securec.h>
#include "teek_client_constants.h"
#include "tc_ns_client.h"
#include "tc_ns_log.h"
#include "tc_client_driver.h"
#include "gp_ops.h"
#include "mailbox_mempool.h"
#include "smc_smp.h"
#include "session_manager.h"
#include "internal_functions.h"
#include "shared_mem.h"
#define DEFAULT_SPI_NUM 111
#define MAX_CALLBACK_COUNT 100
#define UUID_SIZE 16
struct teec_timer_property;
enum timer_class_type {
/* timer event using timer10 */
TIMER_GENERIC,
/* timer event using RTC */
TIMER_RTC
};
struct teec_timer_property {
unsigned int type;
unsigned int timer_id;
unsigned int timer_class;
unsigned int reserved2;
};
struct notify_context_timer {
unsigned int dev_file_id;
unsigned char uuid[UUID_SIZE];
unsigned int session_id;
struct teec_timer_property property;
uint32_t expire_time;
};
struct notify_context_wakeup {
pid_t ca_thread_id;
};
struct notify_context_shadow {
uint64_t target_tcb;
};
#ifdef CONFIG_TA_AFFINITY
#define AFF_BITS_SIZE 64
#define AFF_BITS_NUM ((CONFIG_TA_AFFINITY_CPU_NUMS % AFF_BITS_SIZE == 0) ? \
(CONFIG_TA_AFFINITY_CPU_NUMS / AFF_BITS_SIZE) : \
(CONFIG_TA_AFFINITY_CPU_NUMS / AFF_BITS_SIZE + 1))
#define aff_bits_mask(cpuid) \
(1LLU << (cpuid - (cpuid / AFF_BITS_SIZE) * AFF_BITS_SIZE))
struct aff_bits_t {
uint64_t aff_bits[AFF_BITS_NUM];
};
struct notify_context_set_affinity {
pid_t ca_thread_id;
struct aff_bits_t aff;
};
#endif
struct notify_context_stats {
uint32_t send_s;
uint32_t recv_s;
uint32_t send_w;
uint32_t recv_w;
#ifdef CONFIG_TA_AFFINITY
uint32_t send_af;
uint32_t recv_af;
#endif
uint32_t missed;
};
union notify_context {
struct notify_context_timer timer;
struct notify_context_wakeup wakeup;
struct notify_context_shadow shadow;
#ifdef CONFIG_TA_AFFINITY
struct notify_context_set_affinity affinity;
#endif
struct notify_context_stats meta;
};
#ifndef CONFIG_BIG_ENDIAN
struct notify_data_entry {
uint32_t entry_type : 31;
uint32_t filled : 1;
union notify_context context;
};
#else
struct notify_data_entry {
uint32_t resv;
uint32_t filled : 1;
uint32_t entry_type : 31;
union notify_context context;
};
#endif
#ifdef CONFIG_BIG_SESSION
#define NOTIFY_DATA_ENTRY_COUNT \
(((PAGE_SIZE * ((1U) << (CONFIG_NOTIFY_PAGE_ORDER))) \
/ sizeof(struct notify_data_entry)) - 1)
#else
#define NOTIFY_DATA_ENTRY_COUNT \
((PAGE_SIZE / sizeof(struct notify_data_entry)) - 1)
#endif
struct notify_data_struct {
struct notify_data_entry entry[NOTIFY_DATA_ENTRY_COUNT];
struct notify_data_entry meta;
};
static struct notify_data_struct *g_notify_data;
static struct notify_data_entry *g_notify_data_entry_shadow;
static spinlock_t g_notify_lock;
enum notify_data_type {
NOTIFY_DATA_ENTRY_UNUSED,
NOTIFY_DATA_ENTRY_TIMER,
NOTIFY_DATA_ENTRY_RTC,
NOTIFY_DATA_ENTRY_WAKEUP,
NOTIFY_DATA_ENTRY_SHADOW,
NOTIFY_DATA_ENTRY_FIQSHD,
NOTIFY_DATA_ENTRY_SHADOW_EXIT,
#ifdef CONFIG_TA_AFFINITY
NOTIFY_DATA_ENTRY_SET_AFFINITY,
#endif
NOTIFY_DATA_ENTRY_MAX,
};
struct tc_ns_callback {
unsigned char uuid[UUID_SIZE];
struct mutex callback_lock;
void (*callback_func)(void *);
struct list_head head;
};
struct tc_ns_callback_list {
unsigned int callback_count;
struct mutex callback_list_lock;
struct list_head callback_list;
};
static void tc_notify_fn(struct work_struct *dummy);
static struct tc_ns_callback_list g_ta_callback_func_list;
static DECLARE_WORK(tc_notify_work, tc_notify_fn);
static struct workqueue_struct *g_tz_spi_wq;
static void walk_callback_list(
struct notify_context_timer *tc_notify_data_timer)
{
struct tc_ns_callback *callback_func_t = NULL;
mutex_lock(&g_ta_callback_func_list.callback_list_lock);
list_for_each_entry(callback_func_t,
&g_ta_callback_func_list.callback_list, head) {
if (memcmp(callback_func_t->uuid, tc_notify_data_timer->uuid,
UUID_SIZE) != 0)
continue;
if (tc_notify_data_timer->property.timer_class ==
TIMER_RTC) {
tlogd("start to call callback func\n");
callback_func_t->callback_func(
&(tc_notify_data_timer->property));
tlogd("end to call callback func\n");
} else if (tc_notify_data_timer->property.timer_class ==
TIMER_GENERIC) {
tlogd("timer60 no callback func\n");
}
}
mutex_unlock(&g_ta_callback_func_list.callback_list_lock);
}
static int find_notify_sess(
const struct notify_context_timer *tc_notify_data_timer,
struct tc_ns_session **temp_ses, bool *enc_found)
{
struct tc_ns_dev_file *temp_dev_file = NULL;
struct tc_ns_dev_list *dev_list = NULL;
struct tc_ns_service *temp_svc = NULL;
dev_list = get_dev_list();
if (!dev_list) {
tloge("dev list is invalid\n");
return -ENOENT;
}
mutex_lock(&dev_list->dev_lock);
list_for_each_entry(temp_dev_file, &dev_list->dev_file_list, head) {
tlogd("dev file id1 = %u, id2 = %u\n",
temp_dev_file->dev_file_id,
tc_notify_data_timer->dev_file_id);
if (temp_dev_file->dev_file_id ==
tc_notify_data_timer->dev_file_id) {
mutex_lock(&temp_dev_file->service_lock);
temp_svc =
tc_find_service_in_dev(temp_dev_file,
tc_notify_data_timer->uuid, UUID_LEN);
get_service_struct(temp_svc);
mutex_unlock(&temp_dev_file->service_lock);
if (!temp_svc)
break;
mutex_lock(&temp_svc->session_lock);
*temp_ses =
tc_find_session_withowner(
&temp_svc->session_list,
tc_notify_data_timer->session_id,
temp_dev_file);
get_session_struct(*temp_ses);
mutex_unlock(&temp_svc->session_lock);
put_service_struct(temp_svc);
temp_svc = NULL;
if (*temp_ses) {
tlogd("send cmd ses id %u\n",
(*temp_ses)->session_id);
*enc_found = true;
break;
}
break;
}
}
mutex_unlock(&dev_list->dev_lock);
return 0;
}
static void tc_notify_timer_fn(struct notify_data_entry *notify_data_entry)
{
struct tc_ns_session *temp_ses = NULL;
bool enc_found = false;
struct notify_context_timer *tc_notify_data_timer = NULL;
tc_notify_data_timer = &(notify_data_entry->context.timer);
notify_data_entry->filled = 0;
tlogd("notify data timer type is 0x%x, timer ID is 0x%x\n",
tc_notify_data_timer->property.type,
tc_notify_data_timer->property.timer_id);
walk_callback_list(tc_notify_data_timer);
if (find_notify_sess(tc_notify_data_timer, &temp_ses, &enc_found) != 0)
return;
if (tc_notify_data_timer->property.timer_class == TIMER_GENERIC) {
tlogd("timer60 wake up event\n");
if (enc_found && temp_ses) {
temp_ses->wait_data.send_wait_flag = 1;
wake_up(&temp_ses->wait_data.send_cmd_wq);
put_session_struct(temp_ses);
temp_ses = NULL;
}
} else {
tlogd("RTC do not need to wakeup\n");
}
}
static noinline int get_notify_data_entry(struct notify_data_entry *copy)
{
uint32_t i;
int filled;
int ret = -1;
if (!copy || !g_notify_data) {
tloge("bad parameters or notify data is NULL");
return ret;
}
spin_lock(&g_notify_lock);
/* TIMER and RTC use fix entry, skip them. */
for (i = NOTIFY_DATA_ENTRY_UNUSED; i < NOTIFY_DATA_ENTRY_COUNT; i++) {
struct notify_data_entry *e = &g_notify_data->entry[i];
filled = e->filled;
smp_mb();
if (filled == 0)
continue;
switch (e->entry_type) {
case NOTIFY_DATA_ENTRY_TIMER:
case NOTIFY_DATA_ENTRY_RTC:
break;
case NOTIFY_DATA_ENTRY_SHADOW:
case NOTIFY_DATA_ENTRY_SHADOW_EXIT:
case NOTIFY_DATA_ENTRY_FIQSHD:
g_notify_data->meta.context.meta.recv_s++;
break;
case NOTIFY_DATA_ENTRY_WAKEUP:
g_notify_data->meta.context.meta.recv_w++;
break;
#ifdef CONFIG_TA_AFFINITY
case NOTIFY_DATA_ENTRY_SET_AFFINITY:
g_notify_data->meta.context.meta.recv_af++;
break;
#endif
default:
tloge("invalid notify type=%u\n", e->entry_type);
goto exit;
}
if (memcpy_s(copy, sizeof(*copy), e, sizeof(*e)) != EOK) {
tloge("memcpy entry failed\n");
break;
}
smp_mb();
e->filled = 0;
ret = 0;
break;
}
exit:
spin_unlock(&g_notify_lock);
return ret;
}
static void tc_notify_wakeup_fn(const struct notify_data_entry *entry)
{
const struct notify_context_wakeup *tc_notify_wakeup = NULL;
tc_notify_wakeup = &(entry->context.wakeup);
smc_wakeup_ca(tc_notify_wakeup->ca_thread_id);
tlogd("notify data entry wakeup ca: %d\n",
tc_notify_wakeup->ca_thread_id);
}
static void tc_notify_shadow_fn(const struct notify_data_entry *entry)
{
const struct notify_context_shadow *tc_notify_shadow = NULL;
tc_notify_shadow = &(entry->context.shadow);
smc_queue_shadow_worker(tc_notify_shadow->target_tcb);
}
static void tc_notify_fiqshd_fn(const struct notify_data_entry *entry)
{
const struct notify_context_shadow *tc_notify_shadow = NULL;
if (!entry) {
/* for NOTIFY_DATA_ENTRY_FIQSHD missed */
fiq_shadow_work_func(0);
return;
}
tc_notify_shadow = &(entry->context.shadow);
fiq_shadow_work_func(tc_notify_shadow->target_tcb);
}
static void tc_notify_shadowexit_fn(const struct notify_data_entry *entry)
{
const struct notify_context_wakeup *tc_notify_wakeup = NULL;
tc_notify_wakeup = &(entry->context.wakeup);
if (smc_shadow_exit(tc_notify_wakeup->ca_thread_id) != 0)
tloge("shadow ca exit failed: %d\n",
(int)tc_notify_wakeup->ca_thread_id);
}
#ifdef CONFIG_TA_AFFINITY
static void tc_notify_set_affinity(struct notify_data_entry *entry)
{
struct notify_context_set_affinity *af_data = NULL;
struct pending_entry *pe = NULL;
af_data = &(entry->context.affinity);
pe = find_pending_entry(af_data->ca_thread_id);
if (pe != NULL) {
struct cpumask mask;
uint32_t i;
cpumask_clear(&mask);
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);
}
/*
* we don't set ca's cpumask here but in ca's own thread
* context after ca is wakeup in smc_send_func, or
* scheduler will set task's allow cpumask failure in that case.
*/
cpumask_copy(&pe->ta_mask, &mask);
smc_wakeup_ca(af_data->ca_thread_id);
tlogd("set affinity for ca thread id %u\n", af_data->ca_thread_id);
put_pending_entry(pe);
} else {
tloge("invalid ca thread id %u for set affinity\n",
af_data->ca_thread_id);
/*
* if a TEE tcb without CA bind(CA is 0) cause a affinity set,
* the CA tid(current cpu context) may wrong
* (in tc_notify_fiqshd_fn, don't init_pending_entry,
* in this case, cannot find pending_entry),
* but we must set affinity for CA otherwise the TA can't run,
* so we wakeup all blocked CA.
*/
(void)smc_wakeup_broadcast();
}
}
#endif
#define MISSED_COUNT 4
static void spi_broadcast_notifications(void)
{
uint32_t missed;
smp_mb();
if (!g_notify_data) {
tloge("notify data is NULL\n");
return;
}
missed = (uint32_t)__xchg(0, &g_notify_data->meta.context.meta.missed, MISSED_COUNT);
if (missed == 0)
return;
if ((missed & (1U << NOTIFY_DATA_ENTRY_WAKEUP)) != 0) {
smc_wakeup_broadcast();
missed &= ~(1U << NOTIFY_DATA_ENTRY_WAKEUP);
}
if ((missed & (1U << NOTIFY_DATA_ENTRY_FIQSHD)) != 0) {
tc_notify_fiqshd_fn(NULL);
missed &= ~(1U << NOTIFY_DATA_ENTRY_FIQSHD);
}
if (missed != 0)
tloge("missed spi notification mask %x\n", missed);
}
static void tc_notify_fn(struct work_struct *dummy)
{
struct notify_data_entry copy = {0};
(void)dummy;
while (get_notify_data_entry(&copy) == 0) {
switch (copy.entry_type) {
case NOTIFY_DATA_ENTRY_TIMER:
case NOTIFY_DATA_ENTRY_RTC:
tc_notify_timer_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_WAKEUP:
tc_notify_wakeup_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_SHADOW:
tc_notify_shadow_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_FIQSHD:
tc_notify_fiqshd_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_SHADOW_EXIT:
tc_notify_shadowexit_fn(&copy);
break;
#ifdef CONFIG_TA_AFFINITY
case NOTIFY_DATA_ENTRY_SET_AFFINITY:
tc_notify_set_affinity(&copy);
break;
#endif
default:
tloge("invalid entry type = %u\n", copy.entry_type);
}
if (memset_s(&copy, sizeof(copy), 0, sizeof(copy)) != 0)
tloge("memset copy failed\n");
}
spi_broadcast_notifications();
}
static irqreturn_t tc_secure_notify(int irq, void *dev_id)
{
#define N_WORK 8
int i;
int queued = 0;
static struct work_struct tc_notify_works[N_WORK];
static int init;
(void)dev_id;
if (init == 0) {
for (i = 0; i < N_WORK; i++)
INIT_WORK(&tc_notify_works[i], tc_notify_fn);
init = 1;
}
for (i = 0; i < N_WORK; i++) {
if (queue_work(g_tz_spi_wq, &tc_notify_works[i])) {
queued = 1;
break;
}
}
if (queued == 1)
tee_trace_add_event(INTERRUPT_HANDLE_SPI_REE_RESPONSE, (uint64_t)irq);
else
tee_trace_add_event(INTERRUPT_HANDLE_SPI_REE_MISS, (uint64_t)irq);
#undef N_WORK
return IRQ_HANDLED;
}
int tc_ns_register_service_call_back_func(const char *uuid, void *func,
const void *private_data)
{
struct tc_ns_callback *callback_func = NULL;
struct tc_ns_callback *new_callback = NULL;
int ret = 0;
if (!uuid || !func)
return -EINVAL;
(void)private_data;
mutex_lock(&g_ta_callback_func_list.callback_list_lock);
if (g_ta_callback_func_list.callback_count > MAX_CALLBACK_COUNT) {
mutex_unlock(&g_ta_callback_func_list.callback_list_lock);
tloge("callback_count is out\n");
return -ENOMEM;
}
list_for_each_entry(callback_func,
&g_ta_callback_func_list.callback_list, head) {
if (memcmp(callback_func->uuid, uuid, UUID_SIZE) == 0) {
callback_func->callback_func = (void (*)(void *))func;
tlogd("succeed to find uuid ta_callback_func_list\n");
goto find_callback;
}
}
/* create a new callback struct if we couldn't find it in list */
new_callback = kzalloc(sizeof(*new_callback), GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)new_callback)) {
tloge("kzalloc failed\n");
ret = -ENOMEM;
goto find_callback;
}
if (memcpy_s(new_callback->uuid, UUID_SIZE, uuid, UUID_SIZE) != 0) {
kfree(new_callback);
new_callback = NULL;
ret = -ENOMEM;
goto find_callback;
}
g_ta_callback_func_list.callback_count++;
tlogd("callback count is %u\n",
g_ta_callback_func_list.callback_count);
INIT_LIST_HEAD(&new_callback->head);
new_callback->callback_func = (void (*)(void *))func;
mutex_init(&new_callback->callback_lock);
list_add_tail(&new_callback->head,
&g_ta_callback_func_list.callback_list);
find_callback:
mutex_unlock(&g_ta_callback_func_list.callback_list_lock);
return ret;
}
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 send_notify_cmd(unsigned int cmd_id)
{
struct tc_ns_smc_cmd smc_cmd = { {0}, 0 };
int ret = 0;
struct mb_cmd_pack *mb_pack = NULL;
mb_pack = mailbox_alloc_cmd_pack();
if (!mb_pack)
return -ENOMEM;
mb_pack->operation.paramtypes =
TEE_PARAM_TYPE_VALUE_INPUT |
TEE_PARAM_TYPE_VALUE_INPUT << TEE_PARAM_NUM;
mb_pack->operation.params[0].value.a =
(unsigned int)(get_spi_mem_paddr((uintptr_t)g_notify_data));
mb_pack->operation.params[0].value.b =
(unsigned int)(get_spi_mem_paddr((uintptr_t)g_notify_data) >> ADDR_TRANS_NUM);
mb_pack->operation.params[1].value.a = SZ_4K;
smc_cmd.cmd_type = CMD_TYPE_GLOBAL;
smc_cmd.cmd_id = cmd_id;
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);
if (is_tee_rebooting())
ret = send_smc_cmd_rebooting(TSP_REQUEST, 0, 0, &smc_cmd);
else
ret = tc_ns_smc(&smc_cmd);
if (ret != 0) {
ret = -EPERM;
tloge("register notify mem failed\n");
}
mailbox_free(mb_pack);
return ret;
}
static unsigned int g_irq = DEFAULT_SPI_NUM;
static int config_spi_context(struct device *class_dev, struct device_node *np)
{
int ret;
#ifndef CONFIG_ACPI
if (!np) {
tloge("device node not found\n");
return -EINVAL;
}
#endif
/* Map IRQ 0 from the OF interrupts list */
#ifdef CONFIG_ACPI
g_irq = (unsigned int)get_acpi_tz_irq();
#else
g_irq = irq_of_parse_and_map(np, 0);
#endif
ret = devm_request_irq(class_dev, g_irq, tc_secure_notify,
IRQF_NO_SUSPEND, TC_NS_CLIENT_DEV, NULL);
if (ret < 0) {
tloge("device irq %u request failed %d", g_irq, ret);
return ret;
}
g_ta_callback_func_list.callback_count = 0;
INIT_LIST_HEAD(&g_ta_callback_func_list.callback_list);
mutex_init(&g_ta_callback_func_list.callback_list_lock);
return 0;
}
int tz_spi_init(struct device *class_dev, struct device_node *np)
{
int ret;
if (!class_dev) /* here np can be NULL */
return -EINVAL;
spin_lock_init(&g_notify_lock);
g_tz_spi_wq = alloc_workqueue("g_tz_spi_wq",
WQ_UNBOUND | WQ_HIGHPRI, TZ_WQ_MAX_ACTIVE);
if (!g_tz_spi_wq) {
tloge("it failed to create workqueue g_tz_spi_wq\n");
return -ENOMEM;
}
tz_workqueue_bind_mask(g_tz_spi_wq, WQ_HIGHPRI);
ret = config_spi_context(class_dev, np);
if (ret != 0)
goto clean;
if (!g_notify_data) {
g_notify_data = (struct notify_data_struct *)(uintptr_t)get_spi_mem_vaddr();
if (!g_notify_data) {
tloge("get free page failed for notification data\n");
ret = -ENOMEM;
goto clean;
}
ret = send_notify_cmd(GLOBAL_CMD_ID_REGISTER_NOTIFY_MEMORY);
if (ret != 0) {
tloge("shared memory failed ret is 0x%x\n", ret);
ret = -EFAULT;
free_spi_mem((uint64_t)(uintptr_t)g_notify_data);
g_notify_data = NULL;
goto clean;
}
g_notify_data_entry_shadow =
&g_notify_data->entry[NOTIFY_DATA_ENTRY_SHADOW - 1];
tlogd("target is: %llx\n",
g_notify_data_entry_shadow->context.shadow.target_tcb);
}
return 0;
clean:
free_tz_spi(class_dev);
return ret;
}
void free_tz_spi(struct device *class_dev)
{
if (g_notify_data) {
free_spi_mem((uint64_t)(uintptr_t)g_notify_data);
g_notify_data = NULL;
}
if (g_tz_spi_wq) {
flush_workqueue(g_tz_spi_wq);
destroy_workqueue(g_tz_spi_wq);
g_tz_spi_wq = NULL;
}
if (!class_dev)
return;
devm_free_irq(class_dev, g_irq, NULL);
}
+24
View File
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: exported funcs for spi interrupt actions.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TZ_SPI_NOTIFY_H
#define TZ_SPI_NOTIFY_H
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include "teek_ns_client.h"
int tz_spi_init(struct device *class_dev, struct device_node *np);
void free_tz_spi(struct device *class_dev);
int send_notify_cmd(unsigned int cmd_id);
#endif
+209
View File
@@ -0,0 +1,209 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function for update crl.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "tz_update_crl.h"
#include <linux/namei.h>
#include <linux/dcache.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include "mailbox_mempool.h"
#include "smc_smp.h"
#define D_PATH_LEN 256
static DEFINE_MUTEX(g_cms_crl_update_lock);
int send_crl_to_tee(const char *crl_buffer, uint32_t crl_len, const struct tc_ns_dev_file *dev_file)
{
int ret;
struct tc_ns_smc_cmd smc_cmd = { {0}, 0 };
struct mb_cmd_pack *mb_pack = NULL;
char *mb_param = NULL;
/* dev_file not need check null */
if (crl_buffer == NULL || crl_len == 0 || crl_len > DEVICE_CRL_MAX) {
tloge("invalid params\n");
return -EINVAL;
}
mb_pack = mailbox_alloc_cmd_pack();
if (!mb_pack) {
tloge("alloc mb pack failed\n");
return -ENOMEM;
}
mb_param = mailbox_copy_alloc(crl_buffer, crl_len);
if (!mb_param) {
tloge("alloc mb param failed\n");
ret = -ENOMEM;
goto clean;
}
mb_pack->operation.paramtypes = TEEC_MEMREF_TEMP_INPUT;
mb_pack->operation.params[0].memref.buffer = (unsigned int )mailbox_virt_to_phys((uintptr_t)mb_param);
mb_pack->operation.buffer_h_addr[0] =
(unsigned int)((uint64_t)mailbox_virt_to_phys((uintptr_t)mb_param) >> ADDR_TRANS_NUM);
mb_pack->operation.params[0].memref.size = crl_len;
smc_cmd.cmd_id = GLOBAL_CMD_ID_UPDATE_TA_CRL;
smc_cmd.cmd_type = CMD_TYPE_GLOBAL;
if (dev_file != NULL)
smc_cmd.dev_file_id = dev_file->dev_file_id;
smc_cmd.context_id = 0;
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);
mutex_lock(&g_cms_crl_update_lock);
ret = tc_ns_smc(&smc_cmd);
mutex_unlock(&g_cms_crl_update_lock);
if (ret != 0)
tloge("smc call returns error ret 0x%x\n", ret);
clean:
mailbox_free(mb_pack);
mb_pack = NULL;
if (mb_param)
mailbox_free(mb_param);
return ret;
}
int tc_ns_update_ta_crl(const struct tc_ns_dev_file *dev_file, void __user *argp)
{
int ret;
struct tc_ns_client_crl context = {0};
void *buffer_addr = NULL;
uint8_t *crl_buffer = NULL;
if (!dev_file || !argp) {
tloge("invalid params\n");
return -EINVAL;
}
if (copy_from_user(&context, argp, sizeof(context)) != 0) {
tloge("copy from user failed\n");
return -ENOMEM;
}
if (context.size > DEVICE_CRL_MAX) {
tloge("crl size is too long\n");
return -ENOMEM;
}
crl_buffer = kmalloc(context.size, GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)(crl_buffer))) {
tloge("failed to allocate crl buffer\n");
return -ENOMEM;
}
buffer_addr = (void *)(uintptr_t)(context.memref.buffer_addr |
(((uint64_t)context.memref.buffer_h_addr) << ADDR_TRANS_NUM));
if (copy_from_user(crl_buffer, buffer_addr, context.size) != 0) {
tloge("copy from user failed\n");
goto clean;
}
ret = send_crl_to_tee(crl_buffer, context.size, dev_file);
if (ret != 0) {
tloge("send crl to tee failed\n");
goto clean;
}
clean:
kfree(crl_buffer);
return ret;
}
static struct file *crl_file_open(const char *file_path)
{
struct file *fp = NULL;
int ret;
char *dpath = NULL;
char tmp_buf[D_PATH_LEN] = {0};
struct path base_path = {
.mnt = NULL,
.dentry = NULL
};
ret = kern_path(file_path, LOOKUP_FOLLOW, &base_path);
if (ret != 0)
return NULL;
dpath = d_path(&base_path, tmp_buf, D_PATH_LEN);
if (!dpath || IS_ERR(dpath))
goto clean;
fp = filp_open(dpath, O_RDONLY, 0);
clean:
path_put(&base_path);
return fp;
}
int tz_update_crl(const char *file_path, const struct tc_ns_dev_file *dev_file)
{
struct file *fp = NULL;
uint32_t crl_len;
char *crl_buffer = NULL;
uint32_t read_size;
loff_t pos = 0;
int ret = 0;
if (!dev_file || !file_path) {
tloge("invalid params\n");
return -EINVAL;
}
fp = crl_file_open(file_path);
if (!fp || IS_ERR(fp)) {
tloge("open crl file error, ret = %ld\n", PTR_ERR(fp));
return -ENOENT;
}
if (!fp->f_inode) {
tloge("node is NULL\n");
ret = -EINVAL;
goto clean;
}
crl_len = (uint32_t)(fp->f_inode->i_size);
if (crl_len > DEVICE_CRL_MAX) {
tloge("crl file len is invalid %u\n", crl_len);
ret = -EINVAL;
goto clean;
}
crl_buffer = vmalloc(crl_len);
if (!crl_buffer) {
tloge("alloc crl file buffer(size=%u) failed\n", crl_len);
ret = -ENOMEM;
goto clean;
}
read_size = (uint32_t)kernel_read(fp, crl_buffer, crl_len, &pos);
if (read_size != crl_len) {
tloge("read crl file failed, read size/total size=%u/%u\n", read_size, crl_len);
ret = -ENOENT;
goto clean;
}
ret = send_crl_to_tee(crl_buffer, crl_len, dev_file);
if (ret != 0) {
tloge("send crl to tee failed\n");
goto clean;
}
clean:
filp_close(fp, 0);
fp = NULL;
if (crl_buffer)
vfree(crl_buffer);
return ret;
}
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: function for update crl.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TZ_UPDATE_CRL_H
#define TZ_UPDATE_CRL_H
#include "teek_ns_client.h"
#define DEVICE_CRL_MAX 0x4000 /* 16KB */
int send_crl_to_tee(const char *crl_buffer, uint32_t crl_len, const struct tc_ns_dev_file *dev_file);
int tc_ns_update_ta_crl(const struct tc_ns_dev_file *dev_file, void __user *argp);
int tz_update_crl(const char *file_path, const struct tc_ns_dev_file *dev_file);
#endif
+458
View File
@@ -0,0 +1,458 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: for tzdriver debug.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <stdarg.h>
#include <linux/mm.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
#include <securec.h>
#include <asm/io.h>
#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 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 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
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 <linux/types.h>
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
+1
View File
@@ -0,0 +1 @@
ion/dynamic_ion_mem.h
+112
View File
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2012-2022 Huawei Technologies Co., Ltd.
* Description: tzdriver internal functions.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 INTERNAL_FUNCTIONS_H
#define INTERNAL_FUNCTIONS_H
#include <linux/device.h>
#include <securec.h>
#include "teek_ns_client.h"
#include "teek_client_constants.h"
#ifndef CONFIG_TEE_FAULT_MANAGER
static inline void fault_monitor_start(int32_t type)
{
(void)type;
return;
}
static inline void fault_monitor_end(void)
{
return;
}
#endif
#ifdef CONFIG_KTHREAD_AFFINITY
#include "tz_kthread_affinity.h"
#else
static inline void init_kthread_cpumask(void)
{
}
static inline void tz_kthread_bind_mask(struct task_struct *kthread)
{
(void)kthread;
}
static inline void tz_workqueue_bind_mask(struct workqueue_struct *wq,
uint32_t flag)
{
(void)wq;
(void)flag;
}
#endif
#ifdef CONFIG_LIVEPATCH_ENABLE
#include "livepatch_cmd.h"
#else
static inline int livepatch_init(const struct device *dev)
{
(void)dev;
return 0;
}
static inline void livepatch_down_read_sem(void)
{
}
static inline void livepatch_up_read_sem(void)
{
}
static inline void free_livepatch(void)
{
}
#endif
#ifdef CONFIG_TEE_TRACE
#include "tee_trace_event.h"
#include "tee_trace_interrupt.h"
#else
static inline void tee_trace_add_event(enum tee_event_id id, uint64_t add_info)
{
(void)id;
(void)add_info;
}
static inline void free_event_mem(void)
{
}
static inline void free_interrupt_trace(void)
{
}
#endif
#ifdef CONFIG_TEE_REBOOT
#include "reboot.h"
#else
static inline bool is_tee_rebooting(void)
{
return false;
}
static inline int tee_init_reboot_thread(void)
{
return 0;
}
static inline int tee_wake_up_reboot(void)
{
return 0;
}
static inline void free_reboot_thread(void)
{
return;
}
#endif
#endif
+13
View File
@@ -0,0 +1,13 @@
config DYNAMIC_ION
bool "Dynamic Ion Feature"
default n
depends on TZDRIVER
help
TEEOS dynamic ion
config STATIC_ION
bool "Static Ion Feature"
default n
depends on TZDRIVER
help
TEEOS static ion
+20
View File
@@ -0,0 +1,20 @@
KERNEL_DIR :=$(srctree)
ifneq ($(TARGET_BUILD_VARIANT),user)
ccflags-y += -DDEF_ENG
endif
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/staging/android
obj-$(CONFIG_STATIC_ION) += static_ion_mem.o
obj-$(CONFIG_DYNAMIC_ION) += dynamic_ion_mem.o
ifneq ($(CONFIG_MTK_PLATFORM), )
obj-$(CONFIG_STATIC_ION) += mplat/declare_static_ion.o
else
obj-$(CONFIG_STATIC_ION) += generic/declare_static_ion.o
endif
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/include
EXTRA_CFLAGS += -include internal_functions.h
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2012-2022 Huawei Technologies Co., Ltd.
* Description: set static mem info.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 DECLARE_STATIC_ION_H
#define DECLARE_STATIC_ION_H
#include "static_ion_mem.h"
void set_ion_mem_info(struct register_ion_mem_tag *memtag);
#endif
+653
View File
@@ -0,0 +1,653 @@
/*
* Copyright (c) 2012-2022 Huawei Technologies Co., Ltd.
* Description: dynamic Ion memory allocation and free.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "dynamic_ion_mem.h"
#include <stdarg.h>
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/version.h>
#ifndef CONFIG_DMABUF_MM
#include <linux/ion.h>
#endif
#include <linux/mm.h>
#include <linux/cma.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
#if ((defined CONFIG_ION_MM) || (defined CONFIG_ION_MM_SECSG))
#include <linux/ion/mm_ion.h>
#endif
#ifdef CONFIG_DMABUF_MM
#include <linux/dmabuf/mm_dma_heap.h>
#endif
#include "tc_ns_log.h"
#include "tc_ns_client.h"
#include "smc_smp.h"
#include "gp_ops.h"
#include "teek_client_constants.h"
#include "mailbox_mempool.h"
#include "dynamic_ion_uuid.h"
static DEFINE_MUTEX(dynamic_mem_lock);
struct dynamic_mem_list {
struct list_head list;
};
static const struct dynamic_mem_config g_dyn_mem_config[] = {
#ifdef DEF_ENG
{TEE_SERVICE_UT, SEC_EID},
{TEE_SERVICE_TEST_DYNION, SEC_AI_ION},
#endif
{TEE_SECIDENTIFICATION1, SEC_EID},
{TEE_SECIDENTIFICATION3, SEC_EID},
{TEE_SERVICE_AI, SEC_AI_ION},
{TEE_SERVICE_AI_TINY, SEC_AI_ION},
{TEE_SERVICE_VCODEC, SEC_DRM_TEE},
};
static struct dynamic_mem_list g_dynamic_mem_list;
static const uint32_t g_dyn_mem_config_num = ARRAY_SIZE(g_dyn_mem_config);
static int release_ion_srv(const struct tc_uuid *uuid)
{
struct tc_ns_smc_cmd smc_cmd = {{0}, 0};
smc_cmd.err_origin = TEEC_ORIGIN_COMMS;
smc_cmd.cmd_type = CMD_TYPE_GLOBAL;
smc_cmd.cmd_id = GLOBAL_CMD_ID_RELEASE_ION_SRV;
if (memcpy_s(&smc_cmd.uuid, sizeof(smc_cmd.uuid), uuid, sizeof(*uuid))) {
tloge("copy uuid failed\n");
return -ENOMEM;
}
if (tc_ns_smc(&smc_cmd)) {
tloge("send release ion srv cmd failed\n");
return -EPERM;
}
return 0;
}
static int get_ion_sglist(struct dynamic_mem_item *mem_item)
{
struct sglist *tmp_sglist = NULL;
struct scatterlist *sg = NULL;
struct page *page = NULL;
uint32_t sglist_size;
uint32_t i = 0;
struct sg_table *ion_sg_table = mem_item->memory.dyn_sg_table;
if (!ion_sg_table)
return -EINVAL;
if (ion_sg_table->nents <= 0 || ion_sg_table->nents > MAX_ION_NENTS)
return -EINVAL;
for_each_sg(ion_sg_table->sgl, sg, ion_sg_table->nents, i) {
if (!sg) {
tloge("an error sg when get ion sglist\n");
return -EINVAL;
}
}
sglist_size = sizeof(struct ion_page_info) * ion_sg_table->nents + sizeof(*tmp_sglist);
tmp_sglist = (struct sglist *)mailbox_alloc(sglist_size, MB_FLAG_ZERO);
if (!tmp_sglist) {
tloge("mailbox alloc failed\n");
return -ENOMEM;
}
tmp_sglist->sglist_size = (uint64_t)sglist_size;
tmp_sglist->ion_size = (uint64_t)mem_item->size;
tmp_sglist->info_length = (uint64_t)ion_sg_table->nents;
for_each_sg(ion_sg_table->sgl, sg, ion_sg_table->nents, i) {
page = sg_page(sg);
tmp_sglist->page_info[i].phys_addr = page_to_phys(page);
tmp_sglist->page_info[i].npages = sg->length / PAGE_SIZE;
}
mem_item->memory.ion_phys_addr = mailbox_virt_to_phys((uintptr_t)(void *)tmp_sglist);
mem_item->memory.len = sglist_size;
return 0;
}
static int send_dyn_ion_cmd(struct dynamic_mem_item *mem_item, unsigned int cmd_id, int32_t *ret_origin)
{
struct tc_ns_smc_cmd smc_cmd = {{0}, 0};
int ret;
struct mb_cmd_pack *mb_pack = NULL;
if (!mem_item) {
tloge("mem_item is null\n");
return -EINVAL;
}
ret = get_ion_sglist(mem_item);
if (ret != 0)
return ret;
mb_pack = mailbox_alloc_cmd_pack();
if (!mb_pack) {
mailbox_free(phys_to_virt(mem_item->memory.ion_phys_addr));
tloge("alloc cmd pack failed\n");
return -ENOMEM;
}
smc_cmd.cmd_type = CMD_TYPE_GLOBAL;
smc_cmd.cmd_id = cmd_id;
smc_cmd.err_origin = TEEC_ORIGIN_COMMS;
mb_pack->operation.paramtypes = teec_param_types(
TEE_PARAM_TYPE_ION_SGLIST_INPUT,
TEE_PARAM_TYPE_VALUE_INPUT,
TEE_PARAM_TYPE_VALUE_INPUT,
TEE_PARAM_TYPE_NONE);
mb_pack->operation.params[0].memref.size = (uint32_t)mem_item->memory.len;
mb_pack->operation.params[0].memref.buffer =
(uint32_t)(mem_item->memory.ion_phys_addr & 0xFFFFFFFF);
mb_pack->operation.buffer_h_addr[0] =
(uint64_t)(mem_item->memory.ion_phys_addr) >> ADDR_TRANS_NUM;
mb_pack->operation.params[1].value.a = (uint32_t)mem_item->size;
mb_pack->operation.params[2].value.a = mem_item->configid;
smc_cmd.operation_phys = (unsigned int)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation);
smc_cmd.operation_h_phys = (uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM;
if (tc_ns_smc(&smc_cmd)) {
if (ret_origin)
*ret_origin = smc_cmd.err_origin;
ret = -EPERM;
tlogd("send loadapp ion failed\n");
}
mailbox_free(phys_to_virt(mem_item->memory.ion_phys_addr));
mailbox_free(mb_pack);
return ret;
}
static struct dynamic_mem_item *find_memitem_by_configid_locked(uint32_t configid)
{
struct dynamic_mem_item *item = NULL;
list_for_each_entry(item, &g_dynamic_mem_list.list, head) {
if (item->configid == configid)
return item;
}
return NULL;
}
static struct dynamic_mem_item *find_memitem_by_uuid_locked(const struct tc_uuid *uuid)
{
struct dynamic_mem_item *item = NULL;
list_for_each_entry(item, &g_dynamic_mem_list.list, head) {
if (!memcmp(&item->uuid, uuid, sizeof(*uuid)))
return item;
}
return NULL;
}
#define BLOCK_64KB_SIZE (64 * 1024) /* 64 */
#define BLOCK_64KB_MASK 0xFFFFFFFFFFFF0000
/* size should be aligned with 64KB */
#define BLOCK_64KB_SIZE_MASK (BLOCK_64KB_SIZE -1)
static int proc_alloc_dyn_mem(struct dynamic_mem_item *mem_item)
{
struct sg_table *ion_sg_table = NULL;
if (mem_item->size + BLOCK_64KB_SIZE_MASK < mem_item->size) {
tloge("ion size is error, size = %x\n", mem_item->size);
return -EINVAL;
}
mem_item->memory.len = (mem_item ->size + BLOCK_64KB_SIZE_MASK) & BLOCK_64KB_MASK;
ion_sg_table = mm_secmem_alloc(mem_item->addr_sec_region,
mem_item->memory.len);
if (!ion_sg_table) {
tloge("failed to get ion page, configid = %d\n",
mem_item->configid);
return -ENOMEM;
}
mem_item->memory.dyn_sg_table = ion_sg_table;
return 0;
}
static void proc_free_dyn_mem(struct dynamic_mem_item *mem_item)
{
if (!mem_item->memory.dyn_sg_table) {
tloge("ion_phys_addr is NULL\n");
return;
}
mm_secmem_free(mem_item->ddr_sec_region,
mem_item->memory.dyn_sg_table);
mem_item->memory.dyn_sg_table = NULL;
return;
}
int init_dynamic_mem(void)
{
INIT_LIST_HEAD(&(g_dynamic_mem_list.list));
return 0;
}
static int32_t find_ddr_sec_region_by_uuid(const struct tc_uuid *uuid,
uint32_t *ddr_sec_region)
{
uint32_t i;
for (i = 0; i < g_dyn_mem_config_num; i++) {
if (!memcmp(&(g_dyn_mem_config[i].uuid), uuid,
sizeof(*uuid))) {
*ddr_sec_region = g_dyn_mem_config[i].ddr_sec_region;
return 0;
}
}
return -EINVAL;
}
static struct dynamic_mem_item *alloc_dyn_mem_item(uint32_t configid,
uint32_t cafd, const struct tc_uuid *uuid, uint32_t size)
{
uint32_t ddr_sec_region;
struct dynamic_mem_item *mem_item = NULL;
int32_t result;
result = find_ddr_sec_region_by_uuid(uuid, &ddr_sec_region);
if (result != 0) {
tloge("find ddr sec region failed\n");
return NULL;
}
mem_item = kzalloc(sizeof(*mem_item), GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)mem_item)) {
tloge("alloc mem item failed\n");
return NULL;
}
mem_item->ddr_sec_region = ddr_sec_region;
mem_item->configid = configid;
mem_item->size = size;
mem_item->cafd = cafd;
result = memcpy_s(&mem_item->uuid, sizeof(mem_item->uuid), uuid,
sizeof(*uuid));
if(result != EOK) {
tloge("memcpy uuid failed\n");
kfree(mem_item);
return NULL;
}
return mem_item;
}
static int trans_configid2memid(uint32_t configid, uint32_t cafd,
const struct tc_uuid *uuid, uint32_t size, int32_t *ret_origin)
{
int result;
if (!uuid)
return -EINVAL;
mutex_lock(&dynamic_mem_lock);
do {
struct dynamic_mem_item *mem_item =
find_memitem_by_configid_locked(configid);
if (mem_item) {
result = -EINVAL;
break;
}
mem_item = alloc_dyn_mem_item(configid, cafd, uuid, size);
if (!mem_item) {
tloge("alloc dyn mem item failed\n");
result = -ENOMEM;
break;
}
result = proc_alloc_dyn_mem(mem_item);
if (result != 0) {
tloge("alloc dyn mem failed , ret = %d\n", result);
kfree(mem_item);
break;
}
/* register to tee */
result = send_dyn_ion_cmd(mem_item, GLOBAL_CMD_ID_ADD_DYNAMIC_ION, ret_origin);
if (result != 0) {
tloge("register to tee failed, result = %d\n", result);
proc_free_dyn_mem(mem_item);
kfree(mem_item);
break;
}
list_add_tail(&mem_item->head, &g_dynamic_mem_list.list);
tloge("log import:alloc ion configid=%d\n",
mem_item->configid);
} while (0);
mutex_unlock(&dynamic_mem_lock);
return result;
}
static void release_configid_mem_locked(uint32_t configid)
{
int result;
/* if config id is memid map, and can reuse */
do {
struct dynamic_mem_item *mem_item =
find_memitem_by_configid_locked(configid);
if (!mem_item) {
tloge("fail to find memitem by configid\n");
break;
}
result = send_dyn_ion_cmd(mem_item, GLOBAL_CMD_ID_DEL_DYNAMIC_ION, NULL);
if (result != 0) {
tloge("unregister_from_tee configid=%d, result =%d\n",
mem_item->configid, result);
break;
}
proc_free_dyn_mem(mem_item);
list_del(&mem_item->head);
kfree(mem_item);
tloge("log import: free ion\n");
} while (0);
return;
}
int load_app_use_configid(uint32_t configid, uint32_t cafd,
const struct tc_uuid *uuid, uint32_t size, int32_t *ret_origin)
{
int result;
if (!uuid)
return -EINVAL;
result = trans_configid2memid(configid, cafd, uuid, size, ret_origin);
if (result != 0) {
tloge("trans_configid2memid failed ret = %d\n", result);
if (release_ion_srv(uuid) != 0)
tloge("release ion srv failed\n");
}
return result;
}
void kill_ion_by_uuid(const struct tc_uuid *uuid)
{
if (!uuid) {
tloge("uuid is null\n");
return;
}
mutex_lock(&dynamic_mem_lock);
do {
struct dynamic_mem_item *mem_item =
find_memitem_by_uuid_locked(uuid);
if (!mem_item)
break;
tlogd("kill ION by UUID\n");
release_configid_mem_locked(mem_item->configid);
} while (0);
mutex_unlock(&dynamic_mem_lock);
}
void kill_ion_by_cafd(unsigned int cafd)
{
struct dynamic_mem_item *item = NULL;
struct dynamic_mem_item *temp = NULL;
tlogd("kill_ion_by_cafd:\n");
mutex_lock(&dynamic_mem_lock);
list_for_each_entry_safe(item, temp, &g_dynamic_mem_list.list, head) {
if (item->cafd == cafd)
release_configid_mem_locked(item->configid);
}
mutex_unlock(&dynamic_mem_lock);
}
int load_image_for_ion(const struct load_img_params *params, int32_t *ret_origin)
{
int ret = 0;
if (!params)
return -EFAULT;
/* check need to add ionmem */
uint32_t configid = params->mb_pack->operation.params[1].value.a;
uint32_t ion_size = params->mb_pack->operation.params[1].value.b;
int32_t check_result = (configid != 0 && ion_size != 0);
tloge("check load result=%d, cfgid=%d, ion_size=%d, uuid=%x\n",
check_result, configid, ion_size, params->uuid_return->time_low);
if (check_result) {
ret = load_app_use_configid(configid, params->dev_file->dev_file_id,
params->uuid_return, ion_size ret_origin);
if (ret != 0) {
tloge("load app use configid failed ret=%d\n", ret);
return -EFAULT;
}
}
return ret;
}
bool is_ion_param(uint32_t param_type)
{
if (param_type == TEEC_ION_INPUT ||
param_type == TEEC_ION_SGLIST_INPUT)
return true;
return false;
}
static void fill_sg_list(struct sg_table *ion_table,
uint32_t ion_list_num, struct sglist *tmp_sglist)
{
uint32_t i;
struct page *page = NULL;
struct scatterlist *sg = NULL;
for_each_sg(ion_table->sgl, sg, ion_list_num, i) {
page = sg_page(sg);
tmp_sglist->page_info[i].phys_addr = page_to_phys(page);
tmp_sglist->page_info[i].npages = sg->length / PAGE_SIZE;
}
}
static int check_sg_list(const struct sg_table *ion_table, uint32_t ion_list_num)
{
struct scatterlist *sg = NULL;
uint32_t i;
for_each_sg(ion_table->sgl, sg, ion_list_num, i) {
if (!sg) {
tloge("an error sg when get ion sglist \n");
return -EFAULT;
}
}
return 0;
}
static int get_ion_sg_list_from_fd(uint32_t ion_shared_fd,
uint32_t ion_alloc_size, phys_addr_t *sglist_table,
size_t *ion_sglist_size)
{
struct sg_table *ion_table = NULL;
struct sglist *tmp_sglist = NULL;
uint64_t ion_id = 0;
enum SEC_SVC ion_type = 0;
uint32_t ion_list_num = 0;
uint32_t sglist_size;
#ifdef CONFIG_DMABUF_MM
if (mm_dma_heap_secmem_get_buffer(ion_shared_fd, &ion_table, &ion_id, &ion_type)) {
#else
if (secmem_get_buffer(ion_shared_fd, &ion_table, &ion_id, &ion_type)) {
#endif
tloge("get ion table failed. \n");
return -EFAULT;
}
if (ion_type != SEC_DRM_TEE) {
if (ion_table->nents <= 0 || ion_table->nents > MAX_ION_NENTS)
return -EFAULT;
ion_list_num = (uint32_t)(ion_table->nents & INT_MAX);
if (check_sg_list(ion_table, ion_list_num) != 0)
return -EFAULT;
}
/* ion_list_num is less than 1024, so sglist_size won't flow */
sglist_size = sizeof(struct ion_page_info) * ion_list_num + sizeof(*tmp_sglist);
tmp_sglist = (struct sglist *)mailbox_alloc(sglist_size, MB_FLAG_ZERO);
if (!tmp_sglist) {
tloge("sglist mem alloc failed\n");
return -ENOMEM;
}
tmp_sglist->sglist_size = (uint64_t)sglist_size;
tmp_sglist->ion_size = (uint64_t)ion_alloc_size;
tmp_sglist->info_length = (uint64_t)ion_list_num;
if (ion_type != SEC_DRM_TEE)
fill_sg_list(ion_table, ion_list_num, tmp_sglist);
else
tmp_sglist->ion_id = ion_id;
*sglist_table = mailbox_virt_to_phys((uintptr_t)tmp_sglist);
*ion_sglist_size = sglist_size;
return 0;
}
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)
{
struct tc_ns_operation *operation = NULL;
size_t ion_sglist_size = 0;
phys_addr_t ion_sglist_addr = 0x0;
union tc_ns_client_param *client_param = NULL;
unsigned int ion_shared_fd = 0;
unsigned int ion_alloc_size;
uint64_t a_addr, b_addr;
/* this never happens */
if (index >= TEE_PARAM_NUM || !call_params || !op_params)
return -EINVAL;
operation = &op_params->mb_pack->operation;
client_param = &(call_params->context->params[index]);
a_addr = client_param->value.a_addr |
((uint64_t)client_param->value.a_h_addr << ADDR_TRANS_NUM);
b_addr = client_param->value.b_addr |
((uint64_t)client_param->value.b_h_addr << ADDR_TRANS_NUM);
if (read_from_client(&operation->params[index].value.a,
sizeof(operation->params[index].value.a),
(void *)(uintptr_t)a_addr,
sizeof(operation->params[index].value.a), kernel_params)) {
tloge("valuea copy failed\n");
return -EFAULT;
}
if (read_from_client(&operation->params[index].value.b,
sizeof(operation->params[index].value.b),
(void *)(uintptr_t)b_addr,
sizeof(operation->params[index].value.b), kernel_params)) {
tloge("valueb copy failed\n");
return -EFAULT;
}
ion_shared_fd = operation->params[index].value.a;
ion_alloc_size = operation->params[index].value.b;
if(get_ion_sg_list_from_fd(ion_shared_fd, ion_alloc_size,
&ion_sglist_addr, &ion_sglist_size)) {
tloge("get ion sglist failed, fd=%u\n", ion_shared_fd);
return -EFAULT;
}
op_params->local_tmpbuf[index].temp_buffer = phys_to_virt(ion_sglist_addr);
op_params->local_tmpbuf[index].size = ion_sglist_size;
operation->params[index].memref.buffer = (unsigned int)ion_sglist_addr;
operation->buffer_h_addr[index] =
(uint64_t)ion_sglist_addr >> ADDR_TRANS_NUM;
operation->params[index].memref.size = (unsigned int)ion_sglist_size;
op_params->trans_paramtype[index] = param_type;
return 0;
}
static int transfer_ion_params(struct tc_ns_operation *operation,
union tc_ns_client_param *client_param, uint8_t kernel_params,
unsigned int index)
{
uint64_t a_addr = client_param->value.a_addr |
((uint64_t)client_param->value.a_h_addr << ADDR_TRANS_NUM);
uint64_t b_addr = client_param->value.b_addr |
((uint64_t)client_param->value.b_h_addr << ADDR_TRANS_NUM);
if (read_from_client(&operation->params[index].value.a,
sizeof(operation->params[index].value.a),
(void *)(uintptr_t)a_addr,
sizeof(operation->params[index].value.a), kernel_params)) {
tloge("value.a_addr copy failed\n");
return -EFAULT;
}
if (read_from_client(&operation->params[index].value.b,
sizeof(operation->params[index].value.b),
(void *)(uintptr_t)b_addr,
sizeof(operation->params[index].value.b), kernel_params)) {
tloge("value.b_addr copy failed\n");
return -EFAULT;
}
return 0;
}
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)
{
struct tc_ns_operation *operation = NULL;
size_t drm_ion_size = 0;
phys_addr_t drm_ion_phys = 0x0;
struct dma_buf *drm_dma_buf = NULL;
union tc_ns_client_param *client_param = NULL;
unsigned int ion_shared_fd = 0;
int ret = 0;
/* this never happens */
if (index >= TEE_PARAM_NUM || !call_params || !op_params)
return -EINVAL;
operation = &op_params->mb_pack->operation;
client_param = &(call_params->context->params[index]);
if (transfer_ion_params(operation, client_param, kernel_params, index))
return -EFAULT;
ion_shared_fd = operation->params[index].value.a;
drm_dma_buf = dma_buf_get(ion_shared_fd);
if (IS_ERR_OR_NULL(drm_dma_buf)) {
tloge("drm dma buf is err, ret = %d fd = %u\n", ret, ion_shared_fd);
return -EFAULT;
}
#ifdef CONFIG_DMABUF_MM
ret = mm_dma_heap_secmem_get_phys(drm_dma_buf, &drm_ion_phys, &drm_ion_size);
#else
ret = ion_secmem_get_phys(drm_dma_buf, &drm_ion_phys, &drm_ion_size);
#endif
if (ret != 0) {
tloge("in %s err:ret=%d fd=%u\n", __func__, ret, ion_shared_fd);
dma_buf_put(drm_dma_buf);
return -EFAULT;
}
if (drm_ion_size > operation->params[index].value.b)
drm_ion_size = operation->params[index].value.b;
operation->params[index].value.a = (unsigned int)drm_ion_phys;
operation->params[index].value.b = (unsigned int)drm_ion_size;
op_params->trans_paramtype[index] = param_type;
dma_buf_put(drm_dma_buf);
return ret;
}
+150
View File
@@ -0,0 +1,150 @@
/*
* Copyright (c) 2012-2022 Huawei Technologies Co., Ltd.
* Description: dynamic ion memory function declaration.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 DYNAMIC_MMEM_H
#define DYNAMIC_MMEM_H
#include <linux/version.h>
#include <securec.h>
#include "teek_ns_client.h"
#ifdef CONFIG_DYNAMIC_ION
#ifdef CONFIG_DMABUF_MM
#include <linux/dmabuf/mm_dma_heap.h>
#else
#include <linux/ion/mm_ion.h>
#endif
#endif
struct sg_memory {
int dyn_shared_fd;
struct sg_table *dyn_sg_table;
struct dma_buf *dyn_dma_buf;
phys_addr_t ion_phys_addr;
size_t len;
void *ion_virt_addr;
};
struct dynamic_mem_item {
struct list_head head;
uint32_t configid;
uint32_t size;
struct sg_memory memory;
uint32_t cafd;
struct tc_uuid uuid;
uint32_t ddr_sec_region;
};
struct dynamic_mem_config {
struct tc_uuid uuid;
uint32_t ddr_sec_region;
};
#define MAX_ION_NENTS 1024
typedef struct ion_page_info {
phys_addr_t phys_addr;
uint32_t npages;
}tz_page_info;
typedef struct sglist {
uint64_t sglist_size;
uint64_t ion_size;
uint64_t ion_id;
uint64_t info_length;
struct ion_page_info page_info[0];
}tz_sg_list;
#ifdef CONFIG_DYNAMIC_ION
bool is_ion_param(uint32_t param_type);
int init_dynamic_mem(void);
int load_app_use_configid(uint32_t configid, uint32_t cafd,
const struct tc_uuid *uuid, uint32_t size, int32_t *ret_origin);
void kill_ion_by_cafd(unsigned int cafd);
void kill_ion_by_uuid(const struct tc_uuid *uuid);
int load_image_for_ion(const struct load_img_params *params, int32_t *ret_origin);
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);
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);
#else
static inline bool is_ion_param(uint32_t param_type)
{
(void)param_type;
return false;
}
static inline int load_image_for_ion(const struct load_img_params *params, int32_t *ret_origin)
{
(void)params;
(void)ret_origin;
return 0;
}
static inline int init_dynamic_mem(void)
{
return 0;
}
static inline int load_app_use_configid(uint32_t configid, uint32_t cafd,
const struct tc_uuid *uuid, uint32_t size)
{
(void)configid;
(void)cafd;
(void)uuid;
(void)size;
return 0;
}
static inline void kill_ion_by_cafd(unsigned int cafd)
{
(void)cafd;
return;
}
static inline void kill_ion_by_uuid(const struct tc_uuid *uuid)
{
(void)uuid;
return;
}
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)
{
(void)call_params;
(void)op_params;
(void)kernel_params;
(void)param_type;
(void)index;
tloge("not support seg and related feature!\n");
return -1;
}
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)
{
(void)call_params;
(void)op_params;
(void)kernel_params;
(void)param_type;
(void)index;
tloge("not support ion and related feature!\n");
return -1;
}
#endif
#endif
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2012-2022 Huawei Technologies Co., Ltd.
* Description: dynamic ion uuid declaration.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 DYNAMIC_ION_UUID_H
#define DYNAMIC_ION_UUID_H
#ifdef DEF_ENG
#define TEE_SERVICE_UT \
{ \
0x03030303, \
0x0303, \
0x0303, \
{ \
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 \
}\
}
#define TEE_SERVICE_TEST_DYNION \
{ \
0x7f313b2a, \
0x68b9, \
0x4e92, \
{ \
0xac, 0xf9, 0x13, 0x3e, 0xbb, 0x54, 0xeb, 0x56 \
} \
}
#endif
#define TEE_SECIDENTIFICATION1 \
{ \
0x8780dda1, \
0xa49e, \
0x45f4, \
{ \
0x96, 0x97, 0xc7, 0xed, 0x9e, 0x38, 0x5e, 0x83 \
} \
}
#define TEE_SECIDENTIFICATION3 \
{ \
0x335129cd, \
0x41fa, \
0x4b53, \
{ \
0x97, 0x97, 0x5c, 0xcb, 0x20, 0x2a, 0x52, 0xd4 \
} \
}
#define TEE_SERVICE_AI \
{ \
0xf4a8816d, \
0xb6fb, \
0x4d4f, \
{ \
0xa2, 0xb9, 0x7d, 0xae, 0x57, 0x33, 0x13, 0xc0 \
} \
}
#define TEE_SERVICE_AI_TINY \
{ \
0xc123c643, \
0x5b5b, \
0x4c9f, \
{ \
0x90, 0x98, 0xbb, 0x09, 0x56, 0x4d, 0x6e, 0xda \
} \
}
#define TEE_SERVICE_VCODEC \
{ \
0x528822b7, \
0xfc78, \
0x466b, \
{ \
0xb5, 0x7e, 0x62, 0x09, 0x3d, 0x60, 0x34, 0xa7 \
} \
}
#endif
+175
View File
@@ -0,0 +1,175 @@
/*
* Copyright (c) 2012-2022 Huawei Technologies Co., Ltd.
* Description: get and set static mem info.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "declare_static_ion.h"
#include <linux/of_reserved_mem.h>
#include <linux/of.h>
#include "tc_ns_log.h"
static u64 g_ion_mem_addr;
static u64 g_ion_mem_size;
static int supersonic_reserve_tee_mem(const struct reserved_mem *rmem)
{
if (rmem) {
g_ion_mem_addr = rmem->base;
g_ion_mem_size = rmem->size;
} else {
tloge("rmem is NULL\n");
}
return 0;
}
RESERVEDMEM_OF_DECLARE(supersonic, "platform-supersonic",
supersonic_reserve_tee_mem);
static u64 g_secfacedetect_mem_addr;
static u64 g_secfacedetect_mem_size;
static int secfacedetect_reserve_tee_mem(const struct reserved_mem *rmem)
{
if (rmem) {
g_secfacedetect_mem_addr = rmem->base;
g_secfacedetect_mem_size = rmem->size;
} else {
tloge("secfacedetect_reserve_tee_mem mem is NULL\n");
}
return 0;
}
RESERVEDMEM_OF_DECLARE(secfacedetect, "platform-secfacedetect",
secfacedetect_reserve_tee_mem);
static u64 g_pt_addr = 0;
static u64 g_pt_size = 0;
static int reserve_pt_mem(const struct reserved_mem *rmem)
{
if (rmem) {
g_pt_size = rmem->size;
g_pt_addr = rmem->base;
tloge("reserve pt mem is not NULL\n");
} else {
tloge("reserve pt mem is NULL\n");
}
return 0;
}
RESERVEDMEM_OF_DECLARE(pagetable, "platform-ai-pagetable",
reserve_pt_mem);
static u64 g_pp_addr = 0;
static u64 g_pp_size = 0;
static int reserve_pp_mem(const struct reserved_mem *rmem)
{
if (rmem) {
g_pp_addr = rmem->base;
g_pp_size = rmem->size;
} else {
tloge("reserve pp mem is NULL\n");
}
return 0;
}
RESERVEDMEM_OF_DECLARE(ai_running, "platform-ai-running",
reserve_pp_mem);
static u64 g_voiceid_addr = 0;
static u64 g_voiceid_size = 0;
static int voiceid_reserve_tee_mem(const struct reserved_mem *rmem)
{
if (rmem) {
g_voiceid_addr = rmem->base;
g_voiceid_size = rmem->size;
} else {
tloge("voiceid reserve tee mem is NULL\n");
}
return 0;
}
RESERVEDMEM_OF_DECLARE(voiceid, "platform-voiceid",
voiceid_reserve_tee_mem);
static u64 g_secos_ex_addr;
static u64 g_secos_ex_size;
static int secos_reserve_tee_mem(const struct reserved_mem *rmem)
{
if (rmem) {
g_secos_ex_addr = rmem->base;
g_secos_ex_size = rmem->size;
} else {
tloge("secos reserve tee mem is NULL\n");
}
return 0;
}
RESERVEDMEM_OF_DECLARE(secos_ex, "platform-secos-ex",
secos_reserve_tee_mem);
static u64 g_ion_ex_mem_addr;
static u64 g_ion_ex_mem_size;
static int supersonic_ex_reserve_tee_mem(const struct reserved_mem *rmem)
{
if (rmem) {
g_ion_ex_mem_addr = rmem->base;
g_ion_ex_mem_size = rmem->size;
} else {
tloge("rmem is NULL\n");
}
return 0;
}
RESERVEDMEM_OF_DECLARE(supersonic_ex, "platform-supersonic-ex",
supersonic_ex_reserve_tee_mem);
static void set_mem_tag(struct register_ion_mem_tag *memtag,
u64 addr, u64 size, uint32_t tag, uint32_t *pos)
{
memtag->memaddr[*pos] = addr;
memtag->memsize[*pos] = size;
memtag->memtag[*pos] = tag;
(*pos)++;
}
void set_ion_mem_info(struct register_ion_mem_tag *memtag)
{
uint32_t pos = 0;
if(!memtag) {
tloge("invalid memtag\n");
return;
}
tlogi("ion mem static reserved for tee face=%d, finger=%d,voiceid=%d,"
"secos=%d,finger-ex=%d, pt_size= %d,pp_size=%d\n",
(uint32_t)g_secfacedetect_mem_size, (uint32_t)g_ion_mem_size,
(uint32_t)g_voiceid_size, (uint32_t)g_secos_ex_size,
(uint32_t)g_ion_ex_mem_size, (uint32_t)g_pt_size,
(uint32_t)g_pp_size);
if (g_ion_mem_addr != (u64)0 && g_ion_mem_size != (u64)0)
set_mem_tag(memtag,g_ion_mem_addr, g_ion_mem_size, PP_MEM_TAG, &pos);
if (g_secfacedetect_mem_addr != (u64)0 && g_secfacedetect_mem_size != (u64)0)
set_mem_tag(memtag,g_secfacedetect_mem_addr, g_secfacedetect_mem_size, PP_MEM_TAG, &pos);
if (g_voiceid_addr != (u64)0 && g_voiceid_size != (u64)0)
set_mem_tag(memtag, g_voiceid_addr, g_voiceid_size, PP_MEM_TAG, &pos);
if (g_secos_ex_addr != (u64)0 && g_secos_ex_size != (u64)0)
set_mem_tag(memtag, g_secos_ex_addr, g_secos_ex_size, PP_MEM_TAG, &pos);
if (g_pt_addr != (u64)0 && g_pt_size != (u64)0)
set_mem_tag(memtag, g_pt_addr, g_pt_size, PT_MEM_TAG, &pos);
if (g_pp_addr != (u64)0 && g_pp_size != (u64)0)
set_mem_tag(memtag, g_pp_addr, g_pp_size, PRI_PP_MEM_TAG, &pos);
if (g_ion_ex_mem_addr != (u64)0 && g_ion_ex_mem_size != (u64)0)
set_mem_tag(memtag, g_ion_ex_mem_addr, g_ion_ex_mem_size, PP_MEM_TAG, &pos);
/* here pos max is 7, memaddr[] has 10 positions, just 3 free */
memtag->size = pos;
return;
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2012-2022 Huawei Technologies Co., Ltd.
* Description: get and set static mem info.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "declare_static_ion.h"
#include <linux/of_reserved_mem.h>
#include <linux/of.h>
#include "tc_ns_log.h"
static u64 g_secos_ex_addr;
static u64 g_secos_ex_size;
static int secos_reserve_tee_mem(const struct reserved_mem *rmem)
{
if (rmem) {
g_secos_ex_addr = rmem->base;
g_secos_ex_size = rmem->size;
} else {
tloge("secos reserve tee mem is NULL\n");
}
return 0;
}
RESERVEDMEM_OF_DECLARE(secos_ex, "mediatek,tee_os_reserved_memory",
secos_reserve_tee_mem);
void set_ion_mem_info(struct register_ion_mem_tag *memtag)
{
uint32_t pos = 0;
if(!memtag) {
tloge("invalid memtag\n");
return;
}
tlogi("ion mem static reserved for tee secos=0x%x\n", (uint32_t)g_secos_ex_size);
if (g_secos_ex_addr != (u64)0 && g_secos_ex_size != (u64)0) {
memtag->memaddr[pos] = g_secos_ex_addr;
memtag->memsize[pos] = g_secos_ex_size;
memtag->memtag[pos] = PP_MEM_TAG;
pos++;
}
memtag->size = pos;
return;
}
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2012-2022 Huawei Technologies Co., Ltd.
* Description: memory init, register for mailbox pool.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "static_ion_mem.h"
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/mempool.h>
#include <linux/vmalloc.h>
#ifdef DEF_ENG
#include <asm/io.h>
#include <linux/mman.h>
#endif
#include "smc_smp.h"
#include "teek_ns_client.h"
#include "mailbox_mempool.h"
#include "tc_ns_log.h"
#include "declare_static_ion.h"
/* send the ion static memory to tee */
int tc_ns_register_ion_mem(void)
{
struct tc_ns_smc_cmd smc_cmd = {{0}, 0};
int ret = 0;
struct mb_cmd_pack *mb_pack = NULL;
struct register_ion_mem_tag *memtag = NULL;
mb_pack = mailbox_alloc_cmd_pack();
if (!mb_pack) {
tloge("mailbox alloc failed\n");
return -ENOMEM;
}
memtag = mailbox_alloc(sizeof(*memtag), 0);
if (!memtag) {
mailbox_free(mb_pack);
return -ENOMEM;
}
set_ion_mem_info(memtag);
smc_cmd.cmd_type = CMD_TYPE_GLOBAL;
smc_cmd.cmd_id = GLOBAL_CMD_ID_REGISTER_ION_MEM;
mb_pack->operation.paramtypes = TEE_PARAM_TYPE_MEMREF_INPUT;
mb_pack->operation.params[0].memref.buffer =
mailbox_virt_to_phys((uintptr_t)(void *)memtag);
mb_pack->operation.buffer_h_addr[0] =
(uint64_t)mailbox_virt_to_phys((uintptr_t)(void *)memtag) >> ADDR_TRANS_NUM;
mb_pack->operation.params[0].memref.size = sizeof(*memtag);
smc_cmd.operation_phys = mailbox_virt_to_phys((uintptr_t)&mb_pack->operation);
smc_cmd.operation_h_phys =
(uint64_t)mailbox_virt_to_phys((uintptr_t)&mb_pack->operation) >> ADDR_TRANS_NUM;
if (tc_ns_smc(&smc_cmd)) {
ret = -EPERM;
tloge("send ion mem info failed\n");
}
mailbox_free(mb_pack);
mailbox_free(memtag);
return ret;
}
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2012-2022 Huawei Technologies Co., Ltd.
* Description: memory init, register for mailbox pool.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 STATIC_ION_MEM_H
#define STATIC_ION_MEM_H
#include <linux/types.h>
#define ION_MEM_MAX_SIZE 10
struct register_ion_mem_tag {
uint32_t size;
uint64_t memaddr[ION_MEM_MAX_SIZE];
uint32_t memsize[ION_MEM_MAX_SIZE];
uint32_t memtag[ION_MEM_MAX_SIZE];
};
enum static_mem_tag {
MEM_TAG_MIN = 0,
PP_MEM_TAG = 1,
PRI_PP_MEM_TAG = 2,
PT_MEM_TAG = 3,
MEM_TAG_MAX,
};
#ifdef CONFIG_STATIC_ION
int tc_ns_register_ion_mem(void);
#else
static inline int tc_ns_register_ion_mem(void)
{
return 0;
}
#endif
#endif
+165
View File
@@ -0,0 +1,165 @@
/*
* ko_adapt.c
*
* function for find symbols not exported
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "ko_adapt.h"
#include <linux/types.h>
#include <linux/mm_types.h>
#include <linux/stddef.h>
#include <linux/cred.h>
#include <linux/version.h>
#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
#include <linux/sched/task.h>
#endif
#include <linux/cpumask.h>
#include <linux/syscalls.h>
#include <linux/fs.h>
#include "tc_ns_log.h"
typedef const struct cred *(get_task_cred_func)(struct task_struct *);
typedef void (kthread_bind_mask_func)(struct task_struct *, const struct cpumask *);
typedef struct page *(alloc_pages_func)(gfp_t gfp_mask, unsigned int order);
typedef struct workqueue_attrs *(alloc_workqueue_attrs_func)(gfp_t gfp_mask);
typedef void (free_workqueue_attrs_func)(struct workqueue_attrs *attrs);
const struct cred *koadpt_get_task_cred(struct task_struct *task)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
return get_task_cred(task);
#else
static get_task_cred_func *get_task_cred_pt = NULL;
if (!task)
return NULL;
if (!get_task_cred_pt) {
get_task_cred_pt = (get_task_cred_func *)
(uintptr_t)kallsyms_lookup_name("get_task_cred");
if (IS_ERR_OR_NULL(get_task_cred_pt)) {
tloge("fail to find symbol get task cred\n");
return NULL;
}
}
return get_task_cred_pt(task);
#endif
}
void koadpt_kthread_bind_mask(struct task_struct *task,
const struct cpumask *mask)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
(void)set_cpus_allowed_ptr(task, mask);
#else
static kthread_bind_mask_func *kthread_bind_mask_pt = NULL;
if (!task || !mask)
return;
if (!kthread_bind_mask_pt) {
kthread_bind_mask_pt = (kthread_bind_mask_func *)
(uintptr_t)kallsyms_lookup_name("kthread_bind_mask");
if (IS_ERR_OR_NULL(kthread_bind_mask_pt)) {
tloge("fail to find symbol kthread bind mask\n");
return;
}
}
kthread_bind_mask_pt(task, mask);
#endif
}
struct page *koadpt_alloc_pages(gfp_t gfp_mask, unsigned int order)
{
#ifdef CONFIG_NUMA
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
return alloc_pages(gfp_mask, order);
#else
static alloc_pages_func *alloc_pages_pt = NULL;
if (!alloc_pages_pt) {
alloc_pages_pt = (alloc_pages_func *)
(uintptr_t)kallsyms_lookup_name("alloc_pages_current");
if (IS_ERR_OR_NULL(alloc_pages_pt)) {
tloge("fail to find symbol alloc pages current\n");
return NULL;
}
}
return alloc_pages_pt(gfp_mask, order);
#endif
#else
return alloc_pages(gfp_mask, order);
#endif
}
struct workqueue_attrs *koadpt_alloc_workqueue_attrs(gfp_t gfp_mask)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
struct workqueue_attrs *attrs;
(void)gfp_mask;
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
if (!attrs) {
tloge("alloc workqueue attr fail\n");
return NULL;
}
if (alloc_cpumask_var(&attrs->cpumask, GFP_KERNEL) == false) {
tloge("alloc cpumask var fail\n");
kfree(attrs);
return NULL;
}
cpumask_copy(attrs->cpumask, cpu_possible_mask);
return attrs;
#else
static alloc_workqueue_attrs_func *alloc_workqueue_attrs_pt = NULL;
if (!alloc_workqueue_attrs_pt) {
alloc_workqueue_attrs_pt = (alloc_workqueue_attrs_func *)
(uintptr_t)kallsyms_lookup_name("alloc_workqueue_attrs");
if (IS_ERR_OR_NULL(alloc_workqueue_attrs_pt)) {
tloge("fail to find symbol alloc workqueue attrs\n");
return NULL;
}
}
return alloc_workqueue_attrs_pt(gfp_mask);
#endif
}
void koadpt_free_workqueue_attrs(struct workqueue_attrs *attrs)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
if (!attrs)
return;
free_cpumask_var(attrs->cpumask);
kfree(attrs);
#else
static free_workqueue_attrs_func *free_workqueue_attrs_pt = NULL;
if (!attrs)
return;
if (!free_workqueue_attrs_pt) {
free_workqueue_attrs_pt = (free_workqueue_attrs_func *)
(uintptr_t)kallsyms_lookup_name("free_workqueue_attrs");
if (IS_ERR_OR_NULL(free_workqueue_attrs_pt)) {
tloge("fail to find symbol free workqueue attrs\n");
return;
}
}
free_workqueue_attrs_pt(attrs);
#endif
}
+78
View File
@@ -0,0 +1,78 @@
/*
* ko_adapt.h
*
* function for find symbols not exported
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 KO_ADAPT_H
#define KO_ADAPT_H
#include <linux/types.h>
#include <linux/cred.h>
#include <linux/version.h>
#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
#include <linux/sched/task.h>
#endif
#include <linux/kthread.h>
#include <linux/cpumask.h>
#include <linux/syscalls.h>
#include <linux/version.h>
#include <linux/gfp.h>
#ifdef CONFIG_TZDRIVER_MODULE
const struct cred *koadpt_get_task_cred(struct task_struct *task);
void koadpt_kthread_bind_mask(struct task_struct *task,
const struct cpumask *mask);
struct page *koadpt_alloc_pages(gfp_t gfp_mask, unsigned int order);
struct workqueue_attrs *koadpt_alloc_workqueue_attrs(gfp_t gfp_mask);
void koadpt_free_workqueue_attrs(struct workqueue_attrs *attrs);
#else
static inline const struct cred *koadpt_get_task_cred(struct task_struct *task)
{
return get_task_cred(task);
}
static inline void koadpt_kthread_bind_mask(struct task_struct *task,
const struct cpumask *mask)
{
kthread_bind_mask(task, mask);
}
static inline struct page *koadpt_alloc_pages(gfp_t gfp_mask, unsigned int order)
{
return alloc_pages(gfp_mask, order);
}
static inline struct workqueue_attrs *koadpt_alloc_workqueue_attrs(
gfp_t gfp_mask)
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 19, 0))
return alloc_workqueue_attrs(gfp_mask);
#else
(void)gfp_mask;
return alloc_workqueue_attrs();
#endif
}
static inline void koadpt_free_workqueue_attrs(struct workqueue_attrs *attrs)
{
return free_workqueue_attrs(attrs);
}
#endif
#endif
+197
View File
@@ -0,0 +1,197 @@
/*
* tc_ns_client.h
*
* data structure declaration for nonsecure world
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TC_NS_CLIENT_H
#define TC_NS_CLIENT_H
#include <linux/types.h>
#include <linux/version.h>
#define UUID_LEN 16
#define PARAM_NUM 4
#define ADDR_TRANS_NUM 32
#define teec_param_types(param0_type, param1_type, param2_type, param3_type) \
((param3_type) << 12 | (param2_type) << 8 | \
(param1_type) << 4 | (param0_type))
#define teec_param_type_get(param_types, index) \
(((param_types) >> ((index) << 2)) & 0x0F)
#ifndef ZERO_SIZE_PTR
#define ZERO_SIZE_PTR ((void *)16)
#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= (unsigned long)ZERO_SIZE_PTR)
#endif
#if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE)
#define mm_sem_lock(mm) (mm)->mmap_lock
#else
#define mm_sem_lock(mm) (mm)->mmap_sem
#endif
struct tc_ns_client_login {
__u32 method;
__u32 mdata;
};
union tc_ns_client_param {
struct {
__u32 buffer;
__u32 buffer_h_addr;
__u32 offset;
__u32 h_offset;
__u32 size_addr;
__u32 size_h_addr;
} memref;
struct {
__u32 a_addr;
__u32 a_h_addr;
__u32 b_addr;
__u32 b_h_addr;
} value;
};
struct tc_ns_client_return {
int code;
__u32 origin;
};
struct tc_ns_client_context {
unsigned char uuid[UUID_LEN];
__u32 session_id;
__u32 cmd_id;
struct tc_ns_client_return returns;
struct tc_ns_client_login login;
union tc_ns_client_param params[PARAM_NUM];
__u32 param_types;
__u8 started;
__u32 calling_pid;
unsigned int file_size;
union {
char *file_buffer;
struct {
uint32_t file_addr;
uint32_t file_h_addr;
} memref;
};
};
struct tc_ns_client_time {
uint32_t seconds;
uint32_t millis;
};
enum secfile_type_t {
LOAD_TA = 0,
LOAD_SERVICE,
LOAD_LIB,
LOAD_DYNAMIC_DRV,
LOAD_PATCH,
LOAD_TYPE_MAX,
};
struct sec_file_info {
enum secfile_type_t secfile_type;
uint32_t file_size;
int32_t sec_load_err;
};
struct load_secfile_ioctl_struct {
struct sec_file_info sec_file_info;
unsigned char uuid[UUID_LEN];
union {
char *file_buffer;
struct {
uint32_t file_addr;
uint32_t file_h_addr;
} memref;
};
}__attribute__((packed));
struct agent_ioctl_args {
uint32_t id;
uint32_t buffer_size;
union {
void *buffer;
unsigned long long addr;
};
};
struct tc_ns_client_crl {
union {
uint8_t *buffer;
struct {
uint32_t buffer_addr;
uint32_t buffer_h_addr;
} memref;
};
uint32_t size;
};
#ifdef CONFIG_LOG_POOL_ENABLE
struct tc_ns_log_pool {
uint64_t addr;
uint64_t size;
};
#endif
#define MAX_SHA_256_SZ 32
#define TC_NS_CLIENT_IOCTL_SES_OPEN_REQ \
_IOW(TC_NS_CLIENT_IOC_MAGIC, 1, struct tc_ns_client_context)
#define TC_NS_CLIENT_IOCTL_SES_CLOSE_REQ \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 2, struct tc_ns_client_context)
#define TC_NS_CLIENT_IOCTL_SEND_CMD_REQ \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 3, struct tc_ns_client_context)
#define TC_NS_CLIENT_IOCTL_SHRD_MEM_RELEASE \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 4, unsigned int)
#define TC_NS_CLIENT_IOCTL_WAIT_EVENT \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 5, unsigned int)
#define TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 6, unsigned int)
#define TC_NS_CLIENT_IOCTL_REGISTER_AGENT \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 7, struct agent_ioctl_args)
#define TC_NS_CLIENT_IOCTL_UNREGISTER_AGENT \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 8, unsigned int)
#define TC_NS_CLIENT_IOCTL_LOAD_APP_REQ \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 9, struct load_secfile_ioctl_struct)
#define TC_NS_CLIENT_IOCTL_NEED_LOAD_APP \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 10, struct tc_ns_client_context)
#define TC_NS_CLIENT_IOCTL_ALLOC_EXCEPTING_MEM \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 12, unsigned int)
#define TC_NS_CLIENT_IOCTL_CANCEL_CMD_REQ \
_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_TUI_EVENT \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 16, int)
#define TC_NS_CLIENT_IOCTL_SYC_SYS_TIME \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 17, struct tc_ns_client_time)
#define TC_NS_CLIENT_IOCTL_SET_NATIVECA_IDENTITY \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 18, int)
#define TC_NS_CLIENT_IOCTL_LOAD_TTF_FILE_AND_NOTCH_HEIGHT \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 19, unsigned int)
#define TC_NS_CLIENT_IOCTL_LATEINIT \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 20, unsigned int)
#define TC_NS_CLIENT_IOCTL_GET_TEE_VERSION \
_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
#endif
+67
View File
@@ -0,0 +1,67 @@
/*
* tc_ns_log.h
*
* log func declaration
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TC_NS_LOG_H
#define TC_NS_LOG_H
#include <linux/version.h>
#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
#include <linux/sched/mm.h>
#endif
#include <linux/printk.h>
enum {
TZ_DEBUG_VERBOSE = 0,
TZ_DEBUG_DEBUG,
TZ_DEBUG_INFO,
TZ_DEBUG_WARN,
TZ_DEBUG_ERROR,
};
#define MOD_TEE "tzdriver"
#define TEE_LOG_MASK TZ_DEBUG_INFO
#define tlogv(fmt, args...) \
do { \
if (TZ_DEBUG_VERBOSE >= TEE_LOG_MASK) \
pr_info("[%s] (%i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args); \
} while (0)
#define tlogd(fmt, args...) \
do { \
if (TZ_DEBUG_DEBUG >= TEE_LOG_MASK) \
pr_info("[%s] (%i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args); \
} while (0)
#define tlogi(fmt, args...) \
do { \
if (TZ_DEBUG_INFO >= TEE_LOG_MASK) \
pr_info("[%s] (%i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args); \
} while (0)
#define tlogw(fmt, args...) \
do { \
if (TZ_DEBUG_WARN >= TEE_LOG_MASK) \
pr_warn("[%s] (%i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args); \
} while (0)
#define tloge(fmt, args...) \
pr_err("[%s] (%i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args)
#endif
+183
View File
@@ -0,0 +1,183 @@
/*
* teek_client_api.h
*
* function declaration for libteec interface for kernel CA.
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TEEK_CLIENT_API_H
#define TEEK_CLIENT_API_H
#include "teek_ns_client.h"
#include "teek_client_type.h"
#define TEEC_PARAM_TYPES(param0_type, param1_type, param2_type, param3_type) \
((param3_type) << 12 | (param2_type) << 8 | \
(param1_type) << 4 | (param0_type))
#define TEEC_PARAM_TYPE_GET(param_types, index) \
(((param_types) >> ((index) << 2)) & 0x0F)
#define TEEC_VALUE_UNDEF 0xFFFFFFFF
int TC_NS_RegisterServiceCallbackFunc(const char *uuid, void *func, const void *private_data);
#ifdef CONFIG_KERNEL_CLIENT
/*
* for history reason, we supply two set interface
* first set is uncapitalized and satisfies kernel code rule
* second set is capitalized for compatibility
*/
int teek_is_agent_alive(unsigned int agent_id);
uint32_t teek_initialize_context(const char *name,
struct teec_context *context);
void teek_finalize_context(struct teec_context *context);
uint32_t teek_open_session(struct teec_context *context,
struct teec_session *session,
const struct teec_uuid *destination,
uint32_t connection_method,
const void *connection_data,
const struct teec_operation *operation,
uint32_t *return_origin);
void teek_close_session(struct teec_session *session);
uint32_t teek_send_secfile(struct teec_session *session,
const char *file_buffer, unsigned int file_size);
TEEC_Result TEEK_SendSecfile(TEEC_Session *session,
const char *file_buffer, unsigned int file_size);
uint32_t teek_invoke_command(struct teec_session *session,
uint32_t cmd_id, struct teec_operation *operation,
uint32_t *return_origin);
uint32_t teek_register_shared_memory(struct teec_context *context,
struct teec_sharedmemory *sharedmem);
uint32_t teek_allocate_shared_memory(struct teec_context *context,
struct teec_sharedmemory *sharedmem);
void teek_release_shared_memory(struct teec_sharedmemory *sharedmem);
void teek_request_cancellation(struct teec_operation *operation);
int TEEK_IsAgentAlive(unsigned int agent_id);
TEEC_Result TEEK_InitializeContext(const char *name, TEEC_Context *context);
void TEEK_FinalizeContext(TEEC_Context *context);
TEEC_Result TEEK_OpenSession(TEEC_Context *context,
TEEC_Session *session,
const TEEC_UUID *destination,
uint32_t connectionMethod,
const void *connectionData,
TEEC_Operation *operation,
uint32_t *returnOrigin);
void TEEK_CloseSession(TEEC_Session *session);
TEEC_Result TEEK_InvokeCommand(TEEC_Session *session,
uint32_t commandID,
TEEC_Operation *operation,
uint32_t *returnOrigin);
#else
static inline int teek_is_agent_alive(unsigned int agent_id)
{
return TEEC_SUCCESS;
}
static inline int TEEK_IsAgentAlive(unsigned int agent_id)
{
return TEEC_SUCCESS;
}
static inline uint32_t teek_initialize_context(const char *name,
struct teec_context *context)
{
return TEEC_SUCCESS;
}
static inline TEEC_Result TEEK_InitializeContext(const char *name,
TEEC_Context *context)
{
return TEEC_SUCCESS;
}
static inline void teek_finalize_context(struct teec_context *context)
{
(void)context;
}
static inline void TEEK_FinalizeContext(TEEC_Context *context)
{
(void)context;
}
static inline uint32_t teek_open_session(struct teec_context *context,
struct teec_session *session,
const struct teec_uuid *destination,
uint32_t connection_method,
const void *connection_data,
const struct teec_operation *operation,
uint32_t *return_origin)
{
return TEEC_SUCCESS;
}
static inline TEEC_Result TEEK_OpenSession(TEEC_Context *context,
TEEC_Session *session, const TEEC_UUID *destination,
uint32_t connectionMethod, const void *connectionData,
TEEC_Operation *operation, uint32_t *returnOrigin)
{
return TEEC_SUCCESS;
}
static inline void teek_close_session(struct teec_session *session)
{
(void)session;
}
static inline void TEEK_CloseSession(TEEC_Session *session)
{
(void)session;
}
static inline uint32_t teek_invoke_command(struct teec_session *session,
uint32_t cmd_id, struct teec_operation *operation,
uint32_t *return_origin)
{
return TEEC_SUCCESS;
}
static inline TEEC_Result TEEK_InvokeCommand(TEEC_Session *session,
uint32_t commandID, TEEC_Operation *operation, uint32_t *returnOrigin)
{
return TEEC_SUCCESS;
}
static inline uint32_t teek_send_secfile(struct teec_session *session,
const char *file_buffer, unsigned int file_size)
{
return TEEC_SUCCESS;
}
#endif
#endif
+214
View File
@@ -0,0 +1,214 @@
/*
* teek_client_constants.h
*
* macro declaration for libteec interface for kernel CA.
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TEEK_CLIENT_CONSTANTS_H
#define TEEK_CLIENT_CONSTANTS_H
enum global_service_cmd_id {
GLOBAL_CMD_ID_INVALID = 0x0,
GLOBAL_CMD_ID_BOOT_ACK = 0x1,
GLOBAL_CMD_ID_OPEN_SESSION = 0x2,
GLOBAL_CMD_ID_CLOSE_SESSION = 0x3,
GLOBAL_CMD_ID_LOAD_SECURE_APP = 0x4,
GLOBAL_CMD_ID_NEED_LOAD_APP = 0x5,
GLOBAL_CMD_ID_REGISTER_AGENT = 0x6,
GLOBAL_CMD_ID_UNREGISTER_AGENT = 0x7,
GLOBAL_CMD_ID_REGISTER_NOTIFY_MEMORY = 0x8,
GLOBAL_CMD_ID_UNREGISTER_NOTIFY_MEMORY = 0x9,
GLOBAL_CMD_ID_INIT_CONTENT_PATH = 0xa,
GLOBAL_CMD_ID_TERMINATE_CONTENT_PATH = 0xb,
GLOBAL_CMD_ID_ALLOC_EXCEPTION_MEM = 0xc,
GLOBAL_CMD_ID_TEE_TIME = 0xd,
GLOBAL_CMD_ID_TEE_INFO = 0xe,
GLOBAL_CMD_ID_REGISTER_LOG_MEM = 0xf,
GLOBAL_CMD_ID_KILL_TASK = 0x10,
GLOBAL_CMD_ID_TUI_EXCEPTION = 0x11,
GLOBAL_CMD_ID_ADJUST_TIME = 0x12,
GLOBAL_CMD_ID_SET_CA_HASH = 0x13,
/* set the Android's build version */
GLOBAL_CMD_ID_SET_BUILD_VERSION = 0x14,
GLOBAL_CMD_ID_REGISTER_TTF_MEM = 0x15,
/* get session key for encrypting dialog */
GLOBAL_CMD_ID_GET_SESSION_SECURE_PARAMS = 0x16,
GLOBAL_CMD_ID_REGISTER_MAILBOX = 0x17,
GLOBAL_CMD_ID_REGISTER_UNUSUAL_TTF_MEM = 0x18,
GLOBAL_CMD_ID_REGISTER_ION_MEM = 0x19,
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,
#ifdef CONFIG_CMS_SIGNATURE
GLOBAL_CMD_ID_UPDATE_TA_CRL = 0x23,
#endif
GLOBAL_CMD_ID_REGISTER_RESMEM = 0x24,
GLOBAL_CMD_ID_DUMP_SRV_SESS = 0x25,
GLOBAL_CMD_ID_TRACE_ENABLE = 0x26,
#ifdef CONFIG_LIVEPATCH_ENABLE
GLOBAL_CMD_ID_LIVEPATCH_UNLOAD = 0x27,
GLOBAL_CMD_ID_LIVEPATCH_ENABLE = 0x28,
GLOBAL_CMD_ID_LIVEPATCH_DISABLE = 0x29,
GLOBAL_CMD_ID_LIVEPATCH_QUERY = 0x2a,
#endif
GLOBAL_CMD_ID_UNKNOWN = 0x7FFFFFFE,
GLOBAL_CMD_ID_MAX = 0x7FFFFFFF
};
enum teec_result {
TEEC_SUCCESS = 0x0,
TEEC_ERROR_INVALID_CMD = 0x1,
TEEC_ERROR_SERVICE_NOT_EXIST = 0x2,
TEEC_ERROR_SESSION_NOT_EXIST = 0x3,
TEEC_ERROR_SESSION_MAXIMUM,
TEEC_ERROR_REGISTER_EXIST_SERVICE,
TEEC_ERROR_TAGET_DEAD_FATAL,
TEEC_ERROR_READ_DATA,
TEEC_ERROR_WRITE_DATA,
TEEC_ERROR_TRUNCATE_OBJECT,
TEEC_ERROR_SEEK_DATA,
TEEC_ERROR_RENAME_OBJECT,
TEEC_ERROR_TRUSTED_APP_LOAD_ERROR,
TEEC_ERROR_GENERIC = 0xFFFF0000,
TEEC_ERROR_ACCESS_DENIED = 0xFFFF0001,
TEEC_ERROR_CANCEL = 0xFFFF0002,
TEEC_ERROR_ACCESS_CONFLICT = 0xFFFF0003,
TEEC_ERROR_EXCESS_DATA = 0xFFFF0004,
TEEC_ERROR_BAD_FORMAT = 0xFFFF0005,
TEEC_ERROR_BAD_PARAMETERS = 0xFFFF0006,
TEEC_ERROR_BAD_STATE = 0xFFFF0007,
TEEC_ERROR_ITEM_NOT_FOUND = 0xFFFF0008,
TEEC_ERROR_NOT_IMPLEMENTED = 0xFFFF0009,
TEEC_ERROR_NOT_SUPPORTED = 0xFFFF000A,
TEEC_ERROR_NO_DATA = 0xFFFF000B,
TEEC_ERROR_OUT_OF_MEMORY = 0xFFFF000C,
TEEC_ERROR_BUSY = 0xFFFF000D,
TEEC_ERROR_COMMUNICATION = 0xFFFF000E,
TEEC_ERROR_SECURITY = 0xFFFF000F,
TEEC_ERROR_SHORT_BUFFER = 0xFFFF0010,
TEEC_PENDING = 0xFFFF2000,
TEEC_PENDING2 = 0xFFFF2001,
TEE_ERROR_TAGET_DEAD = 0xFFFF3024,
TEE_ERROR_GT_DEAD = 0xFFFF3124,
TEEC_ERROR_MAC_INVALID = 0xFFFF3071,
TEEC_CLIENT_INTR = 0xFFFF4000,
TEEC_ERROR_TUI_IN_USE = 0xFFFF7110,
TEEC_ERROR_TUI_SWITCH_CHANNAL,
TEEC_ERROR_TUI_CFG_DRIVER,
TEEC_ERROR_TUI_INVALID_EVENT,
TEEC_ERROR_TUI_POLL_EVENT,
TEEC_ERROR_TUI_CANCELED,
TEEC_ERROR_TUI_EXIT,
TEEC_ERROR_TUI_NOT_AVAILABLE,
TEEC_ERROR_SEC_FLASH_NOT_AVAILABLE,
TEEC_ERROR_CA_AUTH_FAIL = 0xFFFFCFE5,
TEE_ERROR_AUDIT_FAIL = 0xFFFF9112,
TEE_ERROR_IS_DEAD = 0xFFFFABAB,
};
enum TEEC_ReturnCodeOrigin {
TEEC_ORIGIN_API = 0x1,
TEEC_ORIGIN_COMMS = 0x2,
TEEC_ORIGIN_TEE = 0x3,
TEEC_ORIGIN_TRUSTED_APP = 0x4,
};
enum TEEC_SharedMemCtl {
TEEC_MEM_INPUT = 0x1,
TEEC_MEM_OUTPUT = 0x2,
TEEC_MEM_INOUT = 0x3,
};
enum TEEC_ParamType {
TEEC_NONE = 0x0,
TEEC_VALUE_INPUT = 0x01,
TEEC_VALUE_OUTPUT = 0x02,
TEEC_VALUE_INOUT = 0x03,
TEEC_MEMREF_TEMP_INPUT = 0x05,
TEEC_MEMREF_TEMP_OUTPUT = 0x06,
TEEC_MEMREF_TEMP_INOUT = 0x07,
TEEC_ION_INPUT = 0x08,
TEEC_ION_SGLIST_INPUT = 0x09,
TEEC_MEMREF_SHARED_INOUT = 0x0a,
TEEC_MEMREF_WHOLE = 0xc,
TEEC_MEMREF_PARTIAL_INPUT = 0xd,
TEEC_MEMREF_PARTIAL_OUTPUT = 0xe,
TEEC_MEMREF_PARTIAL_INOUT = 0xf
};
enum TEE_ParamType {
TEE_PARAM_TYPE_NONE = 0x0,
TEE_PARAM_TYPE_VALUE_INPUT = 0x1,
TEE_PARAM_TYPE_VALUE_OUTPUT = 0x2,
TEE_PARAM_TYPE_VALUE_INOUT = 0x3,
TEE_PARAM_TYPE_MEMREF_INPUT = 0x5,
TEE_PARAM_TYPE_MEMREF_OUTPUT = 0x6,
TEE_PARAM_TYPE_MEMREF_INOUT = 0x7,
TEE_PARAM_TYPE_ION_INPUT = 0x8,
TEE_PARAM_TYPE_ION_SGLIST_INPUT = 0x9,
TEE_PARAM_TYPE_MEMREF_SHARED_INOUT = 0x0a,
TEE_PARAM_TYPE_RESMEM_INPUT = 0xc,
TEE_PARAM_TYPE_RESMEM_OUTPUT = 0xd,
TEE_PARAM_TYPE_RESMEM_INOUT = 0xe
};
enum TEEC_LoginMethod {
TEEC_LOGIN_PUBLIC = 0x0,
TEEC_LOGIN_USER,
TEEC_LOGIN_GROUP,
TEEC_LOGIN_APPLICATION = 0x4,
TEEC_LOGIN_USER_APPLICATION = 0x5,
TEEC_LOGIN_GROUP_APPLICATION = 0x6,
TEEC_LOGIN_IDENTIFY = 0x7,
TEEK_LOGIN_IDENTIFY = 0x80000001,
};
/* Add event id's name in 'view_state[]' in same order */
enum tee_event_id {
INVOKE_CMD_START,
INVOKE_CMD_END,
SMC_SEND,
SMC_DONE,
SMC_IN,
SMC_OUT,
SMC_SLEEP,
SMC_PREEMPT,
GTASK_GET_CMD,
GTASK_PUT_CMD,
GTASK_REQ_TA,
GTASK_RESP_TA,
SPI_WAKEUP,
SCHED_IN,
SCHED_OUT,
INTERRUPT_HANDLE_SPI_START,
INTERRUPT_HANDLE_SPI_REE_RESPONSE,
INTERRUPT_HANDLE_SPI_REE_MISS,
INTERRUPT_HANDLE_SPI_REE_SCHEDULED,
INTERRUPT_HANDLE_SPI_END,
INTERRUPT_HANDLE_START,
INTERRUPT_HANDLE_END,
TEE_EVENT_MAX
};
#define TZ_WQ_MAX_ACTIVE 1
#endif
+27
View File
@@ -0,0 +1,27 @@
/*
* teek_client_ext.h
*
* ext api for teek
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TEEK_CLIENT_EXT_H
#define TEEK_CLIENT_EXT_H
#include <linux/types.h>
/* update crl */
#ifdef CONFIG_CMS_SIGNATURE
uint32_t teek_update_crl(uint8_t *crl, uint32_t crl_len);
#endif
#endif
+139
View File
@@ -0,0 +1,139 @@
/*
* teek_client_id.h
*
* define exported data for secboot CA
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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_CLIENT_ID_H
#define TEE_CLIENT_ID_H
#define TEE_SERVICE_SECBOOT \
{ \
0x08080808, \
0x0808, \
0x0808, \
{ \
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 \
} \
}
/* e7ed1f64-4687-41da-96dc-cbe4f27c838f */
#define TEE_SERVICE_ANTIROOT \
{ \
0xE7ED1F64, \
0x4687, \
0x41DA, \
{ \
0x96, 0xDC, 0xCB, 0xE4, 0xF2, 0x7C, 0x83, 0x8F \
} \
}
/* dca5ae8a-769e-4e24-896b-7d06442c1c0e */
#define TEE_SERVICE_SECISP \
{ \
0xDCA5AE8A, \
0x769E, \
0x4E24, \
{ \
0x89, 0x6B, 0x7D, 0x06, 0x44, 0x2C, 0x1C, 0x0E \
} \
}
/* 5700f837-8b8e-4661-800b-42bb3fc3141f */
#define TEE_SERVICE_DRM_GRALLOC \
{ \
0x5700F837, \
0x8B8E, \
0x4661, \
{ \
0x80, 0x0B, 0x42, 0xBB, 0x3F, 0xC3, 0x14, 0x1F \
} \
}
enum SVC_SECBOOT_CMD_ID {
SECBOOT_CMD_ID_INVALID = 0x0,
SECBOOT_CMD_ID_COPY_VRL,
SECBOOT_CMD_ID_COPY_DATA,
SECBOOT_CMD_ID_VERIFY_DATA,
SECBOOT_CMD_ID_RESET_IMAGE,
SECBOOT_CMD_ID_COPY_VRL_TYPE,
SECBOOT_CMD_ID_COPY_DATA_TYPE,
SECBOOT_CMD_ID_VERIFY_DATA_TYPE,
SECBOOT_CMD_ID_VERIFY_DATA_TYPE_LOCAL,
SECBOOT_CMD_ID_COPY_IMG_TYPE,
SECBOOT_CMD_ID_BSP_MODEM_CALL,
SECBOOT_CMD_ID_BSP_MODULE_VERIFY,
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,
};
#ifdef CONFIG_SECBOOT_IMG
#define CAS 0xff
enum SVC_SECBOOT_IMG_TYPE {
MODEM,
DSP,
XDSP,
TAS,
WAS,
MODEM_COMM_IMG,
MODEM_DTB,
NVM,
NVM_S,
MBN_R,
MBN_A,
MODEM_COLD_PATCH,
DSP_COLD_PATCH,
MODEM_CERT,
MAX_SOC_MODEM,
HIFI,
ISP,
IVP,
SOC_MAX
};
#elif defined(CONFIG_SECBOOT_IMG_V2)
enum SVC_SECBOOT_IMG_TYPE {
HIFI,
ISP,
IVP,
MAX_AP_SOC,
MODEM_START = 0x100,
MODEM_END = 0x1FF,
MAX_SOC,
};
#else
enum SVC_SECBOOT_IMG_TYPE {
MODEM,
HIFI,
DSP,
XDSP,
TAS,
WAS,
CAS,
MODEM_DTB,
ISP,
#ifdef CONFIG_COLD_PATCH
MODEM_COLD_PATCH,
DSP_COLD_PATCH,
#endif
#ifdef CONFIG_RFIC_LOAD
RFIC,
#endif
SOC_MAX
};
#endif
#endif
+138
View File
@@ -0,0 +1,138 @@
/*
* teek_client_type.h
*
* define exported structures
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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_CLIENT_TYPE_H
#define TEE_CLIENT_TYPE_H
#include <linux/list.h>
#include "teek_client_constants.h"
#ifndef NULL
#define NULL 0
#endif
struct teec_uuid {
uint32_t time_low;
uint16_t time_mid;
uint16_t timehi_and_version;
uint8_t clockseq_and_node[8];
};
struct teec_context {
void *dev;
uint8_t *ta_path;
struct list_head shrd_mem_list;
};
struct teec_session {
uint32_t session_id;
struct teec_uuid service_id;
uint32_t ops_cnt;
struct teec_context *context;
};
struct teec_sharedmemory {
void *buffer;
uint32_t size;
uint32_t flags;
uint32_t ops_cnt;
bool is_allocated;
struct list_head head;
struct teec_context *context;
};
struct teec_tempmemory_reference {
void *buffer;
uint32_t size;
};
struct teec_registeredmemory_reference {
struct teec_sharedmemory *parent;
uint32_t size;
uint32_t offset;
};
struct teec_value {
uint32_t a;
uint32_t b;
};
struct teec_ion_reference {
int ion_share_fd;
uint32_t ion_size;
};
union teec_parameter {
struct teec_tempmemory_reference tmpref;
struct teec_registeredmemory_reference memref;
struct teec_value value;
struct teec_ion_reference ionref;
};
struct teec_tui_parameter {
uint32_t event_type;
/* tui event type */
uint32_t value;
/* return value, is keycode if tui event is getkeycode */
uint32_t notch; /* notch size of phone */
uint32_t width; /* width of foldable screen */
uint32_t height; /* height of foldable screen */
uint32_t fold_state; /* state of foldable screen */
uint32_t display_state; /* one state of folded state */
uint32_t phy_width; /* real width of the mobile */
uint32_t phy_height; /* real height of the mobile */
};
struct teec_operation {
uint32_t started;
uint32_t paramtypes;
union teec_parameter params[4]; /* GP has four params */
struct teec_session *session;
bool cancel_flag;
};
typedef uint32_t TEEC_Result;
typedef struct teec_uuid TEEC_UUID;
typedef struct teec_context TEEC_Context;
typedef struct teec_session TEEC_Session;
typedef struct teec_sharedmemory TEEC_SharedMemory;
typedef struct teec_tempmemory_reference TEEC_TempMemoryReference;
typedef struct teec_registeredmemory_reference TEEC_RegisteredMemoryReference;
typedef struct teec_value TEEC_Value;
typedef struct teec_ion_reference TEEC_IonReference;
typedef union teec_parameter TEEC_Parameter;
typedef struct teec_tui_parameter TEEC_TUI_Parameter;
typedef struct {
uint32_t started;
uint32_t paramTypes;
TEEC_Parameter params[4];
TEEC_Session *session;
bool cancel_flag;
} TEEC_Operation;
#endif
+240
View File
@@ -0,0 +1,240 @@
/*
* teek_ns_client.h
*
* define structures and IOCTLs.
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TEEK_NS_CLIENT_H
#define TEEK_NS_CLIENT_H
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/completion.h>
#include "tc_ns_client.h"
#include "tc_ns_log.h"
#define TC_NS_CLIENT_IOC_MAGIC 't'
#define TC_NS_CLIENT_DEV "tc_ns_client"
#define TC_PRIV_DEV "tc_private"
#define TC_NS_CLIENT_DEV_NAME "/dev/tc_ns_client"
#define EXCEPTION_MEM_SIZE (8*1024) /* mem for exception handling */
#ifdef CONFIG_THIRDPARTY_COMPATIBLE
#define TSP_REQUEST 0x32000008
#define TSP_RESPONSE 0xBE000005
#else
#define TSP_REQUEST 0xB2000008
#define TSP_RESPONSE 0xB2000009
#endif
#define TSP_REE_SIQ 0xB200000A
#define TSP_CRASH 0xB200000B
#define TSP_REBOOT 0xB200000E
#define TSP_CPU_ON 0xB200000F
#define TSP_REBOOT_DONE 0xB2000010
#define TSP_PREEMPTED 0xB2000005
#define TC_CALL_GLOBAL 0x01
#define TC_CALL_SYNC 0x02
#define TC_CALL_LOGIN 0x04
#define TEE_REQ_FROM_USER_MODE 0U
#define TEE_REQ_FROM_KERNEL_MODE 1U
#define TEE_PARAM_NUM 4
#define VMALLOC_TYPE 0
#define RESERVED_TYPE 1
/* Max sizes for login info buffer comming from teecd */
#define MAX_PACKAGE_NAME_LEN 255
/*
* The apk certificate format is as follows:
* modulus_size(4 bytes) + modulus buffer(512 bytes)
* + exponent size(4 bytes) + exponent buffer(1 bytes)
*/
#define MAX_PUBKEY_LEN 1024
struct tc_ns_dev_list {
struct mutex dev_lock; /* for dev_file_list */
struct list_head dev_file_list;
};
struct tc_uuid {
uint32_t time_low;
uint16_t time_mid;
uint16_t timehi_and_version;
uint8_t clockseq_and_node[8]; /* clock len is 8 */
};
#define INVALID_MAP_ADDR ((void*)-1)
struct tc_ns_shared_mem {
void *kernel_addr;
void *user_addr;
void *user_addr_ca; /* for ca alloc share mem */
unsigned int len;
int mem_type;
struct list_head head;
atomic_t usage;
atomic_t offset;
};
struct tc_ns_service {
unsigned char uuid[UUID_LEN];
struct mutex session_lock; /* for session_list */
struct list_head session_list;
struct list_head head;
struct mutex operation_lock; /* for session's open/close */
atomic_t usage;
};
#define SERVICES_MAX_COUNT 32 /* service limit can opened on 1 fd */
struct tc_ns_dev_file {
unsigned int dev_file_id;
struct mutex service_lock; /* for service_ref[], services[] */
uint8_t service_ref[SERVICES_MAX_COUNT]; /* a judge if set services[i]=NULL */
struct tc_ns_service *services[SERVICES_MAX_COUNT];
struct mutex shared_mem_lock; /* for shared_mem_list */
struct list_head shared_mem_list;
struct list_head head;
/* Device is linked to call from kernel */
uint8_t kernel_api;
/* client login info provided by teecd, can be either package name and public
* key or uid(for non android services/daemons)
* login information can only be set once, dont' allow subsequent calls
*/
bool login_setup;
struct mutex login_setup_lock; /* for login_setup */
#ifdef CONFIG_AUTH_HASH
bool cainfo_hash_setup;
struct mutex cainfo_hash_setup_lock;
#endif
uint32_t pkg_name_len;
uint8_t pkg_name[MAX_PACKAGE_NAME_LEN];
uint32_t pub_key_len;
uint8_t pub_key[MAX_PUBKEY_LEN];
int load_app_flag;
struct completion close_comp; /* for kthread close unclosed session */
};
union tc_ns_parameter {
struct {
unsigned int buffer;
unsigned int size;
} memref;
struct {
unsigned int a;
unsigned int b;
} value;
};
struct tc_ns_login {
unsigned int method;
unsigned int mdata;
};
struct tc_ns_operation {
unsigned int paramtypes;
union tc_ns_parameter params[TEE_PARAM_NUM];
unsigned int buffer_h_addr[TEE_PARAM_NUM];
struct tc_ns_shared_mem *sharemem[TEE_PARAM_NUM];
void *mb_buffer[TEE_PARAM_NUM];
};
struct tc_ns_temp_buf {
void *temp_buffer;
unsigned int size;
};
enum smc_cmd_type {
CMD_TYPE_GLOBAL,
CMD_TYPE_TA,
CMD_TYPE_TA_AGENT,
CMD_TYPE_TA2TA_AGENT, /* compatible with TA2TA2TA->AGENT etc. */
CMD_TYPE_BUILDIN_AGENT,
};
struct tc_ns_smc_cmd {
uint8_t uuid[sizeof(struct tc_uuid)];
unsigned int cmd_type;
unsigned int cmd_id;
unsigned int dev_file_id;
unsigned int context_id;
unsigned int agent_id;
unsigned int operation_phys;
unsigned int operation_h_phys;
unsigned int login_method;
unsigned int login_data_phy;
unsigned int login_data_h_addr;
unsigned int login_data_len;
unsigned int err_origin;
int ret_val;
unsigned int event_nr;
unsigned int uid;
unsigned int ca_pid; /* pid */
unsigned int pid; /* tgid */
unsigned int eventindex; /* tee audit event index for upload */
bool started;
} __attribute__((__packed__));
/*
* @brief
*/
struct tc_wait_data {
wait_queue_head_t send_cmd_wq;
int send_wait_flag;
};
#define NUM_OF_SO 1
#ifdef CONFIG_CMS_CAHASH_AUTH
#define KIND_OF_SO 1 /* the number of libteecxxx.so library on MDC\DC\TI */
#else
#define KIND_OF_SO 2 /* the number of libteecxxx.so library on OH\HO */
#endif
struct tc_ns_session {
unsigned int session_id;
struct list_head head;
struct tc_wait_data wait_data;
struct mutex ta_session_lock; /* for open/close/invoke on 1 session */
struct tc_ns_dev_file *owner;
uint8_t auth_hash_buf[MAX_SHA_256_SZ * NUM_OF_SO + MAX_SHA_256_SZ];
atomic_t usage;
};
struct mb_cmd_pack {
struct tc_ns_operation operation;
unsigned char login_data[MAX_SHA_256_SZ * NUM_OF_SO + MAX_SHA_256_SZ];
};
struct load_img_params {
struct tc_ns_dev_file *dev_file;
const char *file_buffer;
unsigned int file_size;
struct mb_cmd_pack *mb_pack;
char *mb_load_mem;
struct tc_uuid *uuid_return;
unsigned int mb_load_size;
};
struct tc_call_params {
struct tc_ns_dev_file *dev;
struct tc_ns_client_context *context;
struct tc_ns_session *sess;
uint8_t flags;
};
struct tc_op_params {
struct mb_cmd_pack *mb_pack;
struct tc_ns_smc_cmd *smc_cmd;
struct tc_ns_temp_buf local_tmpbuf[TEE_PARAM_NUM];
uint32_t trans_paramtype[TEE_PARAM_NUM];
bool op_inited;
};
#endif
+46
View File
@@ -0,0 +1,46 @@
config TEELOG
bool "Secure Execution Log Driver"
default n
depends on TZDRIVER
help
TEEOS log
config TEE_LOG_ACHIVE_PATH
string "Tee log achive path"
default "/data/log/tee/last_teemsg"
depends on TEELOG
help
Last tee msg log path
config TEE_LOG_EXCEPTION
bool "Log Exception Info to Imonitor"
default n
depends on TEELOG
help
Log exception info to imonitor
choice
prompt "Register tee log Mem"
default PAGES_MEM
depends on TEELOG
config RDR_MEM
bool "Register rdr log mem"
depends on DFX_BB
help
Register rdr log mem
config BBOX_MEM
bool "Register bbox log mem"
depends on MNTN
help
Register bbox log mem
config PAGES_MEM
bool "Register pages log mem"
help
Register pages log mem
endchoice
+19
View File
@@ -0,0 +1,19 @@
KERNEL_DIR := $(srctree)
ifneq ($(TARGET_BUILD_VARIANT), user)
ccflags-y += -DDEF_ENG
endif
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../third_party/bounds_checking_function/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/include
ifeq ($(CONFIG_TZDRIVER_INTERNAL), y)
include $(KERNEL_DIR)/drivers/tzdriver/tzdriver_internal/internal.mk
endif
obj-$(CONFIG_TEELOG) += tlogger.o
# For tee log memory type: bbox, rdr, or pages
# If no log mechanism is available, the pages memory can be used.
obj-$(CONFIG_PAGES_MEM) += log_pages_cfg.o
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: for log cfg api define
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 LOG_CFG_API_H
#define LOG_CFG_API_H
#include <linux/types.h>
#if ((defined(CONFIG_BBOX_MEM) || defined(CONFIG_RDR_MEM) || \
defined(CONFIG_PAGES_MEM)) && defined(CONFIG_TEELOG))
int register_log_mem(uint64_t *addr, uint32_t *len);
int register_log_exception(void);
void report_log_system_error(void);
void report_log_system_panic(void);
int *map_log_mem(uint64_t mem_addr, uint32_t mem_len);
void unmap_log_mem(int *log_buffer);
void get_log_chown(uid_t *user, gid_t *group);
void unregister_log_exception(void);
void ta_crash_report_log(void);
#else
static inline int register_log_mem(const uint64_t *addr, const uint32_t *len)
{
(void)addr;
(void)len;
return 0;
}
static inline int register_log_exception(void)
{
return 0;
}
static inline void report_log_system_error(void)
{
}
static inline void report_log_system_panic(void)
{
}
static inline int *map_log_mem(uint64_t mem_addr, uint32_t mem_len)
{
(void)mem_addr;
(void)mem_len;
return NULL;
}
static inline void unmap_log_mem(const int *log_buffer)
{
(void)log_buffer;
}
static inline void get_log_chown(const uid_t *user, const gid_t *group)
{
(void)user;
(void)group;
}
static inline void unregister_log_exception(void)
{
}
static inline void ta_crash_report_log(void)
{
}
#endif
#endif
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: for pages log cfg api define
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 "log_cfg_api.h"
#include <linux/sizes.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/semaphore.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/stat.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include <linux/slab.h>
#include <securec.h>
#include "tc_ns_log.h"
#include "tlogger.h"
#include "shared_mem.h"
void unregister_log_exception(void)
{
}
int register_log_exception(void)
{
return 0;
}
struct pages_module_result {
uint64_t log_addr;
uint32_t log_len;
};
struct pages_module_result g_mem_info = {0};
static int tee_pages_register_core(void)
{
if (g_mem_info.log_addr != 0 || g_mem_info.log_len != 0) {
if (memset_s((void *)g_mem_info.log_addr, g_mem_info.log_len, 0, g_mem_info.log_len) != 0) {
tloge("clean log memory failed\n");
return -EFAULT;
}
return 0;
}
g_mem_info.log_addr = get_log_mem_vaddr();
if (IS_ERR_OR_NULL((void *)(uintptr_t)g_mem_info.log_addr)) {
tloge("get log mem error\n");
return -1;
}
g_mem_info.log_len = PAGES_LOG_MEM_LEN;
return 0;
}
/* Register log memory */
int register_log_mem(uint64_t *addr, uint32_t *len)
{
int ret;
uint64_t mem_addr;
uint32_t mem_len;
if (!addr || !len) {
tloge("addr or len is invalid\n");
return -1;
}
ret = tee_pages_register_core();
if (ret != 0)
return ret;
mem_addr = get_log_mem_paddr(g_mem_info.log_addr);
mem_len = g_mem_info.log_len;
ret = register_mem_to_teeos(mem_addr, mem_len, true);
if (ret != 0)
return ret;
*addr = g_mem_info.log_addr;
*len = g_mem_info.log_len;
return ret;
}
void report_log_system_error(void)
{
}
void report_log_system_panic(void)
{
/* default support trigger ap reset */
#ifndef NOT_TRIGGER_AP_RESET
panic("TEEOS panic\n");
#endif
}
void ta_crash_report_log(void)
{
}
int *map_log_mem(uint64_t mem_addr, uint32_t mem_len)
{
(void)mem_len;
return (int *)(uintptr_t)mem_addr;
}
void unmap_log_mem(int *log_buffer)
{
free_log_mem((uint64_t)(uintptr_t)log_buffer);
}
void get_log_chown(uid_t *user, gid_t *group)
{
if (!user || !group) {
tloge("user or group buffer is null\n");
return;
}
*user = ROOT_UID;
*group = FILE_CHOWN_GID;
}
File diff suppressed because it is too large Load Diff
+70
View File
@@ -0,0 +1,70 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
* Decription: TEE Logging Subsystem, read the tee os log from rdr memory
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TLOGGER_H
#define TLOGGER_H
#include <linux/types.h>
#define OPEN_FILE_MODE 0640U
#define ROOT_UID 0
#define ROOT_GID 0
#define SYSTEM_GID 1000
#ifdef LAST_TEE_MSG_ROOT_GID
#define FILE_CHOWN_GID 0
#else
/* system gid for last_teemsg file sys chown */
#define FILE_CHOWN_GID 1000
#endif
#define UINT64_MAX (uint64_t)(~((uint64_t)0)) /* 0xFFFFFFFFFFFFFFFF */
#ifdef CONFIG_TEELOG
void tz_log_write(void);
int tlogger_store_msg(const char *file_path, uint32_t file_path_len);
int register_mem_to_teeos(uint64_t mem_addr, uint32_t mem_len, bool is_cache_mem);
#ifdef CONFIG_TZDRIVER_MODULE
int init_tlogger_service(void);
void free_tlogger_service(void);
int register_tloger_mem(void);
#endif
#else
static inline void tz_log_write(void)
{
return;
}
static inline int tlogger_store_msg(const char *file_path, uint32_t file_path_len)
{
(void)file_path;
(void)file_path_len;
return 0;
}
static inline int register_mem_to_teeos(uint64_t mem_addr, uint32_t mem_len,
bool is_cache_mem)
{
(void)mem_addr;
(void)mem_len;
return 0;
}
static inline int init_tlogger_service(void)
{
return 0;
}
static inline void free_tlogger_service(void)
{
}
#endif
#endif
+1
View File
@@ -0,0 +1 @@
tui/tui.h
+20
View File
@@ -0,0 +1,20 @@
config TEE_TUI
bool "Trusted User Interface Driver"
default n
depends on TZDRIVER
help
Trusted user interface driver
config TEE_TUI_FP
bool "Trusted User Interface Driver for FP"
default n
depends on TZDRIVER
help
Trusted user interface driver
config TEE_TUI_DISPLAY_3_0
bool "Trusted User Interface Driver for DSS3.0"
default n
depends on TEE_TUI
help
Trusted user interface driver
+48
View File
@@ -0,0 +1,48 @@
KERNEL_DIR :=$(srctree)
ifneq ($(TARGET_BUILD_VARIANT), user)
ccflags-y += -DDEBUG_TUI
endif
ifeq ($(CONFIG_TZDRIVER_OHOS),y)
EXTRA_CFLAGS += -DTUI_DAEMON_UID_IN_OH=6668
endif
ifeq ($(CONFIG_TEE_TUI_MTK), y)
EXTRA_CFLAGS += -Idrivers/tzdriver
EXTRA_CFLAGS += -Idrivers/tzdriver/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../third_party/bounds_checking_function/include
EXTRA_CFLAGS += -Idrivers/gpu/drm/mediatek
EXTRA_CFLAGS += -Idrivers/misc/mediatek/memory-ssmr
EXTRA_CFLAGS += -Idrivers/devkit/lcdkit/lcdkit3.0/kernel/mtk/include
EXTRA_CFLAGS += -Idrivers/devkit/lcdkit/lcdkit3.0/kernel/common/include
EXTRA_CFLAGS += -Idrivers/devkit/lcdkit/lcdkit3.0/kernel/mtk/adapt
else
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver/core
ifeq ($(CONFIG_TEE_TUI_DISPLAY_3_0), y)
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/dkmd/dksm
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/fbdev/dkmd/dksm
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/dkmd/dpu/begonia
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/fbdev/dkmd/dpu/begonia
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/dkmd/dpu/begonia/composer
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/fbdev/dkmd/dpu/begonia/composer
EXTRA_CFLAGS += -I$(KERNEL_DIR)/include/platform_include/display/dkmd
else
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/dkmd/dpu/azalea
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/fbdev/dkmd/dpu/azalea
endif
endif
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver/ion
EXTRA_CFLAGS += -include internal_functions.h
ifeq ($(CONFIG_HW_SECMEM), y)
EXTRA_CFLAGS += -Idrivers/uni_drivers/secmem
endif
obj-$(CONFIG_TEE_TUI) += tui.o
+2015
View File
File diff suppressed because it is too large Load Diff
+275
View File
@@ -0,0 +1,275 @@
/*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 TUI_H
#define TUI_H
#include "teek_ns_client.h"
#include "teek_client_type.h"
#define TEE_TUI_AGENT_ID 0x54554944 /* TUID */
/* tui states */
#define TUI_STATE_UNUSED 0
#define TUI_STATE_CONFIG 1
#define TUI_STATE_RUNNING 2
#define TUI_STATE_ERROR 3
#define TUI_PID_CLEAR 0
#define TUI_PID_CONFIG 1
/* command from secure os */
#define TUI_CMD_ENABLE 1
#define TUI_CMD_DISABLE 2
#define TUI_CMD_POLL 3
#define TUI_CMD_SET_STATE 4
#define TUI_CMD_PAUSE 5
#define TUI_CMD_DO_SYNC 6
#define TUI_CMD_START_DELAY_WORK 7
#define TUI_CMD_CANCEL_DELAY_WORK 8
#define TUI_CMD_LOAD_TTF 9
#define TUI_CMD_FREE_TTF_MEM 11
#define TUI_CMD_EXIT 12
#define TUI_DRV_NAME_MAX 32
/* poll event type from normal to secure */
enum tui_poll_type {
TUI_POLL_CFG_OK,
TUI_POLL_CFG_FAIL,
TUI_POLL_TP,
TUI_POLL_TICK,
TUI_POLL_DELAYED_WORK,
TUI_POLL_TIMEOUT,
TUI_POLL_RESUME_TUI,
/* For some reasons, we need a method to terminate TUI from no secure
* OS, for example the TUI CA maybe killed.
*/
TUI_POLL_CANCEL,
TUI_POLL_HANDLE_TUI, /* for tui to handle event */
TUI_POLL_NAVI_H_TO_S, /* for navigator hide and show */
TUI_POLL_NAVI_S_TO_H,
TUI_POLL_SHS_0_TO_1, /* for single hand mode switch */
TUI_POLL_SHS_0_TO_2,
TUI_POLL_SHS_1_TO_0,
TUI_POLL_SHS_2_TO_0,
TUI_POLL_ROTATION_0, /* for retation switch */
TUI_POLL_ROTATION_90,
TUI_POLL_ROTATION_180,
TUI_POLL_ROTATION_270,
TUI_POLL_KEYBOARDTYPE_0,
TUI_POLL_KEYBOARDTYPE_3,
TUI_POLL_SEMITRANS,
TUI_POLL_CURSOR,
TUI_POLL_GETFP,
TUI_POLL_NOTCH, /* for tui to get notch height */
TUI_POLL_DIALOGTIMEOUT,
TUI_POLL_FOLD, /* for tui to get fold_screen */
TUI_POLL_MAX /* Do Not add type behind this one */
};
/* tui max should be bigger than TUI_POLL_MAX in tui.h */
static const char *const poll_event_type_name[] = {
"config-ok",
"config-fail",
"tp",
"tui-tick",
"tui-delaywork",
"tui-pause",
"tui-resume",
"tui-terminate",
"tui-handle",
"tui-hs",
"tui-sh",
"tui-01",
"tui-02",
"tui-10",
"tui-20",
"tui-0",
"tui-90",
"tui-180",
"tui-270",
"tui_key_board_type0",
"tui_key_board_type3",
"tui-SEMI",
"tui-cursor",
"tui-gettp",
"tui-notch",
"tui-dialogtimeout",
"tui-fold",
"tui-max"
};
static const char *const state_name[] = {
"unused",
"config",
"running",
"error"
};
struct tui_ctl_shm {
struct {
int command;
int value;
int ret;
} s2n;
struct {
int event_type;
int value;
unsigned int addr;
unsigned int addr_h;
int tp_info;
int tp_info_h_addr;
int status;
int x;
int y;
uint32_t npages;
uint64_t info_length;
uint32_t phy_size;
} n2s;
};
struct tui_msg_node {
int type;
int val;
void *data;
struct list_head list;
};
typedef int (*tui_drv_init) (void *pdata, int secure);
struct tui_drv_node {
tui_drv_init init_func;
void *pdata;
char name[TUI_DRV_NAME_MAX];
int state;
int priority;
struct list_head list;
};
/* tui need memory is calculated dynamically according to the screen resolution */
struct tui_mem {
unsigned int tui_addr_size;
unsigned int tui_addr;
unsigned int tui_addr_h;
struct device *tui_dev;
char *tui_virt;
};
struct ttf_mem {
unsigned int ttf_addr_h;
unsigned int ttf_addr_l;
char *ttf_buff_virt;
unsigned int ttf_file_size;
};
typedef struct tui_memory {
phys_addr_t tui_ion_phys_addr;
void *tui_ion_virt_addr;
size_t len;
uint32_t size;
uint32_t configid;
struct sg_table *tui_sg_table;
phys_addr_t fb_phys_addr;
uint32_t npages;
uint64_t info_length;
} tui_ion_mem;
#ifdef CONFIG_TEE_TUI
extern int ts_tui_report_input(void *finger_data);
extern int tui_fp_notify(void);
int __init init_tui(const struct device *dev);
void free_tui(void);
int tui_send_event(int event, struct teec_tui_parameter *tui_param);
int register_tui_driver(tui_drv_init fun, const char *name,
void *pdata);
void unregister_tui_driver(const char *name);
/*
* TUI has different state that can recieve given types of message,
* there are 3 APIs to send message.
* send_tui_msg_config:send message to TUI in config state only.
*/
int send_tui_msg_config(int type, int val, void *data);
void tui_poweroff_work_start(void);
void set_tui_caller_info(unsigned int devid, int pid);
void free_tui_caller_info(void);
unsigned int tui_attach_device(void);
void do_ns_tui_release(void);
int is_tui_in_use(int pid_value);
int tc_ns_tui_event(struct tc_ns_dev_file *dev_file, const void *argp);
bool is_tui_agent(unsigned int agent_id);
#else
static inline bool is_tui_agent(unsigned int agent_id)
{
(void)agent_id;
return false;
}
static inline int init_tui(const struct device *dev)
{
(void)dev;
return 0;
}
static inline void free_tui(void)
{
}
static inline void unregister_tui_driver(const char *name)
{
(void)name;
}
static inline int send_tui_msg_config(int type, int val, const void *data)
{
(void)type;
(void)val;
(void)data;
return 0;
}
static inline void set_tui_caller_info(unsigned int devid, int pid)
{
(void)devid;
(void)pid;
}
static inline void free_tui_caller_info(void)
{
}
static inline unsigned int tui_attach_device(void)
{
return 0;
}
static inline int is_tui_in_use(int pid_value)
{
(void)pid_value;
return 0;
}
static inline void do_ns_tui_release(void)
{
}
static inline int tc_ns_tui_event(struct tc_ns_dev_file *dev_file, const void *argp)
{
(void)dev_file;
(void)argp;
return 0;
}
#endif
#endif
+14
View File
@@ -0,0 +1,14 @@
KERNEL_DIR := $(srctree)
ifneq ($(TARGET_BUILD_VARIANT), user)
ccflags-y += -DDEF_ENG
endif
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../third_party/bounds_checking_function/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/include
EXTRA_CFLAGS += -include internal_functions.h
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/core
obj-y += agent_allowed_ca.o

Some files were not shown because too many files have changed in this diff Show More