mirror of
https://github.com/openharmony/kernel_linux_common_modules.git
synced 2026-08-27 19:49:56 -04:00
@@ -1,5 +1,6 @@
|
||||
(1) The directories below are licensed under GPL-2.0-or-later.
|
||||
./newip/
|
||||
./tzdriver/
|
||||
./xpm/
|
||||
./qos_auth/
|
||||
./ucollection/
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
add_device_ko(LOCAL_MODULE tzdriver
|
||||
KO_SRC_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
core/agent.h
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
config RPMB_AGENT
|
||||
bool "Tzdriver Rpmb Agent"
|
||||
default n
|
||||
depends on TZDRIVER
|
||||
help
|
||||
Tzdriver Rpmb Agent
|
||||
Executable
+35
@@ -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
|
||||
Executable
+331
@@ -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);
|
||||
Executable
+29
@@ -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
|
||||
Executable
+26
@@ -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);
|
||||
}
|
||||
Executable
+65
@@ -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
|
||||
Executable
+76
@@ -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__ */
|
||||
Executable
+46
@@ -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);
|
||||
}
|
||||
Executable
+34
@@ -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
|
||||
Executable
+511
@@ -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;
|
||||
}
|
||||
Executable
+34
@@ -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
|
||||
Executable
+28
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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 (¤t->cpus_mask)
|
||||
#else
|
||||
#define CURRENT_CPUS_ALLOWED (¤t->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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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(©) == 0) {
|
||||
switch (copy.entry_type) {
|
||||
case NOTIFY_DATA_ENTRY_TIMER:
|
||||
case NOTIFY_DATA_ENTRY_RTC:
|
||||
tc_notify_timer_fn(©);
|
||||
break;
|
||||
case NOTIFY_DATA_ENTRY_WAKEUP:
|
||||
tc_notify_wakeup_fn(©);
|
||||
break;
|
||||
case NOTIFY_DATA_ENTRY_SHADOW:
|
||||
tc_notify_shadow_fn(©);
|
||||
break;
|
||||
case NOTIFY_DATA_ENTRY_FIQSHD:
|
||||
tc_notify_fiqshd_fn(©);
|
||||
break;
|
||||
case NOTIFY_DATA_ENTRY_SHADOW_EXIT:
|
||||
tc_notify_shadowexit_fn(©);
|
||||
break;
|
||||
#ifdef CONFIG_TA_AFFINITY
|
||||
case NOTIFY_DATA_ENTRY_SET_AFFINITY:
|
||||
tc_notify_set_affinity(©);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
tloge("invalid entry type = %u\n", copy.entry_type);
|
||||
}
|
||||
if (memset_s(©, 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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
ion/dynamic_ion_mem.h
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
Executable
+78
@@ -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
|
||||
Executable
+197
@@ -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
|
||||
Executable
+67
@@ -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
|
||||
Executable
+183
@@ -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
|
||||
Executable
+214
@@ -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
|
||||
Executable
+27
@@ -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
|
||||
Executable
+139
@@ -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
|
||||
Executable
+138
@@ -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
|
||||
Executable
+240
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
tui/tui.h
|
||||
@@ -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
|
||||
@@ -0,0 +1,48 @@
|
||||
KERNEL_DIR :=$(srctree)
|
||||
|
||||
ifneq ($(TARGET_BUILD_VARIANT), user)
|
||||
ccflags-y += -DDEBUG_TUI
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_TZDRIVER_OHOS),y)
|
||||
EXTRA_CFLAGS += -DTUI_DAEMON_UID_IN_OH=6668
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_TEE_TUI_MTK), y)
|
||||
EXTRA_CFLAGS += -Idrivers/tzdriver
|
||||
EXTRA_CFLAGS += -Idrivers/tzdriver/core
|
||||
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../third_party/bounds_checking_function/include
|
||||
EXTRA_CFLAGS += -Idrivers/gpu/drm/mediatek
|
||||
EXTRA_CFLAGS += -Idrivers/misc/mediatek/memory-ssmr
|
||||
EXTRA_CFLAGS += -Idrivers/devkit/lcdkit/lcdkit3.0/kernel/mtk/include
|
||||
EXTRA_CFLAGS += -Idrivers/devkit/lcdkit/lcdkit3.0/kernel/common/include
|
||||
EXTRA_CFLAGS += -Idrivers/devkit/lcdkit/lcdkit3.0/kernel/mtk/adapt
|
||||
else
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver/core
|
||||
|
||||
ifeq ($(CONFIG_TEE_TUI_DISPLAY_3_0), y)
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/dkmd/dksm
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/fbdev/dkmd/dksm
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/dkmd/dpu/begonia
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/fbdev/dkmd/dpu/begonia
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/dkmd/dpu/begonia/composer
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/fbdev/dkmd/dpu/begonia/composer
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/include/platform_include/display/dkmd
|
||||
else
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/dkmd/dpu/azalea
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/video/fbdev/dkmd/dpu/azalea
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver/include
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/platform_drivers/tzdriver/ion
|
||||
EXTRA_CFLAGS += -include internal_functions.h
|
||||
|
||||
ifeq ($(CONFIG_HW_SECMEM), y)
|
||||
EXTRA_CFLAGS += -Idrivers/uni_drivers/secmem
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_TEE_TUI) += tui.o
|
||||
+2015
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef TUI_H
|
||||
#define TUI_H
|
||||
|
||||
#include "teek_ns_client.h"
|
||||
#include "teek_client_type.h"
|
||||
|
||||
#define TEE_TUI_AGENT_ID 0x54554944 /* TUID */
|
||||
|
||||
/* tui states */
|
||||
#define TUI_STATE_UNUSED 0
|
||||
#define TUI_STATE_CONFIG 1
|
||||
#define TUI_STATE_RUNNING 2
|
||||
#define TUI_STATE_ERROR 3
|
||||
|
||||
#define TUI_PID_CLEAR 0
|
||||
#define TUI_PID_CONFIG 1
|
||||
/* command from secure os */
|
||||
#define TUI_CMD_ENABLE 1
|
||||
#define TUI_CMD_DISABLE 2
|
||||
#define TUI_CMD_POLL 3
|
||||
#define TUI_CMD_SET_STATE 4
|
||||
#define TUI_CMD_PAUSE 5
|
||||
#define TUI_CMD_DO_SYNC 6
|
||||
#define TUI_CMD_START_DELAY_WORK 7
|
||||
#define TUI_CMD_CANCEL_DELAY_WORK 8
|
||||
#define TUI_CMD_LOAD_TTF 9
|
||||
#define TUI_CMD_FREE_TTF_MEM 11
|
||||
#define TUI_CMD_EXIT 12
|
||||
|
||||
#define TUI_DRV_NAME_MAX 32
|
||||
|
||||
/* poll event type from normal to secure */
|
||||
enum tui_poll_type {
|
||||
TUI_POLL_CFG_OK,
|
||||
TUI_POLL_CFG_FAIL,
|
||||
TUI_POLL_TP,
|
||||
TUI_POLL_TICK,
|
||||
TUI_POLL_DELAYED_WORK,
|
||||
TUI_POLL_TIMEOUT,
|
||||
TUI_POLL_RESUME_TUI,
|
||||
/* For some reasons, we need a method to terminate TUI from no secure
|
||||
* OS, for example the TUI CA maybe killed.
|
||||
*/
|
||||
TUI_POLL_CANCEL,
|
||||
TUI_POLL_HANDLE_TUI, /* for tui to handle event */
|
||||
TUI_POLL_NAVI_H_TO_S, /* for navigator hide and show */
|
||||
TUI_POLL_NAVI_S_TO_H,
|
||||
TUI_POLL_SHS_0_TO_1, /* for single hand mode switch */
|
||||
TUI_POLL_SHS_0_TO_2,
|
||||
TUI_POLL_SHS_1_TO_0,
|
||||
TUI_POLL_SHS_2_TO_0,
|
||||
TUI_POLL_ROTATION_0, /* for retation switch */
|
||||
TUI_POLL_ROTATION_90,
|
||||
TUI_POLL_ROTATION_180,
|
||||
TUI_POLL_ROTATION_270,
|
||||
TUI_POLL_KEYBOARDTYPE_0,
|
||||
TUI_POLL_KEYBOARDTYPE_3,
|
||||
TUI_POLL_SEMITRANS,
|
||||
TUI_POLL_CURSOR,
|
||||
TUI_POLL_GETFP,
|
||||
TUI_POLL_NOTCH, /* for tui to get notch height */
|
||||
TUI_POLL_DIALOGTIMEOUT,
|
||||
TUI_POLL_FOLD, /* for tui to get fold_screen */
|
||||
TUI_POLL_MAX /* Do Not add type behind this one */
|
||||
};
|
||||
|
||||
/* tui max should be bigger than TUI_POLL_MAX in tui.h */
|
||||
static const char *const poll_event_type_name[] = {
|
||||
"config-ok",
|
||||
"config-fail",
|
||||
"tp",
|
||||
"tui-tick",
|
||||
"tui-delaywork",
|
||||
"tui-pause",
|
||||
"tui-resume",
|
||||
"tui-terminate",
|
||||
"tui-handle",
|
||||
"tui-hs",
|
||||
"tui-sh",
|
||||
"tui-01",
|
||||
"tui-02",
|
||||
"tui-10",
|
||||
"tui-20",
|
||||
"tui-0",
|
||||
"tui-90",
|
||||
"tui-180",
|
||||
"tui-270",
|
||||
"tui_key_board_type0",
|
||||
"tui_key_board_type3",
|
||||
"tui-SEMI",
|
||||
"tui-cursor",
|
||||
"tui-gettp",
|
||||
"tui-notch",
|
||||
"tui-dialogtimeout",
|
||||
"tui-fold",
|
||||
"tui-max"
|
||||
};
|
||||
|
||||
static const char *const state_name[] = {
|
||||
"unused",
|
||||
"config",
|
||||
"running",
|
||||
"error"
|
||||
};
|
||||
|
||||
struct tui_ctl_shm {
|
||||
struct {
|
||||
int command;
|
||||
int value;
|
||||
int ret;
|
||||
} s2n;
|
||||
struct {
|
||||
int event_type;
|
||||
int value;
|
||||
unsigned int addr;
|
||||
unsigned int addr_h;
|
||||
int tp_info;
|
||||
int tp_info_h_addr;
|
||||
int status;
|
||||
int x;
|
||||
int y;
|
||||
uint32_t npages;
|
||||
uint64_t info_length;
|
||||
uint32_t phy_size;
|
||||
} n2s;
|
||||
};
|
||||
|
||||
struct tui_msg_node {
|
||||
int type;
|
||||
int val;
|
||||
void *data;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
typedef int (*tui_drv_init) (void *pdata, int secure);
|
||||
|
||||
struct tui_drv_node {
|
||||
tui_drv_init init_func;
|
||||
void *pdata;
|
||||
char name[TUI_DRV_NAME_MAX];
|
||||
int state;
|
||||
int priority;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/* tui need memory is calculated dynamically according to the screen resolution */
|
||||
struct tui_mem {
|
||||
unsigned int tui_addr_size;
|
||||
unsigned int tui_addr;
|
||||
unsigned int tui_addr_h;
|
||||
struct device *tui_dev;
|
||||
char *tui_virt;
|
||||
};
|
||||
|
||||
struct ttf_mem {
|
||||
unsigned int ttf_addr_h;
|
||||
unsigned int ttf_addr_l;
|
||||
char *ttf_buff_virt;
|
||||
unsigned int ttf_file_size;
|
||||
};
|
||||
|
||||
typedef struct tui_memory {
|
||||
phys_addr_t tui_ion_phys_addr;
|
||||
void *tui_ion_virt_addr;
|
||||
size_t len;
|
||||
uint32_t size;
|
||||
uint32_t configid;
|
||||
struct sg_table *tui_sg_table;
|
||||
phys_addr_t fb_phys_addr;
|
||||
uint32_t npages;
|
||||
uint64_t info_length;
|
||||
} tui_ion_mem;
|
||||
|
||||
#ifdef CONFIG_TEE_TUI
|
||||
extern int ts_tui_report_input(void *finger_data);
|
||||
extern int tui_fp_notify(void);
|
||||
int __init init_tui(const struct device *dev);
|
||||
void free_tui(void);
|
||||
int tui_send_event(int event, struct teec_tui_parameter *tui_param);
|
||||
int register_tui_driver(tui_drv_init fun, const char *name,
|
||||
void *pdata);
|
||||
void unregister_tui_driver(const char *name);
|
||||
/*
|
||||
* TUI has different state that can recieve given types of message,
|
||||
* there are 3 APIs to send message.
|
||||
* send_tui_msg_config:send message to TUI in config state only.
|
||||
*/
|
||||
int send_tui_msg_config(int type, int val, void *data);
|
||||
void tui_poweroff_work_start(void);
|
||||
|
||||
void set_tui_caller_info(unsigned int devid, int pid);
|
||||
void free_tui_caller_info(void);
|
||||
|
||||
unsigned int tui_attach_device(void);
|
||||
void do_ns_tui_release(void);
|
||||
int is_tui_in_use(int pid_value);
|
||||
int tc_ns_tui_event(struct tc_ns_dev_file *dev_file, const void *argp);
|
||||
bool is_tui_agent(unsigned int agent_id);
|
||||
#else
|
||||
static inline bool is_tui_agent(unsigned int agent_id)
|
||||
{
|
||||
(void)agent_id;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int init_tui(const struct device *dev)
|
||||
{
|
||||
(void)dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void free_tui(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void unregister_tui_driver(const char *name)
|
||||
{
|
||||
(void)name;
|
||||
}
|
||||
|
||||
static inline int send_tui_msg_config(int type, int val, const void *data)
|
||||
{
|
||||
(void)type;
|
||||
(void)val;
|
||||
(void)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void set_tui_caller_info(unsigned int devid, int pid)
|
||||
{
|
||||
(void)devid;
|
||||
(void)pid;
|
||||
}
|
||||
|
||||
static inline void free_tui_caller_info(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline unsigned int tui_attach_device(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int is_tui_in_use(int pid_value)
|
||||
{
|
||||
(void)pid_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void do_ns_tui_release(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int tc_ns_tui_event(struct tc_ns_dev_file *dev_file, const void *argp)
|
||||
{
|
||||
(void)dev_file;
|
||||
(void)argp;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
KERNEL_DIR := $(srctree)
|
||||
|
||||
ifneq ($(TARGET_BUILD_VARIANT), user)
|
||||
ccflags-y += -DDEF_ENG
|
||||
endif
|
||||
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../third_party/bounds_checking_function/include
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/include
|
||||
EXTRA_CFLAGS += -include internal_functions.h
|
||||
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver
|
||||
EXTRA_CFLAGS += -I$(KERNEL_DIR)/drivers/tzdriver/core
|
||||
|
||||
obj-y += agent_allowed_ca.o
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user