!94 move tzdriver to common_modules

Merge pull request !94 from suwanghw/master
This commit is contained in:
openharmony_ci
2024-01-02 07:59:05 +00:00
committed by Gitee
105 changed files with 23928 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/
+4
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>
@@ -93,6 +96,7 @@ Note:If the text contains special characters, please escape them according to th
<filteritem type="filepath" name="xpm/figures/.*"/>
<filteritem type="filepath" name="qos_auth/figures/.*"/>
<filteritem type="filepath" name="ucollection/figures/.*"/>
<filteritem type="filepath" name="tzdriver/figures/.*"/>
</filefilter>
</filefilterlist>
</oatconfig>
+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
+78
View File
@@ -0,0 +1,78 @@
# Tzdriver driver
## Introduction
Tzdriver is a kernel driver deployed on the REE side, supporting communication between REE and TEE. Tzdriver processes commands from Tee Client and sends instructions to switch from REE to TEE. Tzdriver supports data sharing between REE and TEE by managing shared memory.
Tzdriver includes the following main modules:
smc: Send smc instructions to switch the CPU from the REE side to the TEE side for operation.
session_manager: Manage communication sessions between REE and TEE.
mailboxData is shared between REE and TEE through the mailbox.
cmd_monitorMonitor the operation of SMC instructions and provides a timeout detection mechanism.
tzdebugCreate debugfs debugging nodes to facilitate developers in debugging TEE functionality
tloggerTEE log driver module, supporting TEE log recording and printing.
Figure 1: Tzdriver architecture diagram
![](figures/tzdriver.drawio_en.png)
## Directory
```
/kernel/linux/common_modules/tzdriver
├── core
│ ├── cmdmonitor.c # SMC instruction execution monitoring
├── gp_ops.c # GP TEE specification processing logic
├── mailbox_mempool.c # REE and TEE shared memory management
├── session_manager.c # Session management for CA access to TA
├── smc_smp.c # Send SMC command to switch to TEE
├── tzdebug.c # Debugging module
├── tlogger # TEE log driver
```
## Configuration Option
If you want to enable the Tzdriver driver, you need to modify the defconfig file of the device in the Linux kernel code repository and add configuration options for Tzdriver:
```
#
# TEEOS
#
CONFIG_TZDRIVER=y
CONFIG_CPU_AFF_NR=1
CONFIG_KERNEL_CLIENT=y
CONFIG_TEELOG=y
CONFIG_PAGES_MEM=y
CONFIG_THIRDPARTY_COMPATIBLE=y
```
The meanings of each option are shown in the table below:
**Table 1** Configuration Options Description
| Parameters | Description |
| ---------------------------- | ------------------------------------------------------------ |
| CONFIG_TZDRIVER | Tzdriver module switch. |
| CONFIG_CPU_AFF_NR | CA binding core function, non-zero values represent restrictions on CPUID less than CONFIG_ CPU_ AFF_ NR's CPU can enter TEE, where 0 represents unlimited. Currently, Tzdriver only supports running on 0 cores, so the value is 1. |
| CONFIG_KERNEL_CLIENT | Support the kernel CA option. |
| CONFIG_TEELOG | TEE log switch, it is recommended to enable. |
| CONFIG_PAGES_MEM | TEE log memory management, it is recommended to enable. |
| CONFIG_THIRDPARTY_COMPATIBLE | Used for compatibility with third-party optee, such as the RK3568 chip, which requires this option to be enabled. |
## Compile Command
Tzdriver is compiled together with the kernel. Taking the rk3568 chip as an example, the "boot_linux.img" can be compiled separately. The compilation command is as follows
```
./build.sh --product-name rk3568 --ccache --build-target kernel --gn-args linux_kernel_version=\"linux-5.10\"
```
## Related code repository
[tee_client](https://gitee.com/openharmony/tee_tee_client)
+78
View File
@@ -0,0 +1,78 @@
# Tzdriver驱动
## 简介
Tzdriver是部署在REE侧的内核驱动,支持REE和TEE之间通信。Tzdriver处理来自于Tee Client的命令,发送指令从REE切换到TEE。Tzdriver通过管理共享内存,支持REE和TEE之间共享数据。
Tzdriver驱动包含如下主要模块:
smc:发送smc指令,将CPU从REE侧切换到TEE侧运行。
session_manager:管理REE与TEE之间的通信会话。
mailboxREE和TEE之间通过mailbox共享数据。
cmd_monitor:监控smc指令的运行,提供超时检测机制。
tzdebug:创建debugfs调试节点,方便开发人员调试TEE功能。
tlogger:TEE日志驱动模块,支持TEE日志记录和打印。
图1 Tzdriver驱动架构图
![](figures/tzdriver.drawio.png)
## 目录
```
/kernel/linux/common_modules/tzdriver
├── core
│ ├── cmdmonitor.c # smc指令执行监控
├── gp_ops.c # GP TEE规范处理逻辑
├── mailbox_mempool.c # REE和TEE共享内存管理
├── session_manager.c # CA访问TA的session管理
├── smc_smp.c # 发送smc指令切换到TEE
├── tzdebug.c # 调试模块
├── tlogger # TEE日志驱动
```
## 配置选项
如果要使能Tzdriver驱动,需要修改linux内核代码仓中设备的defconfig文件,增加Tzdriver的配置选项:
```
#
# TEEOS
#
CONFIG_TZDRIVER=y
CONFIG_CPU_AFF_NR=1
CONFIG_KERNEL_CLIENT=y
CONFIG_TEELOG=y
CONFIG_PAGES_MEM=y
CONFIG_THIRDPARTY_COMPATIBLE=y
```
各选项其含义如下表所示:
**表 1** 配置选项说明
| 参数 | 说明 |
| ---------------------------- | ------------------------------------------------------------ |
| CONFIG_TZDRIVER | Tzdriver模块开关。 |
| CONFIG_CPU_AFF_NR | CA绑核功能,非零值代表限制仅cpuid小于CONFIG_CPU_AFF_NR的CPU可以进入TEE,0代表无限制,当前只支持在0核运行,所以值为1。 |
| CONFIG_KERNEL_CLIENT | 支持内核CA选项。 |
| CONFIG_TEELOG | TEE日志开关,建议开启。 |
| CONFIG_PAGES_MEM | TEE日志内存管理,建议开启。 |
| CONFIG_THIRDPARTY_COMPATIBLE | 兼容第三方opteed的适配,例如适配RK3568芯片需要开启此选项。 |
## 编译命令
Tzdriver驱动跟随kernel一起编译,以rk3568为例,可以单独编译boot_linux.img,编译命令如下
```
./build.sh --product-name rk3568 --ccache --build-target kernel --gn-args linux_kernel_version=\"linux-5.10\"
```
## 相关仓
[tee_client](https://gitee.com/openharmony/tee_tee_client)
+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
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

+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

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