move branch recv.master to master

signed-off-by: YuanHao<yuanhao34@huawei.com>
This commit is contained in:
袁浩
2022-03-01 19:39:03 +08:00
parent 08612fabef
commit 60950d3b60
106 changed files with 28993 additions and 75 deletions
+83
View File
@@ -0,0 +1,83 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
-36
View File
@@ -1,36 +0,0 @@
# tee_tee_tzdriver
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+52 -39
View File
@@ -1,39 +1,52 @@
# tee_tee_tzdriver
#### 介绍
{**以下是 Gitee 平台说明,您可以替换此简介**
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
#### 软件架构
软件架构说明
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
# Tzdriver Module Introduction<a name="ZH-CN_TOPIC_0000001078530726"></a>
- [Introduction](#section469617221261)
- [tzdriver project Structure](#section15884114210197)
- [secondary Directories structure](#section1464106163817)
## Introduction<a name="section469617221261"></a>
tzdriver is a part of REE. The REE module provides a set of rich execution environment \(REE\) API components for interacting with TEEOS, including tzdriver \(driver\), libteec \(API library\), and teecd \(agent service\). This module tzdriver normally is a part of kernel, sometimes could be ko(kernel module).
## Tzdriver project Structure<a name="section15884114210197"></a>
tee_tzdriverproject directory
- README.md&README_zh.mdIntroduction file
- LICENSEGPL v2 LICENSE
- linuxtzdriver for linux kernel
- liteostzdriver for liteos_a kernel
## Secondary Directories structure<a name="section1464106163817"></a>
**Table 1** tzdriver main secondary source code structure
<a name="table2977131081412"></a>
<table><thead align="left"><tr id="row7977610131417"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p18792459121314"><a name="p18792459121314"></a><a name="p18792459121314"></a>main secondary directory</p>
</th>
<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p77921459191317"><a name="p77921459191317"></a><a name="p77921459191317"></a>description</p>
</th>
</tr>
</thead>
<tbody><tr id="row17977171010144"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1836912441194"><a name="p1836912441194"></a><a name="p1836912441194"></a>core</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p2549609105"><a name="p2549609105"></a><a name="p2549609105"></a>core function code, include:smc, agent...</p>
</td>
</tr>
<tr id="row6978161091412"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p64006181102"><a name="p64006181102"></a><a name="p64006181102"></a>tlogger</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p7456843192018"><a name="p7456843192018"></a><a name="p7456843192018"></a>for tee log</p>
</td>
</tr>
<tr id="row6978201031415"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1978910485104"><a name="p1978910485104"></a><a name="p1978910485104"></a>auth</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1059035912204"><a name="p1059035912204"></a><a name="p1059035912204"></a>for authentication</p>
</td>
</tr>
<tr id="row1897841071415"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p182586363119"><a name="p182586363119"></a><a name="p182586363119"></a>include</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p19278126102113"><a name="p19278126102113"></a><a name="p19278126102113"></a>export header files</p>
</td>
</tr>
</tbody>
</table>
+52
View File
@@ -0,0 +1,52 @@
# Tzdriver模块介绍<a name="ZH-CN_TOPIC_0000001078530726"></a>
- [简介](#section469617221261)
- [tzdriver工程框架](#section15884114210197)
- [二级目录结构](#section1464106163817)
## 简介<a name="section469617221261"></a>
tzdriverTrustzone driver)是REE的一部分,REE组件提供了一套用于和TEEOS交互的富运行环境(REE)接口组件,包括驱动(tzdriver)、libteec(应用接口库)、teecdagent服务)。本组件tzdriver一般情况下为内核的一部分,也可以编译为ko模块。
## Tzdriver工程框架<a name="section15884114210197"></a>
tee_tzdriver:工程目录
- README.md&README_zh.md:指导文件
- LICENSE:许可证(GPL v2
- linux:为linux kernel提供的tzdriver
- liteos:为liteos_a kernel提供的tzdriver
## 二级目录结构<a name="section1464106163817"></a>
**表 1** tzdriver二级源代码主要目录结构
<a name="table2977131081412"></a>
<table><thead align="left"><tr id="row7977610131417"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p18792459121314"><a name="p18792459121314"></a><a name="p18792459121314"></a>主要二级目录</p>
</th>
<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p77921459191317"><a name="p77921459191317"></a><a name="p77921459191317"></a>描述</p>
</th>
</tr>
</thead>
<tbody><tr id="row17977171010144"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1836912441194"><a name="p1836912441194"></a><a name="p1836912441194"></a>core</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p2549609105"><a name="p2549609105"></a><a name="p2549609105"></a>核心功能代码,smcagent等都在这里面</p>
</td>
</tr>
<tr id="row6978161091412"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p64006181102"><a name="p64006181102"></a><a name="p64006181102"></a>tlogger</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p7456843192018"><a name="p7456843192018"></a><a name="p7456843192018"></a>日志组件相关代码</p>
</td>
</tr>
<tr id="row6978201031415"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1978910485104"><a name="p1978910485104"></a><a name="p1978910485104"></a>auth</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1059035912204"><a name="p1059035912204"></a><a name="p1059035912204"></a>鉴权相关代码</p>
</td>
</tr>
<tr id="row1897841071415"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p182586363119"><a name="p182586363119"></a><a name="p182586363119"></a>include</p>
</td>
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p19278126102113"><a name="p19278126102113"></a><a name="p19278126102113"></a>头文件导出</p>
</td>
</tr>
</tbody>
</table>
Executable
+34
View File
@@ -0,0 +1,34 @@
{
"name": "@openharmony/tee_tzdriver",
"version": "1.0.0",
"description": "TrustZone driver",
"private": false,
"scripts": {},
"author": {},
"repository": "",
"license": "GNU Public License v2",
"component": {
"name": "tee_tzdriver",
"subsystem": "tee",
"syscap": [],
"features": [],
"adapted_system_type": [ "small", "standard" ],
"rom": "400KB",
"ram": "400KB",
"deps": {
"components": [
"kernel",
"libmbedtls"
],
"third_party": [
"bounds_checking_function",
"mbedtls"
]
},
"build": {
"sub_component": [],
"inner_kits": [],
"test": []
}
}
}
+20
View File
@@ -0,0 +1,20 @@
menu "TEE OS"
config TZDRIVER
tristate "Secure Execution Communicator driver"
default n
help
Provides a communication interface between userspace and
TrustZone Operating Environment.
config ASAN_DEBUG
bool "ASAN debug version"
default n
help
Macro defined for ASAN debug version
source "../../../../../base/tee/tee_tzdriver/linux/auth/Kconfig"
source "../../../../../base/tee/tee_tzdriver/linux/core/Kconfig"
source "../../../../../base/tee/tee_tzdriver/linux/tlogger/Kconfig"
endmenu
+11
View File
@@ -0,0 +1,11 @@
ifeq ($(CONFIG_TZDRIVER),y)
KERNEL_DIR := $(srctree)
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../third_party/bounds_checking_function/include/
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../base/tee/tee_tzdriver/linux/include/
obj-$(CONFIG_TZDRIVER) += auth/
obj-$(CONFIG_TZDRIVER) += core/
obj-$(CONFIG_TZDRIVER) += tlogger/
endif
+8
View File
@@ -0,0 +1,8 @@
# Auth Configuration
config CLIENT_AUTH
bool "Client Application Hash Auth"
default n
depends on TZDRIVER
help
TEEOS CA code hash auth
+12
View File
@@ -0,0 +1,12 @@
KERNEL_DIR :=$(srctree)
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../third_party/bounds_checking_function/include/
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../base/tee/tee_tzdriver/linux/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../base/tee/tee_tzdriver/linux/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../base/tee/tee_tzdriver/linux/tlogger
obj-$(CONFIG_CLIENT_AUTH) += client_hash_auth.o
ifeq ($(CONFIG_CLIENT_AUTH), y)
obj-y += auth_base_impl.o
endif
+252
View File
@@ -0,0 +1,252 @@
/*
* 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
#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;
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 tee_exit_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;
#if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE)
if (!mm->mmap) {
tloge("mm sturct error! no start_code\n");
return -EFAULT;
}
unsigned long start_code = mm->mmap->vm_start;
#else
unsigned long start_code = mm->start_code;
#endif
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)
{
struct mm_struct *mm = NULL;
struct sdesc *desc = NULL;
bool check_value = false;
int rc;
check_value = (!cur_struct || !digest ||
dig_len != SHA256_DIGEST_LENGTH);
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 (prepare_desc(&desc) != EOK) {
mmput(mm);
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 */
+69
View File
@@ -0,0 +1,69 @@
/*
* 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
#ifdef CONFIG_CLIENT_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_LENGTH 32
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);
int tee_init_shash_handle(char *hash_type);
void tee_exit_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);
#else
static inline void tee_exit_shash_handle(void)
{
return;
}
static void init_crypto_hash_lock(void)
{
return;
}
#endif /* CLIENT_AUTH */
#endif
+247
View File
@@ -0,0 +1,247 @@
/*
* 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>
#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>
#include "tc_ns_log.h"
#include "auth_base_impl.h"
#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",
};
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_LENGTH) {
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)
{
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_LENGTH, 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_LENGTH, cur_struct);
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;
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;
}
cur_struct = current;
ret = proc_calc_hash(dev_file->kernel_api, session, cur_struct);
return ret;
}
+39
View File
@@ -0,0 +1,39 @@
/*
* 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)
{
return 0;
}
#endif
#endif
+49
View File
@@ -0,0 +1,49 @@
# 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 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
+17
View File
@@ -0,0 +1,17 @@
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)/../../../../../base/tee/tee_tzdriver/linux/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../base/tee/tee_tzdriver/linux/auth
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../base/tee/tee_tzdriver/linux/tlogger
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../base/tee/tee_tzdriver/linux/core
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../base/tee/tee_tzdriver/linux/kthread_affinity
obj-$(CONFIG_KERNEL_CLIENT) += 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
+1315
View File
File diff suppressed because it is too large Load Diff
+131
View File
@@ -0,0 +1,131 @@
/*
* agent.h
*
* agent manager function definition, such as register and send cmd
*
* 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_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 */
#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
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;
pid_t pid;
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);
bool is_third_party_agent(unsigned int agent_id);
void agent_init(void);
void agent_exit(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 tc_ns_sync_sys_time(const struct tc_ns_client_time *tc_ns_time);
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);
void clean_agent_pid_info(struct tc_ns_dev_file *dev_file);
#endif
+431
View File
@@ -0,0 +1,431 @@
/*
* cmd_monitor.c
*
* cmdmonitor function, monitor every cmd which is sent to TEE.
*
* 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 "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
#include "tc_ns_log.h"
#include "smc_smp.h"
#include "mailbox_mempool.h"
#include "tlogger.h"
#include "log_cfg_api.h"
#include "tz_kthread_affinity.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 250
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;
enum {
TYPE_CRASH_TA = 1,
TYPE_CRASH_TEE = 2,
};
static void get_time_spec(struct time_spec *time)
{
#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)
{
g_tee_detect_ta_crash = ((type == TYPE_CRASH_TEE) ?
TYPE_CRASH_TEE : TYPE_CRASH_TA);
tzdebug_archivelog();
}
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)
tloge("strncpy faild: errno = %d\n", sret);
put_task_struct(task);
return sret;
}
bool is_thread_reported(unsigned int 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) {
ret = (monitor->is_reported ||
monitor->agent_call_count >
MAX_AGENT_CALL_COUNT);
break;
}
}
mutex_unlock(&g_cmd_monitor_lock);
return ret;
}
void memstat_report(void)
{
int ret;
struct tee_mem *meminfo = NULL;
meminfo = mailbox_alloc(sizeof(*meminfo), MB_FLAG_ZERO);
if (!meminfo) {
tloge("mailbox alloc failed\n");
return;
}
ret = get_tee_meminfo(meminfo);
if (!ret)
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);
}
/*
* if one session timeout, monitor will print timedifs every step[n] in secends,
* 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;
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;
tlogw("[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);
tlogw("monitor: pid-%d", monitor->pid);
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;
int32_t 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 >= sizeof(g_timer_step) ?
sizeof(g_timer_step) : (monitor->timer_index + 1);
tlogw("[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--;
tlogi("[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);
}
static void cmd_monitor_tickfn(struct work_struct *work)
{
(void)(work);
cmd_monitor_tick();
/* check tlogcat if have new log */
tz_log_write();
}
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_TA) {
}
if (g_tee_detect_ta_crash == TYPE_CRASH_TEE) {
tloge("detect teeos crash, panic\n");
report_log_system_panic();
}
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 faild\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)))
newitem->pname[0] = '\0';
if (get_pid_name(newitem->tid, newitem->tname,
sizeof(newitem->tname)))
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);
}
+72
View File
@@ -0,0 +1,72 @@
/*
* cmd_monitor.h
*
* cmdmonitor function 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 CMD_MONITOR_H
#define CMD_MONITOR_H
#include "tzdebug.h"
#include "teek_ns_client.h"
#include <linux/version.h>
#if (KERNEL_VERSION(4, 14, 0) > LINUX_VERSION_CODE)
#define TASK_COMM_LEN 16
#endif
/*
* 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 do_cmd_need_archivelog(void);
bool is_thread_reported(unsigned int tid);
void tzdebug_archivelog(void);
void cmd_monitor_ta_crash(int32_t type);
void memstat_report(void);
void tzdebug_memstat(void);
#endif
+1271
View File
File diff suppressed because it is too large Load Diff
+56
View File
@@ -0,0 +1,56 @@
/*
* gp_op.h
*
* function declaration for alloc global operation and pass params to TEE.
*
* 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 GP_OPS_H
#define GP_OPS_H
#include "tc_ns_client.h"
#include "teek_ns_client.h"
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;
};
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);
bool is_ion_param(uint32_t param_type);
#endif
+625
View File
@@ -0,0 +1,625 @@
/*
* mailbox_mempool.c
*
* mailbox memory managing for sharing memory with TEE.
*
* 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 "mailbox_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 <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"
#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;
struct page *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 {
struct page *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) {
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)) {
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) {
left = 1 << (uint32_t)g_m_zone->pages[i].order;
order = g_m_zone->pages[i].order;
used += (1 << (uint32_t)g_m_zone->pages[i].order);
}
if (left) {
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 || !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))
continue;
pos = list_first_entry(head, struct mb_page_t, node);
pos->count = 1;
pos->order = order;
/* split and add free list */
for (j = order; j < i; j++) {
struct mb_page_t *new_page = NULL;
new_page = pos + (1 << j);
new_page->count = 0;
new_page->order = j;
list_add_tail(&new_page->node,
&g_m_zone->free_areas[j].page_list);
}
list_del(&pos->node);
addr = page_address(pos->page);
break;
}
mutex_unlock(&g_mb_lock);
if (addr && (flag & MB_FLAG_ZERO)) {
if (memset_s(addr, ALIGN(size, SZ_4K),
0, ALIGN(size, SZ_4K))) {
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 != 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(struct page *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;
struct page *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\n");
return;
}
page = 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) {
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)) {
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;
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);
mutex_unlock(&mb_dbg_lock);
return new_entry->idx;
}
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(struct file *filp,
const char __user *ubuf, size_t cnt, loff_t *ppos)
{
if (!filp || !ppos || !ubuf)
return false;
if (cnt >= MB_WRITE_SIZE || !cnt)
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)
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))
return -EFAULT;
buf[cnt] = 0;
value = buf;
if (!strncmp(value, "reset", strlen("reset"))) {
tlogi("mb dbg reset\n");
mb_dbg_reset();
return 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"))) {
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"))) {
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 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)(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 = kzalloc(sizeof(*operation), GFP_KERNEL);
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 = virt_to_phys(mb_pool);
operation->params[0].value.b =
(uint64_t)virt_to_phys(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 = virt_to_phys(operation);
smc_cmd->operation_h_phys =
(uint64_t)virt_to_phys(operation) >> ADDR_TRANS_NUM;
if (tc_ns_smc(smc_cmd)) {
tloge("resigter mailbox failed\n");
ret = -EIO;
}
kfree(operation);
operation = NULL;
free_smc_cmd:
kfree(smc_cmd);
smc_cmd = NULL;
return ret;
}
int mailbox_mempool_init(void)
{
int i;
struct mb_page_t *mb_page = NULL;
struct mb_free_area_t *area = NULL;
struct page *all_pages = NULL;
size_t zone_len;
g_max_oder = get_order(MAILBOX_POOL_SIZE);
tloge("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 = koadpt_alloc_pages(GFP_KERNEL, 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(page_address(all_pages), MAILBOX_POOL_SIZE)) {
tloge("register mailbox failed\n");
__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);
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);
return 0;
}
void mailbox_mempool_destroy(void)
{
__free_pages(g_m_zone->all_pages, g_max_oder);
g_m_zone->all_pages = NULL;
kfree(g_m_zone);
g_m_zone = NULL;
}
+36
View File
@@ -0,0 +1,36 @@
/*
* mailbox_mempool.h
*
* mailbox memory managing for sharing memory with TEE.
*
* 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 MAILBOX_MEMPOOOL_H
#define MAILBOX_MEMPOOOL_H
#include <linux/kernel.h>
#include <linux/types.h>
#define MAILBOX_POOL_SIZE SZ_4M
/* 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 mailbox_mempool_destroy(void);
struct mb_cmd_pack *mailbox_alloc_cmd_pack(void);
void *mailbox_copy_alloc(const void *src, size_t size);
#endif
+102
View File
@@ -0,0 +1,102 @@
/*
* mem.c
*
* memory operation for gp sharedmem.
*
* 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 "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 "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) {
vfree(shared_mem->kernel_addr);
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 = len;
sh->user_addr = NULL;
sh->user_addr_ca = NULL;
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 > RESEVED_MAX_ALLOC_SIZE || len > RESERVED_MEM_POOL_SIZE) {
tloge("allocate reserved mem size too large\n");
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);
}
addr = vmalloc_user(len);
if (!addr) {
tloge("alloc maibox failed\n");
kfree(shared_mem);
return ERR_PTR(-ENOMEM);
}
init_shared_mem(shared_mem, addr, len);
return shared_mem;
}
+44
View File
@@ -0,0 +1,44 @@
/*
* mem.h
*
* memory operation for gp sharedmem.
*
* 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 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
+440
View File
@@ -0,0 +1,440 @@
/*
* reserved_mempool.c
*
* memory managing for reserved memory with TEE.
*
* 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 "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 <linux/version.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 RESMEM_PAGE_MAX (RESERVED_MEM_POOL_SIZE >> PAGE_SHIFT)
#define STATE_MODE 0440U
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[RESMEM_PAGE_MAX];
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_virt_phy_offset;
static struct dentry *g_res_mem_dbg_dentry;
bool exist_res_mem(void)
{
return g_start_vaddr != 0;
}
unsigned long res_mem_virt_to_phys(unsigned long vaddr)
{
return vaddr - g_virt_phy_offset;
}
int load_reserved_mem(void)
{
struct device_node *np = NULL;
struct resource r;
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) {
tloge("of_address_to_resource error\n");
return -ENODEV;
}
p = ioremap(r.start, resource_size(&r));
if (p == NULL) {
tloge("io remap for reserved memory failed\n");
return -ENOMEM;
}
g_start_vaddr = (unsigned long)(uintptr_t)p;
g_virt_phy_offset = g_start_vaddr - (unsigned long)r.start;
return 0;
}
static int create_zone(void)
{
size_t zone_len;
int order = get_order(RESERVED_MEM_POOL_SIZE);
g_res_max_order = (order > CONFIG_MAX_RES_MEM_ORDER) ? CONFIG_MAX_RES_MEM_ORDER : order;
zone_len = sizeof(struct reserved_free_area_t) * (g_res_max_order + 1) + sizeof(*g_res_zone);
g_res_zone = kzalloc(zone_len, GFP_KERNEL);
if (g_res_zone == NULL) {
tloge("fail to create zone\n");
return -ENOMEM;
}
return 0;
}
static struct virt_page *create_virt_pages(void)
{
int i = 0;
struct virt_page *pages = NULL;
pages = kzalloc(RESMEM_PAGE_MAX * sizeof(struct virt_page), GFP_KERNEL);
if (pages == NULL) {
tloge("alloc pages failed\n");
return NULL;
}
for (i = 0; i < RESMEM_PAGE_MAX; i++)
pages[i].start = g_start_vaddr + i * PAGE_SIZE;
return pages;
}
void free_reserved_mempool(void)
{
if (!exist_res_mem())
return;
kfree(g_res_zone->all_pages);
g_res_zone->all_pages = NULL;
kfree(g_res_zone);
g_res_zone = 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 < RESMEM_PAGE_MAX; i++) {
if (g_res_zone->pages[i].count) {
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, RESMEM_PAGE_MAX);
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)) {
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)(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)
{
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);
}
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 -EIO;
}
operation = kzalloc(sizeof(*operation), GFP_KERNEL);
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 = 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)) {
tloge("resigter res mem failed\n");
ret = -EIO;
}
kfree(operation);
operation = NULL;
free_smc_cmd:
kfree(smc_cmd);
smc_cmd = NULL;
return ret;
}
int reserved_mempool_init()
{
struct virt_page *all_pages = NULL;
struct reserved_free_area_t *area = NULL;
struct reserved_page_t *res_page = NULL;
int ret = 0;
int i;
int max_order_cnt;
unsigned long paddr;
if (!exist_res_mem())
return 0;
ret = create_zone();
if (ret)
return ret;
all_pages = create_virt_pages();
if (all_pages == NULL) {
kfree(g_res_zone);
g_res_zone = NULL;
return -ENOMEM;
}
paddr = res_mem_virt_to_phys(g_start_vaddr);
ret = res_mem_register(paddr, RESERVED_MEM_POOL_SIZE);
if (ret) {
kfree(all_pages);
kfree(g_res_zone);
g_res_zone = NULL;
return -EIO;
}
for (i = 0; i < RESMEM_PAGE_MAX; 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 = RESMEM_PAGE_MAX / (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);
}
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))
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 (pg_idx >= RESMEM_PAGE_MAX || 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) {
tloge("already free in reseverd 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);
}
+38
View File
@@ -0,0 +1,38 @@
/*
* reserved_mempool.h
*
* reserved memory managing for sharing memory with TEE.
*
* 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 RESERVED_MEMPOOOL_H
#define RESERVED_MEMPOOOL_H
#include <linux/kernel.h>
#include <linux/types.h>
#ifndef CONFIG_MAX_RES_MEM_ORDER
#define CONFIG_MAX_RES_MEM_ORDER 15
#endif
#define RESERVED_MEM_POOL_SIZE 0x8000000 //128M
#define RESEVED_MAX_ALLOC_SIZE (1 << (CONFIG_MAX_RES_MEM_ORDER + PAGE_SHIFT)) //2^max_order * 4K
#define LIMIT_RES_MEM_ORDER 15
int load_reserved_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);
#endif
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
/*
* session_manager.h
*
* function declaration for session management
*
* 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 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,
const 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,
unsigned int file_size, struct tc_ns_client_return *tee_ret, enum secfile_type_t type);
int tc_ns_load_image_with_lock(struct tc_ns_dev_file *dev,
const char *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,
struct tc_ns_dev_file *dev_file);
int tc_ns_load_secfile(struct tc_ns_dev_file *dev_file,
const void __user *argp);
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);
#endif
+2042
View File
File diff suppressed because it is too large Load Diff
+125
View File
@@ -0,0 +1,125 @@
/*
* smc_smp.h
*
* function declaration for sending smc cmd
*
* 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_SMP_H
#define SMC_SMP_H
#include <linux/of_device.h>
#include "teek_client_constants.h"
#include "teek_ns_client.h"
#if (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE)
#define CURRENT_CPUS_ALLOWED (&current->cpus_mask)
#else
#define CURRENT_CPUS_ALLOWED (&current->cpus_allowed)
#endif
enum tc_ns_cmd_type {
TC_NS_CMD_TYPE_INVALID = 0,
TC_NS_CMD_TYPE_NS_TO_SECURE,
TC_NS_CMD_TYPE_SECURE_TO_NS,
TC_NS_CMD_TYPE_SECURE_TO_SECURE,
TC_NS_CMD_TYPE_SECURE_CONFIG = 0xf,
TC_NS_CMD_TYPE_MAX
};
struct pending_entry {
atomic_t users;
struct task_struct *task;
#ifdef CONFIG_TA_AFFINITY
struct cpumask ca_mask;
struct cpumask ta_mask;
#endif
pid_t pid;
wait_queue_head_t wq;
atomic_t run;
struct list_head list;
};
#ifdef CONFIG_BIG_SESSION
#define MAX_SMC_CMD CONFIG_BIG_SESSION
#else
#define MAX_SMC_CMD 18
#endif
#ifdef DIV_ROUND_UP
#undef DIV_ROUND_UP
#endif
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8
#ifdef BITS_TO_LONGS
#undef BITS_TO_LONGS
#endif
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(uint64_t))
#ifdef BIT_MASK
#undef BIT_MASK
#endif
#define BIT_MASK(nr) (1UL << (((uint64_t)nr) % sizeof(uint64_t)))
#ifdef BIT_WORD
#undef BIT_WORD
#endif
#define BIT_WORD(nr) ((nr) / sizeof(uint64_t))
#ifdef DECLARE_BITMAP
#undef DECLARE_BITMAP
#endif
#define DECLARE_BITMAP(name, bits) uint64_t name[BITS_TO_LONGS(bits)]
#define SIQ_DUMP_TIMEOUT 1U
#define SIQ_DUMP_SHELL 2U
typedef uint32_t smc_buf_lock_t;
struct tc_ns_smc_queue {
/* set when CA send cmd_in, clear after cmd_out return */
DECLARE_BITMAP(in_bitmap, MAX_SMC_CMD);
/* set when gtask get cmd_in, clear after cmd_out return */
DECLARE_BITMAP(doing_bitmap, MAX_SMC_CMD);
/* set when gtask get cmd_out, clear after cmd_out return */
DECLARE_BITMAP(out_bitmap, MAX_SMC_CMD);
smc_buf_lock_t smc_lock;
volatile uint32_t last_in;
struct tc_ns_smc_cmd in[MAX_SMC_CMD];
volatile uint32_t last_out;
struct tc_ns_smc_cmd out[MAX_SMC_CMD];
};
#define RESLEEP_TIMEOUT 15
bool sigkill_pending(struct task_struct *tsk);
int smc_context_init(const struct device *class_dev);
void smc_free_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);
#endif
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
/*
* tc_client_driver.h
*
* function declaration for proc open,close session and invoke
*
* 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_CLIENT_DRIVER_H
#define TC_CLIENT_DRIVER_H
#include <linux/list.h>
#include "teek_ns_client.h"
struct tc_ns_dev_list *get_dev_list(void);
uint32_t tc_ns_get_uid(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
+48
View File
@@ -0,0 +1,48 @@
/*
* tee_compat_check.c
*
* check compatibility between tzdriver and tee.
*
* 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 "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(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, major tz=%u, major tee=%u\n",
major, buffer[1]);
return -EPERM;
}
/* just print warning */
if (buffer[2] != minor)
tlogw("check minor ver failed, minor tz=%u, minor tee=%u\n",
minor, buffer[2]);
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
/*
* tee_compat_check.h
*
* check compatibility between tzdriver and teeos.
*
* 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_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 0
#define TEEOS_COMPAT_LEVEL_MINOR 1
#define VER_CHECK_MAGIC_NUM 0x5A5A5A5A
#define COMPAT_LEVEL_BUF_LEN 12
int32_t check_teeos_compat_level(uint32_t *buffer, uint32_t size);
#endif
+112
View File
@@ -0,0 +1,112 @@
/*
* teek_app_load.c
*
* function declaration for load app operations 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.
*/
#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;
mm_segment_t old_fs;
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;
}
old_fs = get_fs();
set_fs(KERNEL_DS);
read_size = (uint32_t)koadpt_vfs_read(fp, file_buffer, total_img_len, &pos);
set_fs(old_fs);
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;
}
*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 or user CA means no need to load TA */
if (!ta_path || current->mm != NULL)
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;
}
+28
View File
@@ -0,0 +1,28 @@
/*
* teek_load_api.h
*
* function declaration for load app operations 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_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
+701
View File
@@ -0,0 +1,701 @@
/*
* teek_client_api.c
*
* function definition 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.
*/
#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 "teek_client_id.h"
#include "tc_ns_log.h"
#include "tc_ns_client.h"
#include "gp_ops.h"
#include "session_manager.h"
#include "tc_client_driver.h"
#include "teek_app_load.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;
if (idex >= TEE_PARAM_NUM)
return;
if (param_type[idex] == TEEC_MEMREF_WHOLE) {
context->params[idex].memref.offset = 0;
context->params[idex].memref.size_addr =
(__u64)(uintptr_t)
(&(oper->params[idex].memref.parent->size));
} else {
context->params[idex].memref.offset =
oper->params[idex].memref.offset;
context->params[idex].memref.size_addr =
(__u64)(uintptr_t)
(&(oper->params[idex].memref.size));
}
if (oper->params[idex].memref.parent->is_allocated) {
context->params[idex].memref.buffer =
(__u64)(uintptr_t)
oper->params[idex].memref.parent->buffer;
} else {
context->params[idex].memref.buffer =
(__u64)(uintptr_t)
oper->params[idex].memref.parent->buffer +
oper->params[idex].memref.offset;
context->params[idex].memref.offset = 0;
}
/* 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;
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])) {
cli_context->params[idex].memref.buffer =
(__u64)(uintptr_t)
(operation->params[idex].tmpref.buffer);
cli_context->params[idex].memref.size_addr =
(__u64)(uintptr_t)
(&operation->params[idex].tmpref.size);
} 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])) {
cli_context->params[idex].value.a_addr =
(__u64)(uintptr_t)
(&(operation->params[idex].value.a));
cli_context->params[idex].value.b_addr =
(__u64)(uintptr_t)
(&(operation->params[idex].value.b));
} else if (is_ion_param(param_type[idex])) {
cli_context->params[idex].value.a_addr =
(__u64)(uintptr_t)
(&(operation->params[idex].ionref.ion_share_fd));
cli_context->params[idex].value.b_addr =
(__u64)(uintptr_t)
(&(operation->params[idex].ionref.ion_size));
} 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))) {
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))) {
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) {
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))
return TEEC_ERROR_BAD_PARAMETERS;
} else if (param_type == TEEC_MEMREF_PARTIAL_OUTPUT) {
if (!(memref->parent->flags & TEEC_MEM_OUTPUT))
return TEEC_ERROR_BAD_PARAMETERS;
} else if (param_type == TEEC_MEMREF_PARTIAL_INOUT) {
if (!(memref->parent->flags & TEEC_MEM_INPUT))
return TEEC_ERROR_BAD_PARAMETERS;
if (!(memref->parent->flags & TEEC_MEM_OUTPUT))
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) {
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);
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)
{
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)
{
struct tc_ns_dev_file *dev_file = NULL;
uint32_t teec_ret;
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)) {
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)) {
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) {
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;
/* connectionData current not used */
(void)(connection_data);
if (return_origin)
*return_origin = origin;
/* First, check parameters is valid or not */
if (!context || !operation || !destination ||
!session || connection_method != TEEC_LOGIN_IDENTIFY) {
tloge("invalid input params\n");
teec_ret = TEEC_ERROR_BAD_PARAMETERS;
goto set_ori;
}
cli_login.method = TEEC_LOGIN_IDENTIFY;
teec_ret = check_open_sess_params(context, operation);
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 = teek_get_app(context->ta_path, &cli_context.file_buffer,
&cli_context.file_size);
if (teec_ret != TEEC_SUCCESS)
goto set_ori;
load_app_flag = true;
teec_ret = open_session_and_switch_ret(session, context,
destination, &cli_context, &origin);
set_ori:
if (teec_ret != TEEC_SUCCESS && return_origin != NULL)
*return_origin = origin;
teek_free_app(load_app_flag, &cli_context.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;
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(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 (!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;
}
ret = tc_ns_close_session(session->context->dev, &cli_context);
if (!ret) {
session->session_id = 0;
if (memset_s((uint8_t *)(&session->service_id),
sizeof(session->service_id), 0x00, UUID_LEN))
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;
ret = tc_ns_send_cmd(session->context->dev, cli_context);
if (!ret) {
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 };
/* 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) {
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) {
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) {
goto set_ori;
}
}
teec_ret = proc_invoke_cmd(session, &cli_context, &origin);
set_ori:
if (teec_ret && 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)
{
if (!file_buffer || !file_size || !session ||
!session->context || !session->context->dev) {
tloge("params error!\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
return (uint32_t)tc_ns_load_image_with_lock(session->context->dev,
file_buffer, file_size, LOAD_TA);
}
EXPORT_SYMBOL(teek_send_secfile);
/*
* 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)
{
tloge("teek_register_shared_memory not supported\n");
return TEEC_ERROR_NOT_SUPPORTED;
}
+331
View File
@@ -0,0 +1,331 @@
/*
* tz_pm.c
*
* function for proc open,close session and invoke
*
* 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 "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"
#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 = PAGE_ALIGN(size + offset) / PAGE_SIZE;
pages = kzalloc(sizeof(struct page *) * pages_count, GFP_KERNEL);
if (pages == NULL)
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)
{
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;
}
#ifndef CONFIG_ARM
static uint64_t tc_s4_suspend_or_resume(uint32_t power_op)
{
u64 smc_id = (u64)power_op;
u64 smc_ret = 0xffff;
do {
asm volatile (
"mov x0, %[fid]\n"
"smc #0\n"
"str x0, [%[re0]]\n" :
[fid] "+r"(smc_id) :
[re0] "r"(&smc_ret) :
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13",
"x14", "x15", "x16", "x17");
} while (0);
isb();
wmb();
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;
do {
asm volatile (
"mov x0, %[fid]\n"
"mov x1, %[a1]\n"
"mov x2, %[a2]\n"
"mov x3, %[a3]\n"
"mov x4, %[a4]\n"
"smc #0\n"
"str x0, [%[re0]]\n" :
[fid] "+r"(smc_id),
[a1] "+r"(arg0),
[a2] "+r"(arg1),
[a3] "+r"(arg2),
[a4] "+r"(arg3) :
[re0] "r"(&smc_ret) :
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13",
"x14", "x15", "x16", "x17");
} while (0);
isb();
wmb();
return smc_ret;
}
#else
static uint32_t tc_s4_suspend_or_resume(uint32_t power_op)
{
u32 smc_id = power_op;
u32 smc_ret = 0xffff;
do {
asm volatile (
"mov r0, %[fid]\n"
".arch_extension sec\n"
"smc #0\n"
"str r0, [%[re0]]\n" :
[fid] "+r"(smc_id) :
[re0] "r"(&smc_ret) :
"r0");
} while (0);
isb();
wmb();
return smc_ret;
}
static uint32_t tc_s4_crypto_and_copy(uint32_t crypt_op,
uint64_t middle_mem_addr,
uintptr_t secos_mem,
uint32_t size, uint32_t index)
{
u32 smc_id = crypt_op;
u32 arg0 = (u32)middle_mem_addr;
u32 arg1 = (u32)secos_mem;
u32 arg2 = size;
u32 arg3 = index;
u32 smc_ret = 0xffff;
do {
asm volatile (
"mov r0, %[fid]\n"
"mov r1, %[a1]\n"
"mov r2, %[a2]\n"
"mov r3, %[a3]\n"
"mov r4, %[a4]\n"
".arch_extension sec\n"
"smc #0\n"
"str r0, [%[re0]]\n" :
[fid] "+r"(smc_id),
[a1] "+r"(arg0),
[a2] "+r"(arg1),
[a3] "+r"(arg2),
[a4] "+r"(arg3) :
[re0] "r"(&smc_ret) :
"r0", "r1", "r2", "r3", "r4");
} while (0);
isb();
wmb();
return smc_ret;
}
#endif
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;
if (power_op == TSP_S4_SUSPEND)
g_s4_kernel_mem_addr = kernel_mem_addr;
else
kernel_mem_addr = g_s4_kernel_mem_addr;
isb();
wmb();
/* notify TEEOS to suspend all pm driver */
if (power_op == TSP_S4_SUSPEND) {
ret = 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 = 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;
}
+31
View File
@@ -0,0 +1,31 @@
/*
* tz_pm.h
*
* suspend or freeze func declaration for tzdriver
*
* 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 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
+840
View File
@@ -0,0 +1,840 @@
/*
* tz_spi_notify.c
*
* exported funcs for spi interrupt actions
*
* 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 "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 "tz_kthread_affinity.h"
#define DEFAULT_SPI_NUM 111
#define MAX_CALLBACK_COUNT 100
#define UUID_SIZE 16
struct teec_timer_property;
#ifdef DEF_ENG
static int g_timer_type;
#endif
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;
};
struct notify_data_entry {
uint32_t entry_type : 31;
uint32_t filled : 1;
union notify_context context;
};
#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))
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);
mutex_unlock(&temp_dev_file->service_lock);
if (!temp_svc)
break;
get_service_struct(temp_svc);
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))
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)
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))
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 (i = 0; i < (uint32_t)NR_CPUS; 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 = __xchg(0, &g_notify_data->meta.context.meta.missed,
MISSED_COUNT);
if (!missed)
return;
if (missed & (1U << NOTIFY_DATA_ENTRY_WAKEUP)) {
smc_wakeup_broadcast();
missed &= ~(1U << NOTIFY_DATA_ENTRY_WAKEUP);
}
if (missed & (1U << NOTIFY_DATA_ENTRY_FIQSHD)) {
tc_notify_fiqshd_fn(NULL);
missed &= ~(1U << NOTIFY_DATA_ENTRY_FIQSHD);
}
if (missed)
tloge("missed spi notification mask %x\n", missed);
}
static void tc_notify_fn(struct work_struct *dummy)
{
struct notify_data_entry copy = {0};
while (get_notify_data_entry(&copy) == 0) {
switch (copy.entry_type) {
case NOTIFY_DATA_ENTRY_TIMER:
case NOTIFY_DATA_ENTRY_RTC:
tc_notify_timer_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_WAKEUP:
tc_notify_wakeup_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_SHADOW:
tc_notify_shadow_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_FIQSHD:
tc_notify_fiqshd_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_SHADOW_EXIT:
tc_notify_shadowexit_fn(&copy);
break;
#ifdef CONFIG_TA_AFFINITY
case NOTIFY_DATA_ENTRY_SET_AFFINITY:
tc_notify_set_affinity(&copy);
break;
#endif
default:
tloge("invalid entry type = %u\n", copy.entry_type);
}
if (memset_s(&copy, sizeof(copy), 0, sizeof(copy)))
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;
static struct work_struct tc_notify_works[N_WORK];
static int init;
if (!init) {
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]))
break;
}
#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)) {
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)) {
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;
}
#ifdef DEF_ENG
static void timer_callback_func(void *param)
{
struct teec_timer_property *timer_property =
(struct teec_timer_property *)param;
tlogd("timer property type = %x, timer property timer id = %x\n",
timer_property->type, timer_property->timer_id);
g_timer_type = (int)timer_property->type;
}
static void tst_get_timer_type(int *type)
{
*type = g_timer_type;
}
static void callback_demo_main(const char *uuid)
{
int ret;
tlogd("step into callback_demo_main\n");
ret = tc_ns_register_service_call_back_func(uuid,
timer_callback_func, NULL);
if (ret)
tloge("failed to tc_ns_register_service_call_back_func\n");
}
static int init_tst_test_context(struct tc_ns_client_context *client_context,
const void *argp, int *cmd_id)
{
struct tc_uuid secure_timer_uuid = {
0x19b39980, 0x2487, 0x7b84,
{0xf4, 0x1a, 0xbc, 0x89, 0x22, 0x62, 0xbb, 0x3d}
};
if (copy_from_user(client_context, argp, sizeof(*client_context))) {
tloge("copy from user failed\n");
return -ENOMEM;
}
if (!tc_user_param_valid(client_context, 0)) {
tloge("param 0 is invalid\n");
return -EFAULT;
}
/* a_addr contain the command id */
if (copy_from_user(cmd_id,
(void *)(uintptr_t)client_context->params[0].value.a_addr,
sizeof(*cmd_id))) {
tloge("copy from user failed:cmd_id\n");
return -ENOMEM;
}
if (memcmp((char *)client_context->uuid, (char *)&secure_timer_uuid,
sizeof(struct tc_uuid))) {
tloge("request not from secure_timer\n");
tloge("request uuid: %x %x %x %x\n",
*(client_context->uuid + 0),
*(client_context->uuid + 1),
*(client_context->uuid + 2),
*(client_context->uuid + 3));
/* just wanna print the first four characters of uuid */
return -EACCES;
}
return 0;
}
int tc_ns_tst_cmd(void *argp)
{
struct tc_ns_client_context client_context;
int ret;
int cmd_id;
int timer_type;
if (!argp) {
tloge("argp is NULL input buffer\n");
return -EINVAL;
}
ret = init_tst_test_context(&client_context, argp, &cmd_id);
if (ret)
return ret;
switch (cmd_id) {
case TST_CMD_01:
callback_demo_main((char *)client_context.uuid);
break;
case TST_CMD_02:
tst_get_timer_type(&timer_type);
if (!tc_user_param_valid(&client_context, (unsigned int)1)) {
tloge("param 1 is invalid\n");
ret = -EINVAL;
return ret;
}
if (copy_to_user(
(void *)(uintptr_t)
client_context.params[1].value.a_addr,
&timer_type, sizeof(timer_type))) {
tloge("copy to user failed:timer_type\n");
ret = -ENOMEM;
return ret;
}
break;
default:
ret = -EINVAL;
return ret;
}
if (copy_to_user(argp, &client_context, sizeof(client_context))) {
tloge("copy to user failed:client context\n");
ret = -ENOMEM;
return ret;
}
return ret;
}
#else
int tc_ns_tst_cmd(void *argp)
{
(void)argp;
tloge("usr img do not support this cmd\n");
return 0;
}
#endif
static 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 =
virt_to_phys(g_notify_data);
mb_pack->operation.params[0].value.b = (uint64_t)virt_to_phys(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 =
virt_to_phys(&mb_pack->operation);
smc_cmd.operation_h_phys = (uint64_t)virt_to_phys(&mb_pack->operation) >> ADDR_TRANS_NUM;
if (tc_ns_smc(&smc_cmd)) {
ret = -EPERM;
tloge("register notify mem failed\n");
}
mailbox_free(mb_pack);
return ret;
}
static int config_spi_context(struct device *class_dev, struct device_node *np)
{
unsigned int irq = DEFAULT_SPI_NUM;
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
irq = (unsigned int)get_acpi_tz_irq();
#else
irq = irq_of_parse_and_map(np, 0);
#endif
ret = devm_request_irq(class_dev, irq, tc_secure_notify,
IRQF_NO_SUSPEND, TC_NS_CLIENT_DEV, NULL);
if (ret < 0) {
tloge("device irq %u request failed %d", 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)
goto clean;
if (!g_notify_data) {
#ifdef CONFIG_BIG_SESSION
/* we should map at least 3 pages for 100 sessions, 2^2 > 3 */
g_notify_data = (struct notify_data_struct *)
(uintptr_t)__get_free_pages(
GFP_KERNEL | __GFP_ZERO, CONFIG_NOTIFY_PAGE_ORDER);
#else
g_notify_data = (struct notify_data_struct *)
(uintptr_t)__get_free_page(GFP_KERNEL | __GFP_ZERO);
#endif
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) {
tloge("shared memory failed ret is 0x%x\n", ret);
ret = -EFAULT;
free_page((unsigned long)(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:
tz_spi_exit();
return ret;
}
void tz_spi_exit(void)
{
if (g_notify_data) {
if (send_notify_cmd(GLOBAL_CMD_ID_UNREGISTER_NOTIFY_MEMORY))
tloge("unregister notify data mem failed\n");
#ifdef CONFIG_BIG_SESSION
free_pages((unsigned long)(uintptr_t)g_notify_data,
CONFIG_NOTIFY_PAGE_ORDER);
#else
free_page((unsigned long)(uintptr_t)g_notify_data);
#endif
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;
}
}
+27
View File
@@ -0,0 +1,27 @@
/*
* tz_spi_notify.h
*
* exported funcs for spi interrupt actions
*
* 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 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 tz_spi_exit(void);
int tc_ns_tst_cmd(void *argp);
#endif
+521
View File
@@ -0,0 +1,521 @@
/*
* tzdebug.c
*
* for tzdriver debug
*
* 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 "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"
#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 = virt_to_phys(statmem);
mb_pack->operation.params[0].memref.size = sizeof(*statmem);
mb_pack->operation.buffer_h_addr[0] =
(uint64_t)virt_to_phys(statmem) >> ADDR_TRANS_NUM;
mb_pack->operation.params[1].value.a = flag;
mb_pack->operation.params[1].value.b = history;
smc_cmd.operation_phys =
(unsigned int)virt_to_phys(&mb_pack->operation);
smc_cmd.operation_h_phys =
(uint64_t)virt_to_phys(&mb_pack->operation) >> ADDR_TRANS_NUM;
if (tc_ns_smc(&smc_cmd)) {
ret = -EPERM;
tloge("send dump mem failed\n");
}
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) {
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)
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 (!meminfo)
return -EINVAL;
if (atomic_read(&g_cmd_send)) {
if (get_tee_meminfo_cmd())
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)
return -1;
return 0;
}
EXPORT_SYMBOL(get_tee_meminfo);
static void archivelog(const char *param)
{
(void)param;
tzdebug_archivelog();
}
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))
tloge("send dump mem failed\n");
mailbox_free(mem);
}
static void tz_srv_sess_dump(const char *param)
{
struct tc_ns_smc_cmd smc_cmd = { {0}, 0 };
(void)param;
smc_cmd.cmd_id = GLOBAL_CMD_ID_DUMP_SRV_SESS;
smc_cmd.cmd_type = CMD_TYPE_GLOBAL;
if (tc_ns_smc(&smc_cmd))
tloge("send dump service session failed\n");
}
static void tzmemstat(const char *param)
{
(void)param;
tzdebug_memstat();
}
static void tzlogwrite(const char *param)
{
(void)param;
(void)tz_log_write();
}
#define OFFSET_VALUE_BIT 8U
static void get_value(const char *param, uint32_t *value, uint32_t *index)
{
uint32_t i;
uint32_t val = 0;
for (i = 0; i < OFFSET_VALUE_BIT; i++) {
if (param[i] > '9' || param[i] < '0') {
*value = val;
*index = i;
return;
}
val = (val * 10) + param[i] - '0';
}
*value = val;
*index = i;
return;
}
#define MAX_CMD_NUM 3
#define MAX_CMD_LINE 20
#define MAX_PARAM_LINE 60
#define MAX_MEM_SIZE 0x4000U
#define MAX_VALUE_LEN 8U
#define MAX_ADDRSTR_LEN 18U
struct addr_ops {
uint32_t pos[MAX_CMD_NUM];
char address[MAX_CMD_LINE];
char value[MAX_CMD_LINE];
};
static struct addr_ops g_sec_addr;
static int parse_param(const char *param, uint32_t len)
{
uint32_t i;
uint32_t j;
/*
* param format as follows:
* (r)/(w):addr(Decimal):value
* 'w' for writing a value to a given addr
* 'r' for reading a value form a giver addr
*/
j = 0;
for (i = 0; i < len; i++) {
if (param[i] == ':') {
if (j < MAX_CMD_NUM - 1)
g_sec_addr.pos[j] = i;
j++;
}
}
if (j >= MAX_CMD_NUM ) { /* Max number of ':' is 2 */
tloge("cmd invalid\n");
return -EINVAL;
}
if ((g_sec_addr.pos[1] - g_sec_addr.pos[0] - 1 >= MAX_ADDRSTR_LEN ) || (len - g_sec_addr.pos[1] >= MAX_VALUE_LEN)) {
tloge("invalid param\n");
return -EINVAL;
}
if (param[0] != 'r' && param[0] != 'w' ) {
tloge("cmd not support\n");
return -EINVAL;
}
i = 0;
for (j = g_sec_addr.pos[0] + 1; j <= g_sec_addr.pos[1] - 1; j++) /* skip ':'*/
g_sec_addr.address[i++] = param[j];
g_sec_addr.address[i] = '\0';
i = 0;
for (j = g_sec_addr.pos[1] + 1; j <= len; j++)
g_sec_addr.value[i++] = param[j];
g_sec_addr.value[i] = '\0';
return 0;
}
void tz_secmem_test(const char *param)
{
void __iomem *remap_addr = NULL;
void *addr = NULL;
uint32_t val;
unsigned long long tmp;
uint32_t len;
/* if strlen is negative, len must be larger than MAX_PARAM_LINE, so it's invalied */
len = (uint32_t)strlen(param);
if (len >= MAX_PARAM_LINE) {
tloge("param invalid\n");
return;
}
if (parse_param(param, len) != 0) {
tloge("parse params fail\n");
return;
}
tloge("the second string : %s\n", g_sec_addr.address);
if (kstrtoull(g_sec_addr.address + 2, 16, &tmp) < 0) { /* add 2 for skip '0x' */
tloge("str address to unsigned long fail\n");
return;
}
addr = (void *)(uintptr_t)tmp;
if (kstrtoull(g_sec_addr.value, 10, &tmp) < 0) {
tloge("str val to unsigned long fail\n");
return;
}
val = (uint32_t)tmp;
tloge("val = %u\n", val);
remap_addr = ioremap((phys_addr_t)(uintptr_t)addr, MAX_MEM_SIZE);
if (!remap_addr) {
tloge("remap_addr failed\n");
return;
}
tloge("remap_addr succ\n");
if (param[0] == 'w') {
tloge("read before write : %u \n", *((uint32_t *)remap_addr));
tloge("write val : %u \n", val);
*((uint32_t *)remap_addr) = val;
} else {
tloge("read addr value : %u \n", *((uint32_t *)remap_addr));
}
iounmap(remap_addr);
}
static struct opt_ops g_opt_arr[] = {
{"archivelog", archivelog},
{"dump", tzdump},
{"memdump", tzmemdump},
{"logwrite", tzlogwrite},
{"dump_service", dump_services_status},
{"memstat", tzmemstat},
{"secmem_test", tz_secmem_test},
{"srv_sess_dump", tz_srv_sess_dump},
};
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 (!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 += 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)
return -EINVAL;
if (copy_from_user(buf, ubuf, cnt))
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)) &&
strlen(p) == strlen(g_opt_arr[i].name)) {
g_opt_arr[i].func(value);
return cnt;
}
}
return -EFAULT;
}
#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;
mem_stat = kzalloc(sizeof(*mem_stat), GFP_KERNEL);
if (!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)
{
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
static const struct file_operations g_tz_dbg_opt_fops = {
.owner = THIS_MODULE,
.read = tz_dbg_opt_read,
.write = tz_dbg_opt_write,
};
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
#else
(void)g_tz_dbg_dentry;
(void)g_tz_dbg_opt_fops;
#endif
return 0;
}
void tzdebug_exit(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
}
+43
View File
@@ -0,0 +1,43 @@
/*
* tzdebug.h
*
* for tzdriver debug
*
* 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 tzdebug_exit(void);
#endif
+109
View File
@@ -0,0 +1,109 @@
/*
* 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);
long koadpt_sys_chown(const char __user *filename, uid_t user, gid_t group);
ssize_t koadpt_vfs_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos);
ssize_t koadpt_vfs_read(struct file *file, char __user *buf,
size_t count, loff_t *pos);
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);
}
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0))
static inline long koadpt_sys_chown(const char __user *filename,
uid_t user, gid_t group)
{
return sys_chown(filename, user, group);
}
#else
static inline long koadpt_sys_chown(const char __user *filename,
uid_t user, gid_t group)
{
return ksys_chown(filename, user, group);
}
#endif
static inline ssize_t koadpt_vfs_read(struct file *file, char __user *buf,
size_t count, loff_t *pos)
{
return vfs_read(file, buf, count, pos);
}
static inline ssize_t koadpt_vfs_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
return vfs_write(file, buf, count, pos);
}
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
+180
View File
@@ -0,0 +1,180 @@
/*
* 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 {
__u64 buffer;
__u64 offset;
__u64 size_addr;
} memref;
struct {
__u64 a_addr;
__u64 b_addr;
} value;
struct {
__u64 buffer;
__u64 size_addr;
} sharedmem;
};
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;
unsigned long long file_addr;
};
};
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,
};
struct load_secfile_ioctl_struct {
enum secfile_type_t secfile_type;
unsigned char uuid[UUID_LEN];
uint32_t file_size;
union {
char *file_buffer;
unsigned long long file_addr;
};
};
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;
unsigned long long addr;
};
uint32_t size;
};
#define TST_CMD_01 1
#define TST_CMD_02 2
#define TST_CMD_03 3
#define TST_CMD_04 4
#define TST_CMD_05 5
#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_TST_CMD_REQ \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 15, int)
#define TC_NS_CLIENT_IOCTL_TUI_EVENT \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 16, int)
#define TC_NS_CLIENT_IOCTL_SYC_SYS_TIME \
_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_UNMAP_SHARED_MEM \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 22, unsigned int)
#define TC_NS_CLIENT_IOCTL_UPDATE_TA_CRL\
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 23, struct tc_ns_client_crl)
#endif
+67
View File
@@ -0,0 +1,67 @@
/*
* tc_ns_log.h
*
* log func declaration
*
* Copyright (C) 2022 Huawei Technologies Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef TC_NS_LOG_H
#define TC_NS_LOG_H
#include <linux/version.h>
#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
#include <linux/sched/mm.h>
#endif
#include <linux/printk.h>
enum {
TZ_DEBUG_VERBOSE = 0,
TZ_DEBUG_DEBUG,
TZ_DEBUG_INFO,
TZ_DEBUG_WARN,
TZ_DEBUG_ERROR,
};
#define MOD_TEE "tzdriver"
#define TEE_LOG_MASK TZ_DEBUG_INFO
#define tlogv(fmt, args...) \
do { \
if (TZ_DEBUG_VERBOSE >= TEE_LOG_MASK) \
pr_info("([%s] %i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args); \
} while (0)
#define tlogd(fmt, args...) \
do { \
if (TZ_DEBUG_DEBUG >= TEE_LOG_MASK) \
pr_info("([%s] %i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args); \
} while (0)
#define tlogi(fmt, args...) \
do { \
if (TZ_DEBUG_INFO >= TEE_LOG_MASK) \
pr_info("([%s] %i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args); \
} while (0)
#define tlogw(fmt, args...) \
do { \
if (TZ_DEBUG_WARN >= TEE_LOG_MASK) \
pr_warn("([%s] %i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args); \
} while (0)
#define tloge(fmt, args...) \
pr_err("([%s] %i, %s)%s: " fmt, MOD_TEE, current->pid, current->comm, __func__, ## args)
#endif
+122
View File
@@ -0,0 +1,122 @@
/*
* 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
#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);
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);
#else
static inline int teek_is_agent_alive(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 void teek_finalize_context(struct 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 void teek_close_session(struct 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 uint32_t teek_send_secfile(struct teec_session *session,
const char *file_buffer, unsigned int file_size)
{
return TEEC_SUCCESS;
}
#endif
#endif
+178
View File
@@ -0,0 +1,178 @@
/*
* 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.
*/
#include <linux/types.h>
#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_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,
};
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,
};
#endif
+78
View File
@@ -0,0 +1,78 @@
/*
* 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_ICC_OPEN_THREAD,
SECBOOT_CMD_ID_BSP_RFILE_RW_THREAD,
SECBOOT_CMD_ID_GET_RNG_NUM,
};
#endif
+192
View File
@@ -0,0 +1,192 @@
/*
* 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;
size_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;
size_t size;
};
struct teec_registeredmemory_reference {
struct teec_sharedmemory *parent;
size_t size;
size_t offset;
};
struct teec_value {
uint32_t a;
uint32_t b;
};
struct teec_ion_reference {
int ion_share_fd;
size_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 device */
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 {
uint32_t timeLow;
uint16_t timeMid;
uint16_t timeHiAndVersion;
uint8_t clockSeqAndNode[8];
} TEEC_UUID;
typedef struct {
void *dev;
uint8_t *ta_path;
struct list_head session_list;
struct list_head shrd_mem_list;
} TEEC_Context;
typedef struct {
uint32_t session_id;
TEEC_UUID service_id;
uint32_t ops_cnt;
struct list_head head;
TEEC_Context *context;
} TEEC_Session;
typedef struct {
void *buffer;
size_t size;
uint32_t flags;
uint32_t ops_cnt;
bool is_allocated;
struct list_head head;
TEEC_Context *context;
} TEEC_SharedMemory;
typedef struct {
void *buffer;
size_t size;
} TEEC_TempMemoryReference;
typedef struct {
TEEC_SharedMemory *parent;
size_t size;
size_t offset;
} TEEC_RegisteredMemoryReference;
typedef struct {
uint32_t a;
uint32_t b;
} TEEC_Value;
typedef struct {
int ion_share_fd;
size_t ion_size;
} TEEC_IonReference;
typedef union {
TEEC_TempMemoryReference tmpref;
TEEC_RegisteredMemoryReference memref;
TEEC_Value value;
TEEC_IonReference ionref;
} TEEC_Parameter;
typedef struct {
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 device */
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 */
} TEEC_TUI_Parameter;
typedef struct {
uint32_t started;
uint32_t paramTypes;
TEEC_Parameter params[4];
TEEC_Session *session;
bool cancel_flag;
} TEEC_Operation;
#endif
+205
View File
@@ -0,0 +1,205 @@
/*
* 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 <securec.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_NS_CLIENT_DEV_NAME "/dev/tc_ns_client"
#define EXCEPTION_MEM_SIZE (8*1024) /* mem for exception handling */
#define TSP_REQUEST 0xB2000008
#define TSP_RESPONSE 0xB2000009
#define TSP_REE_SIQ 0xB200000A
#define TSP_CRASH 0xB200000B
#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 */
};
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 */
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 {
unsigned int buffer;
unsigned int size;
} sharedmem;
};
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
#else
#define KIND_OF_SO 2
#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];
};
#endif
+196
View File
@@ -0,0 +1,196 @@
/*
* 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 long (sys_chown_func)(const char __user *filename,
uid_t user, gid_t group);
typedef ssize_t (vfs_write_func)(struct file *file, const char __user *buf,
size_t count, loff_t *pos);
typedef ssize_t (vfs_read_func)(struct file *file, char __user *buf,
size_t count, loff_t *pos);
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)
{
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);
}
void koadpt_kthread_bind_mask(struct task_struct *task,
const struct cpumask *mask)
{
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);
}
long koadpt_sys_chown(const char __user *filename, uid_t user, gid_t group)
{
static sys_chown_func *sys_chown_pt = NULL;
if (!filename)
return -EINVAL;
if (!sys_chown_pt) {
sys_chown_pt = (sys_chown_func *)
(uintptr_t)kallsyms_lookup_name("sys_chown");
if (IS_ERR_OR_NULL(sys_chown_pt)) {
tloge("fail to find symbol kthread bind mask\n");
return -EINVAL;
}
}
return sys_chown_pt(filename, user, group);
}
ssize_t koadpt_vfs_write(struct file *file, const char __user *buf,
size_t count, loff_t *pos)
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 19, 116))
static vfs_write_func *vfs_write_pt = NULL;
if (!file || !buf || !pos)
return -EINVAL;
if (!vfs_write_pt) {
vfs_write_pt = (vfs_write_func *)
(uintptr_t)kallsyms_lookup_name("vfs_write");
if (IS_ERR_OR_NULL(vfs_write_pt)) {
tloge("fail to find symbol vfs write\n");
return -EINVAL;
}
}
return vfs_write_pt(file, buf, count, pos);
#else
return vfs_write(file, buf, count, pos);
#endif
}
ssize_t koadpt_vfs_read(struct file *file, char __user *buf,
size_t count, loff_t *pos)
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 19, 116))
static vfs_read_func *vfs_read_pt = NULL;
if (!file || !buf || !pos)
return -EINVAL;
if (!vfs_read_pt) {
vfs_read_pt = (vfs_read_func *)
(uintptr_t)kallsyms_lookup_name("vfs_read");
if (IS_ERR_OR_NULL(vfs_read_pt)) {
tloge("fail to find symbol vfs read\n");
return -EINVAL;
}
}
return vfs_read_pt(file, buf, count, pos);
#else
return vfs_read(file, buf, count, pos);
#endif
}
struct page *koadpt_alloc_pages(gfp_t gfp_mask, unsigned int order)
{
#ifdef CONFIG_NUMA
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);
#else
return alloc_pages(gfp_mask, order);
#endif
}
struct workqueue_attrs *koadpt_alloc_workqueue_attrs(gfp_t gfp_mask)
{
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);
}
void koadpt_free_workqueue_attrs(struct workqueue_attrs *attrs)
{
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);
}
@@ -0,0 +1,72 @@
/*
* tz_kthread_affinity.c
*
* function for set kthread affinity
*
* 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 "tz_kthread_affinity.h"
#include <linux/cpumask.h>
#include <linux/workqueue.h>
#include "tc_ns_log.h"
#include "ko_adapt.h"
#include "tz_kthread_cpumask.h"
static struct cpumask g_kthread_cpumask;
void init_kthread_cpumask(void)
{
int ret;
cpumask_clear(&g_kthread_cpumask);
ret = get_kthread_cpumask(&g_kthread_cpumask);
if (ret < 0)
tloge("get kthread cpumask failed\n");
}
void tz_kthread_bind_mask(struct task_struct *kthread)
{
if (!kthread)
return;
if (cpumask_empty(&g_kthread_cpumask))
return;
koadpt_kthread_bind_mask(kthread, &g_kthread_cpumask);
}
void tz_workqueue_bind_mask(struct workqueue_struct *wq, uint32_t flag)
{
int ret;
struct workqueue_attrs *attrs = NULL;
if (!wq)
return;
if (cpumask_empty(&g_kthread_cpumask))
return;
attrs = koadpt_alloc_workqueue_attrs(GFP_KERNEL);
if (!attrs) {
tloge("alloc workqueue attrs failed\n");
return;
}
attrs->nice = (flag & WQ_HIGHPRI) ? MIN_NICE : 0;
attrs->no_numa = true;
cpumask_copy(attrs->cpumask, &g_kthread_cpumask);
ret = apply_workqueue_attrs(wq, attrs);
if (ret)
tloge("apply workqueue attrs failed %d\n", ret);
koadpt_free_workqueue_attrs(attrs);
}
@@ -0,0 +1,46 @@
/*
* tz_kthread_affinity.h
*
* exported funcs for kthread affinity
*
* 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 TZ_KTHREAD_AFFINITY_H
#define TZ_KTHREAD_AFFINITY_H
#include <linux/sched.h>
#include <linux/workqueue.h>
#define TZ_WQ_MAX_ACTIVE 1
#ifdef CONFIG_KTHREAD_AFFINITY
void init_kthread_cpumask(void);
void tz_kthread_bind_mask(struct task_struct *kthread);
void tz_workqueue_bind_mask(struct workqueue_struct *wq, uint32_t flag);
#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
#endif
@@ -0,0 +1,24 @@
/*
* tz_kthread_cpumask.h
*
* exported funcs for get kthread cpumask
*
* 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 TZ_KTHREAD_CPUMASK_H
#define TZ_KTHREAD_CPUMASK_H
#include <linux/cpumask.h>
int get_kthread_cpumask(struct cpumask *cpumask);
#endif
@@ -0,0 +1,53 @@
/*
* tz_kthread_cpumask.c
*
* function for get kthread cpumask
*
* 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 "tz_kthread_cpumask.h"
#include <linux/of.h>
#include <linux/cpumask.h>
#include "tc_ns_log.h"
/* on mdc, kthread should be bind to ctrlcpu, which is read from dts */
int get_kthread_cpumask(struct cpumask *cpumask)
{
int ret;
uint32_t i;
uint32_t ctrl_cpu_num;
struct device_node *ctrl_cpu_node = NULL;
if (!cpumask)
return -1;
ctrl_cpu_node = of_find_node_by_name(NULL, "ascend_ctl");
if (ctrl_cpu_node == NULL) {
tloge("get ctrl cpu node failed\n");
return -1;
}
ret = of_property_read_u32_index(ctrl_cpu_node, "ctrl_cpu_num", 0, &ctrl_cpu_num);
if (ret < 0) {
tloge("get ctrl cpu num failed, err=%d\n", ret);
return ret;
}
if (ctrl_cpu_num > num_online_cpus()) {
tloge("ctrl cpu num is invalid\n");
return -1;
}
for (i = 0; i < ctrl_cpu_num; i++)
cpumask_set_cpu(i, cpumask);
return 0;
}
+25
View File
@@ -0,0 +1,25 @@
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
choice
prompt "Register tee log Mem"
default PAGES_MEM
depends on TEELOG
config PAGES_MEM
bool "Register pages log mem"
help
Register pages log mem
endchoice
+22
View File
@@ -0,0 +1,22 @@
ifeq ($(strip $(TARGET_PRODUCT)), mdc)
ccflags-y += -DCONFIG_MDC_PLATFORM
endif
ifeq ($(strip $(TARGET_PRODUCT)), mini)
ccflags-y += -DCONFIG_MINI_PLATFORM
endif
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)/../../../../../base/tee/tee_tzdriver/linux/include
EXTRA_CFLAGS += -I$(KERNEL_DIR)/../../../../../base/tee/tee_tzdriver/linux/core
obj-$(CONFIG_TEELOG) += tlogger.o
# If no log mechanism is available, the pages memory can be used.
obj-$(CONFIG_PAGES_MEM) += log_pages_cfg.o
+77
View File
@@ -0,0 +1,77 @@
/*
* log_cfg_api.h
*
* for log cfg api define
*
* 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 LOG_CFG_API_H
#define LOG_CFG_API_H
#include <linux/types.h>
#if (defined(CONFIG_PAGES_MEM) && defined(CONFIG_TEELOG))
int register_log_mem(u64 *addr, u32 *len);
int register_log_exception(void);
void report_log_system_error(void);
void report_log_system_panic(void);
int *map_log_mem(u64 mem_addr, u32 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 u64 *addr, const u32 *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(u64 mem_addr, u32 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
+143
View File
@@ -0,0 +1,143 @@
/*
* log_pages_cfg.c
*
* for pages log cfg api define
*
* 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 "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"
void unregister_log_exception(void)
{
}
int register_log_exception(void)
{
return 0;
}
struct pages_module_result {
u64 log_addr;
unsigned int log_len;
};
struct pages_module_result g_mem_info = {0};
#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
static int tee_pages_register_core(void)
{
g_mem_info.log_addr = (uintptr_t)__get_free_pages(
GFP_KERNEL | __GFP_ZERO, get_order(PAGES_LOG_MEM_LEN));
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(u64 *addr, u32 *len)
{
int ret;
u64 mem_addr;
u32 mem_len;
if (!addr || !len) {
tloge("check addr or len is failed\n");
return -1;
}
ret = tee_pages_register_core();
if (ret)
return ret;
mem_addr = virt_to_phys((void *)(uintptr_t)g_mem_info.log_addr);
mem_len = g_mem_info.log_len;
ret = register_mem_to_teeos(mem_addr, mem_len, true);
if (ret)
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(u64 mem_addr, u32 mem_len)
{
(void)mem_len;
return (int *)(uintptr_t)mem_addr;
}
void unmap_log_mem(int *log_buffer)
{
free_pages((unsigned long)(uintptr_t)log_buffer,
get_order(PAGES_LOG_MEM_LEN));
}
#define ROOT_UID 0
#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
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
+59
View File
@@ -0,0 +1,59 @@
/*
* tlogger.h
*
* TEE Logging Subsystem, read the tee os log from rdr memory
*
* 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 TLOGGER_H
#define TLOGGER_H
#include <linux/types.h>
#ifdef CONFIG_TEELOG
void tz_log_write(void);
int tlogger_store_msg(const char *file_path, u32 file_path_len);
int register_mem_to_teeos(u64 mem_addr, u32 mem_len, bool is_cache_mem);
#ifdef CONFIG_TZDRIVER_MODULE
int init_tlogger_service(void);
void exit_tlogger_service(void);
#endif
#else
static inline void tz_log_write(void)
{
return;
}
static inline int tlogger_store_msg(const char *file_path, u32 file_path_len)
{
(void)file_path;
(void)file_path_len;
return 0;
}
static inline int register_mem_to_teeos(u64 mem_addr, u32 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 exit_tlogger_service(void)
{
}
#endif
#endif
+67
View File
@@ -0,0 +1,67 @@
# 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.
import("//kernel/liteos_a/liteos.gni")
module_switch = defined(LOSCFG_DRIVERS_TZDRIVER)
module_name = "tzdriver"
kernel_module(module_name) {
open_tlogger_switch = true
defines = [
"CONFIG_TZDRIVER=y",
"CONFIG_LITEOS_TZDRIVER=y",
"CONFIG_CPU_AFF_NR=1",
"CONFIG_KERNEL_CLIENT=y",
"CONFIG_TEECD_PATH=\"/vendor/bin/teecd\"",
]
if (open_tlogger_switch) {
defines += [
"CONFIG_PAGES_MEM=y",
"CONFIG_TEELOG=y",
]
sources = [
"tlogger/log_pages_cfg.c",
"tlogger/tlogger.c",
]
} else {
sources = []
}
sources += [
"los_adapt.c",
"core/agent.c",
"core/cmdmonitor.c",
"core/gp_ops.c",
"core/mailbox_mempool.c",
"core/mem.c",
"core/teek_client_api.c",
"core/session_manager.c",
"core/smc_smp.c",
"core/tc_client_driver.c",
"core/tzdebug.c",
"core/tz_spi_notify.c",
]
include_dirs = [
".",
"auth",
"core",
"include",
"tlogger",
"//third_party/mbedtls/include",
"//third_party/musl/porting/liteos_a/kernel",
"//device/hisilicon/hispark_taurus/sdk_liteos/board/include",
]
}
config("public") {
cflags = [ "-Wno-unused-const-variable", "-Wno-unused-function" ]
include_dirs = [ "include" ]
}
+8
View File
@@ -0,0 +1,8 @@
config DRIVERS_TZDRIVER
bool "Secure Execution Communicator driver"
default n
depends on TEE_ENABLE
help
Provides a communication interface between userspace and
TrustZone Operating Environment.
+37
View File
@@ -0,0 +1,37 @@
include $(LITEOSTOPDIR)/config.mk
MODULE_NAME := tzdriver
LOCAL_FLAGS += -fstack-protector-strong -Wno-unused-const-variable -Wno-unused-function
LOCAL_FLAGS += -DCONFIG_TZDRIVER=y
LOCAL_FLAGS += -DCONFIG_LITEOS_TZDRIVER=y
LOCAL_FLAGS += -DCONFIG_CPU_AFF_NR=1
LOCAL_FLAGS += -DCONFIG_KERNEL_CLIENT=y
LOCAL_FLAGS += -DCONFIG_PAGES_MEM=y
LOCAL_FLAGS += -DCONFIG_TEELOG=y
LOCAL_FLAGS += -DCONFIG_TEECD_PATH=\"/vendor/bin/teecd\"
LOCAL_FLAGS += -I.
LOCAL_FLAGS += -Iauth
LOCAL_FLAGS += -Icore
LOCAL_FLAGS += -Iinclude
LOCAL_FLAGS += -Itlogger
LOCAL_FLAGS += -I$(LITEOSTOPDIR)/../../third_party/mbedtls/include
LOCAL_FLAGS += -I$(LITEOSTOPDIR)/../../third_party/musl/porting/liteos_a/kernel
LOCAL_FLAGS += -I$(LITEOSTOPDIR)/../../device/hisilicon/hispark_taurus/sdk_liteos/board/include
LOCAL_SRCS += los_adapt.c
LOCAL_SRCS += core/agent.c
LOCAL_SRCS += core/cmdmonitor.c
LOCAL_SRCS += core/gp_ops.c
LOCAL_SRCS += core/mailbox_mempool.c
LOCAL_SRCS += core/mem.c
LOCAL_SRCS += core/teek_client_api.c
LOCAL_SRCS += core/session_manager.c
LOCAL_SRCS += core/smc_smp.c
LOCAL_SRCS += core/tc_client_driver.c
LOCAL_SRCS += core/tzdebug.c
LOCAL_SRCS += core/tz_spi_notify.c
LOCAL_SRCS += tlogger/tlogger.c
LOCAL_SRCS += tlogger/log_pages_cfg.c
include $(MODULE)
+46
View File
@@ -0,0 +1,46 @@
/*
* 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 <securec.h>
#include "tc_ns_log.h"
#include "tc_ns_client.h"
#include "agent.h" /* for get_proc_dpath */
#include "los_adapt.h"
int calc_task_hash(unsigned char *digest, uint32_t dig_len,
LosTaskCB *cur_struct)
{
tee_sha256_context ctx;
if (!cur_struct || !digest || dig_len != SHA256_DIGEST_LENGTH) {
tloge("tee hash: input param is error\n");
return -EFAULT;
}
LosVmSpace *space = OS_PCB_FROM_PID(cur_struct->processID)->vmSpace;
if (space == NULL)
return -EFAULT;
init_tee_sha256(&ctx);
/* search the region list */
if (space->codeStart != 0 && space->codeEnd > space->codeStart)
update_tee_sha256(&ctx, (void *)space->codeStart, space->codeEnd - space->codeStart);
else
return -EFAULT;
finish_tee_sha256(&ctx, digest);
return 0;
}
+39
View File
@@ -0,0 +1,39 @@
/*
* 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
#include <linux/types.h>
#include "los_adapt.h"
#if ((defined CONFIG_CLIENT_AUTH) || (defined CONFIG_TEECD_AUTH))
#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_LENGTH 32
int calc_task_hash(unsigned char *digest, uint32_t dig_len, LosTaskCB *cur_struct);
#endif /* CLIENT_AUTH || TEECD_AUTH */
#endif
+78
View File
@@ -0,0 +1,78 @@
/*
* 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 <securec.h>
#include "tc_ns_log.h"
#include "auth_base_impl.h"
#include "los_adapt.h"
static int proc_calc_hash(uint8_t kernel_api, struct tc_ns_session *session,
LosTaskCB *cur_struct)
{
int rc, i;
int so_found = 0;
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_LENGTH, 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) {
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_LENGTH, cur_struct);
if (rc) {
tloge("tee calc ca hash failed\n");
return -EFAULT;
}
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;
LosTaskCB *cur_struct = NULL;
bool check = false;
check = (!dev_file || !context || !session);
if (check) {
tloge("bad params\n");
return -EFAULT;
}
cur_struct = OsCurrTaskGet();
ret = proc_calc_hash(dev_file->kernel_api, session, cur_struct);
return ret;
}
+39
View File
@@ -0,0 +1,39 @@
/*
* 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)
{
return 0;
}
#endif
#endif
+1189
View File
File diff suppressed because it is too large Load Diff
+129
View File
@@ -0,0 +1,129 @@
/*
* agent.h
*
* agent manager function definition, such as register and send cmd
*
* 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_H
#define AGENT_H
#include "teek_ns_client.h"
#define MAX_PATH_SIZE 512
#define AGENT_FS_ID 0x46536673 /* FSfs */
#define AGENT_MISC_ID 0x4d495343 /* MISC */
#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
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;
pid_t pid;
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);
LosTaskCB *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);
bool is_third_party_agent(unsigned int agent_id);
void agent_init(void);
int agent_exit(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 tc_ns_sync_sys_time(const struct tc_ns_client_time *tc_ns_time);
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);
void clean_agent_pid_info(struct tc_ns_dev_file *dev_file);
#endif
+380
View File
@@ -0,0 +1,380 @@
/*
* cmd_monitor.c
*
* cmdmonitor function, monitor every cmd which is sent to TEE.
*
* 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 "cmdmonitor.h"
#include "tc_ns_log.h"
#include "smc_smp.h"
#include "mailbox_mempool.h"
#include "tlogger.h"
#include "log_cfg_api.h"
#include "los_adapt.h"
static int g_cmd_need_archivelog;
static LINUX_LIST_HEAD(g_cmd_monitor_list);
static int g_cmd_monitor_list_size;
/* report 2 hours */
#define MAX_CMD_MONITOR_LIST 200
#define MAX_AGENT_CALL_COUNT 250
static mutex_t g_cmd_monitor_lock = PTHREAD_MUTEX_INITIALIZER;
/* 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;
enum {
TYPE_CRASH_TA = 1,
TYPE_CRASH_TEE = 2,
};
#ifndef CONFIG_TEE_LOG_ACHIVE_PATH
#define CONFIG_TEE_LOG_ACHIVE_PATH "/data/log/tee/last_teemsg"
#endif
static void get_time_spec(struct time_spec *time)
{
time->ts = current_kernel_time();
}
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, msecs_to_jiffies(S_TO_MS));
}
void tzdebug_archivelog(void)
{
schedule_cmd_monitor_work(&g_cmd_monitor_work_archive,
msecs_to_jiffies(0));
}
void cmd_monitor_ta_crash(int32_t type)
{
g_tee_detect_ta_crash = ((type == TYPE_CRASH_TEE) ?
TYPE_CRASH_TEE : TYPE_CRASH_TA);
tzdebug_archivelog();
}
bool is_thread_reported(unsigned int tid)
{
bool ret = false;
struct cmd_monitor *monitor = NULL;
if (mutex_lock(&g_cmd_monitor_lock) != 0) {
tloge("cmd monitor lock fail\n");
return ret;
}
list_for_each_entry(monitor, &g_cmd_monitor_list, list) {
if (monitor->tid == tid) {
ret = (monitor->is_reported ||
monitor->agent_call_count >
MAX_AGENT_CALL_COUNT);
break;
}
}
mutex_unlock(&g_cmd_monitor_lock);
return ret;
}
void memstat_report(void)
{
int ret;
struct tee_mem *meminfo = NULL;
meminfo = mailbox_alloc(sizeof(*meminfo), MB_FLAG_ZERO);
if (!meminfo) {
tloge("mailbox alloc failed\n");
return;
}
ret = get_tee_meminfo(meminfo);
if (!ret)
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 = OsCurrTaskGet()->processID;
pid_t tid = OsCurrTaskGet()->taskID;
if (mutex_lock(&g_cmd_monitor_lock) != 0) {
tloge("cmdmonitor lock fail\n");
return;
}
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);
}
static void show_timeout_cmd_info(struct cmd_monitor *monitor)
{
long long timedif;
struct time_spec nowtime;
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 25s, 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, "
"timedif=%lld ms and report\n",
monitor->pid, monitor->pname, monitor->tid,
monitor->tname, monitor->lastcmdid,
monitor->agent_call_count, timedif);
tloge("monitor: pid-%d", monitor->pid);
show_cmd_bitmap();
g_cmd_need_archivelog = 1;
wakeup_tc_siq();
return;
}
if (timedif > 1 * S_TO_MS)
tloge("[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;
if (mutex_lock(&g_cmd_monitor_lock) != 0) {
tloge("cmd_monitor lock fail\n");
return;
}
list_for_each_entry_safe(monitor, tmp, &g_cmd_monitor_list, list) {
if (monitor->returned) {
g_cmd_monitor_list_size--;
tloge("[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, msecs_to_jiffies(S_TO_MS));
mutex_unlock(&g_cmd_monitor_lock);
}
static void cmd_monitor_tickfn(struct work_struct *work)
{
(void)(work);
cmd_monitor_tick();
/* check tlogcat if have new log */
tz_log_write();
}
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();
}
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 faild\n");
return NULL;
}
get_time_spec(&newitem->sendtime);
newitem->count = 1;
newitem->agent_call_count = 0;
newitem->returned = false;
newitem->is_reported = false;
newitem->pid = OsCurrTaskGet()->processID;
newitem->tid = OsCurrTaskGet()->taskID;
LosProcessCB *run_process = OS_PCB_FROM_PID(newitem->pid);
if (strncpy_s(newitem->pname, TASK_COMM_LEN, run_process->processName, OS_PCB_NAME_LEN) != EOK)
newitem->pname[0] = '\0';
if (strncpy_s(newitem->tname, TASK_COMM_LEN, OsCurrTaskGet()->taskName, OS_TCB_NAME_LEN) != EOK)
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 = OsCurrTaskGet()->processID;
tid = OsCurrTaskGet()->taskID;
if (mutex_lock(&g_cmd_monitor_lock) != 0) {
tloge("cmd monitor lock failed\n");
return NULL;
}
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->count++;
monitor->returned = false;
monitor->is_reported = false;
monitor->lastcmdid = cmd->cmd_id;
monitor->agent_call_count = 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,
msecs_to_jiffies(S_TO_MS));
}
} 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
*/
tloge("time : item s %lld ns %lld nowtime s %lld ns %lld total %lld\n",
(long long)item->sendtime.ts.tv_sec, (long long)item->sendtime.ts.tv_nsec,
(long long)nowtime.ts.tv_sec, (long long)nowtime.ts.tv_nsec, (long long)item->timetotal);
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,
msecs_to_jiffies(S_TO_MS));
}
}
void init_cmd_monitor(void)
{
g_cmd_monitor_wq = alloc_ordered_workqueue("tz_cmd_monitor_wq", 0);
if (!g_cmd_monitor_wq)
tloge("alloc cmd monitor wq failed\n");
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);
}
+63
View File
@@ -0,0 +1,63 @@
/*
* cmd_monitor.h
*
* cmdmonitor function 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 CMD_MONITOR_H
#define CMD_MONITOR_H
#include "tzdebug.h"
#include "teek_ns_client.h"
#define TASK_COMM_LEN OS_TCB_NAME_LEN
/*
* when cmd execute more than 25s in tee,
* it will be terminated when CA is killed
*/
#define CMD_MAX_EXECUTE_TIME 25U
#define S_TO_MS 1000
#define S_TO_US 1000000
struct time_spec {
struct timespec ts;
};
struct cmd_monitor {
struct list_head list;
struct time_spec sendtime;
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 do_cmd_need_archivelog(void);
bool is_thread_reported(unsigned int tid);
void tzdebug_archivelog(void);
void cmd_monitor_ta_crash(int32_t type);
void memstat_report(void);
void tzdebug_memstat(void);
#endif
+1056
View File
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
/*
* gp_op.h
*
* function declaration for alloc global operation and pass params to TEE.
*
* 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 GP_OPS_H
#define GP_OPS_H
#include "tc_ns_client.h"
#include "teek_ns_client.h"
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;
};
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);
bool is_ion_param(uint32_t param_type);
#endif
+614
View File
@@ -0,0 +1,614 @@
/*
* mailbox_mempool.c
*
* mailbox memory managing for sharing memory with TEE.
*
* 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 "mailbox_mempool.h"
#include "teek_client_constants.h"
#include "tc_ns_log.h"
#include "smc_smp.h"
#include "los_adapt.h"
#define MAILBOX_PAGE_MAX (MAILBOX_POOL_SIZE >> PAGE_SHIFT)
#define MAILBOX_ORDER_MAX GET_ORDER(MAILBOX_POOL_SIZE)
static int g_max_oder = MAILBOX_ORDER_MAX;
#define OPT_MODE 0660U
#define STATE_MODE 0440U
struct mb_page_t {
struct list_head node;
LosVmPage *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 {
LosVmPage *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 mutex_t 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) {
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)) {
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) {
left = 1 << (uint32_t)g_m_zone->pages[i].order;
order = g_m_zone->pages[i].order;
used += (1 << (uint32_t)g_m_zone->pages[i].order);
}
if (left) {
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 || !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))
continue;
pos = list_first_entry(head, struct mb_page_t, node);
pos->count = 1;
pos->order = order;
/* split and add free list */
for (j = order; j < i; j++) {
struct mb_page_t *new_page = NULL;
new_page = pos + (1 << j);
new_page->count = 0;
new_page->order = j;
list_add_tail(&new_page->node,
&g_m_zone->free_areas[j].page_list);
}
list_del(&pos->node);
addr = (void *)OsVmPageToVaddr(pos->page);
break;
}
mutex_unlock(&g_mb_lock);
if (addr && (flag & MB_FLAG_ZERO)) {
if (memset_s(addr, ALIGN(size, SZ_4K),
0, ALIGN(size, SZ_4K))) {
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 != 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(LosVmPage *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;
LosVmPage *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\n");
return;
}
page = OsVmVaddrToPage((void *)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) {
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)) {
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 LINUX_LIST_HEAD(mb_dbg_list);
static mutex_t mb_dbg_lock = PTHREAD_MUTEX_INITIALIZER;
static unsigned int g_mb_dbg_entry_count = 1;
static unsigned int g_mb_dbg_last_res; /* only cache 1 opt result */
static unsigned int mb_dbg_add_entry(void *ptr)
{
struct mb_dbg_entry *new_entry = NULL;
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);
mutex_unlock(&mb_dbg_lock);
return new_entry->idx;
}
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(struct file *filp,
const char __user *ubuf, size_t cnt)
{
if (!filp || !ubuf)
return false;
if (cnt >= MB_WRITE_SIZE || !cnt)
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)
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)
{
char buf[MB_WRITE_SIZE] = {0};
char *cmd = NULL;
char *value = NULL;
char *end_ptr = NULL;
unsigned int alloc_size;
unsigned int free_idx;
if (!is_opt_write_param_valid(filp, ubuf, cnt))
return -EINVAL;
if (copy_from_user(buf, ubuf, cnt))
return -EFAULT;
buf[cnt] = 0;
value = buf;
if (!strncmp(value, "reset", strlen("reset"))) {
tlogi("mb dbg reset\n");
mb_dbg_reset();
return 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"))) {
alloc_size = strtoul(value, &end_ptr, 0);
if (end_ptr == NULL || *end_ptr != 0)
tloge("invalid value format for mb dbg\n");
else
alloc_dbg_entry(alloc_size);
} else if (!strncmp(cmd, "free", strlen("free"))) {
free_idx = strtoul(value, &end_ptr, 0);
if (end_ptr == NULL || *end_ptr != 0)
tloge("invalid value format for mb dbg\n");
else
mb_dbg_remove_entry(free_idx);
} else {
tloge("invalid format for mb dbg\n");
}
return cnt;
}
static ssize_t mb_dbg_opt_read(struct file *filp, char __user *ubuf,
size_t cnt)
{
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, buf, ret);
}
static const struct file_operations_vfs g_mb_dbg_opt_fops = {
.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)
{
(void)(filp);
(void)(ubuf);
mailbox_show_status();
mailbox_show_details();
return 0;
}
static const struct file_operations_vfs g_mb_dbg_state_fops = {
.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 = kzalloc(sizeof(*operation), GFP_KERNEL);
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 = virt_to_phys((void *)mb_pool);
operation->params[0].value.b = 0;
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 = virt_to_phys(operation);
smc_cmd->operation_h_phys = 0;
if (tc_ns_smc(smc_cmd)) {
tloge("resigter mailbox failed\n");
ret = -EIO;
}
kfree(operation);
operation = NULL;
free_smc_cmd:
kfree(smc_cmd);
smc_cmd = NULL;
return ret;
}
#define TC_NS_CLIENT_MEILBOX_OPT_NAME "/dev/tz_mailbox_opt"
#define TC_NS_CLIENT_MEILBOX_STATE_NAME "/dev/tz_mailbox_state"
int mailbox_mempool_init(void)
{
int i;
struct mb_page_t *mb_page = NULL;
struct mb_free_area_t *area = NULL;
LosVmPage *all_pages = NULL;
size_t zone_len;
tloge("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_pool_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((void *)page_address(all_pages), MAILBOX_POOL_SIZE)) {
tloge("register mailbox failed\n");
mailbox_pool_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);
int ret = create_tc_client_device(TC_NS_CLIENT_MEILBOX_OPT_NAME, &g_mb_dbg_opt_fops);
if (ret != EOK)
return ret;
ret = create_tc_client_device(TC_NS_CLIENT_MEILBOX_STATE_NAME, &g_mb_dbg_state_fops);
if (ret != EOK)
return ret;
return 0;
}
void mailbox_mempool_destroy(void)
{
mailbox_pool_free_pages(g_m_zone->all_pages, g_max_oder);
g_m_zone->all_pages = NULL;
kfree(g_m_zone);
g_m_zone = NULL;
}
+36
View File
@@ -0,0 +1,36 @@
/*
* mailbox_mempool.h
*
* mailbox memory managing for sharing memory with TEE.
*
* 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 MAILBOX_MEMPOOOL_H
#define MAILBOX_MEMPOOOL_H
#include <linux/kernel.h>
#include <linux/types.h>
#define MAILBOX_POOL_SIZE SZ_4M
/* 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 mailbox_mempool_destroy(void);
struct mb_cmd_pack *mailbox_alloc_cmd_pack(void);
void *mailbox_copy_alloc(const void *src, size_t size);
#endif
+74
View File
@@ -0,0 +1,74 @@
/*
* mem.c
*
* memory operation for gp sharedmem.
*
* 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 "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 "los_adapt.h"
void tc_mem_free(struct tc_ns_shared_mem *shared_mem)
{
if (!shared_mem)
return;
if (shared_mem->kernel_addr) {
LOS_VFree(shared_mem->kernel_addr);
shared_mem->kernel_addr = NULL;
}
kfree(shared_mem);
}
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);
}
len = ALIGN(len, SZ_4K);
if (len > MAILBOX_POOL_SIZE) {
tloge("alloc sharemem size %zu is too large\n", len);
kfree(shared_mem);
return ERR_PTR(-EINVAL);
}
addr = LOS_VMalloc(len);
if (!addr) {
tloge("alloc mailbox failed\n");
kfree(shared_mem);
return ERR_PTR(-ENOMEM);
}
if (memset_s(addr, len, 0, len)) {
tloge("memset mailbox failed\n");
kfree(shared_mem);
LOS_VFree(addr);
return ERR_PTR(-ENOMEM);
}
shared_mem->kernel_addr = addr;
shared_mem->len = len;
shared_mem->user_addr = NULL;
shared_mem->user_addr_ca = NULL;
atomic_set(&shared_mem->usage, 0);
return shared_mem;
}
+44
View File
@@ -0,0 +1,44 @@
/*
* mem.h
*
* memory operation for gp sharedmem.
*
* 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 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
File diff suppressed because it is too large Load Diff
+52
View File
@@ -0,0 +1,52 @@
/*
* session_manager.h
*
* function declaration for session management
*
* 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 SESSION_MANAGER_H
#define SESSION_MANAGER_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,
const 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,
unsigned int file_size, unsigned int *ret_origin, enum secfile_type_t type);
int tc_ns_load_image_with_lock(struct tc_ns_dev_file *dev,
const char *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,
struct tc_ns_dev_file *dev_file);
int tc_ns_load_secfile(struct tc_ns_dev_file *dev_file,
const void __user *argp);
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);
#endif
File diff suppressed because it is too large Load Diff
+142
View File
@@ -0,0 +1,142 @@
/*
* smc_smp.h
*
* function declaration for sending smc cmd
*
* 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_SMP_H
#define SMC_SMP_H
#include "teek_client_constants.h"
#include "teek_ns_client.h"
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)]
static inline void set_bit(int nr, volatile unsigned long *addr)
{
if (addr == NULL)
return;
const unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p |= mask;
}
static inline void clear_bit(int nr, volatile unsigned long *addr)
{
if (addr == NULL)
return;
const unsigned long mask = BIT_MASK(nr);
unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
*p &= ~mask;
}
static inline int test_bit(int nr, const volatile unsigned long *addr)
{
if (addr == NULL)
return 0;
return 1UL & (addr[BIT_WORD(nr)] >> ((unsigned int)nr & (BITS_PER_BYTE * sizeof(uint64_t) - 1)));
}
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 RESLEEP_TIMEOUT 15
bool sigkill_pending(LosTaskCB *tsk);
int smc_context_init(void);
void smc_free_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);
void SetCmdSendState(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(void);
struct tc_ns_smc_queue *get_cmd_data_buffer(void);
#endif
+967
View File
@@ -0,0 +1,967 @@
/*
* tc_client_driver.c
*
* function for proc open,close session and invoke
*
* 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 "tc_client_driver.h"
#include <securec.h>
#include "smc_smp.h"
#include "teek_client_constants.h"
#include "agent.h"
#include "mem.h"
#include "gp_ops.h"
#include "tc_ns_log.h"
#include "tc_ns_client.h"
#include "mailbox_mempool.h"
#include "tz_spi_notify.h"
#include "auth_base_impl.h"
#include "client_hash_auth.h"
#include "auth_base_impl.h"
#include "tlogger.h"
#include "tzdebug.h"
#include "session_manager.h"
#include "los_adapt.h"
struct workqueue_struct *g_tzdriver_wq = NULL;
#ifdef CONFIG_ACPI
static int g_acpi_irq;
#endif
static unsigned int g_device_file_cnt = 1;
static mutex_t g_device_file_cnt_lock = PTHREAD_MUTEX_INITIALIZER;
/* dev node list and itself has mutex to avoid race */
struct tc_ns_dev_list g_tc_ns_dev_list;
static LosTaskCB *g_teecd_task;
void set_teecd_task(LosTaskCB* task)
{
g_teecd_task = task;
}
LosTaskCB *get_teecd_task(void)
{
return g_teecd_task;
}
struct tc_ns_dev_list *get_dev_list(void)
{
return &g_tc_ns_dev_list;
}
static int tc_ns_get_tee_version(const struct tc_ns_dev_file *dev_file,
void __user *argp)
{
unsigned int version;
struct tc_ns_smc_cmd smc_cmd = { {0}, 0 };
int ret = 0;
struct mb_cmd_pack *mb_pack = NULL;
if (!argp) {
tloge("error input parameter\n");
return -EINVAL;
}
mb_pack = mailbox_alloc_cmd_pack();
if (!mb_pack) {
tloge("alloc mb pack failed\n");
return -ENOMEM;
}
mb_pack->operation.paramtypes = TEEC_VALUE_OUTPUT;
smc_cmd.cmd_type = CMD_TYPE_GLOBAL;
smc_cmd.cmd_id = GLOBAL_CMD_ID_GET_TEE_VERSION;
smc_cmd.dev_file_id = dev_file->dev_file_id;
smc_cmd.operation_phys = virt_to_phys(&mb_pack->operation);
smc_cmd.operation_h_phys = 0;
if (tc_ns_smc(&smc_cmd)) {
ret = -EPERM;
tloge("smc call returns error ret 0x%x\n", smc_cmd.ret_val);
}
version = mb_pack->operation.params[0].value.a;
if (copy_to_user(argp, &version, sizeof(unsigned int)))
ret = -EFAULT;
mailbox_free(mb_pack);
return ret;
}
/*
* This is the login information
* and is set teecd when client opens a new session
*/
#define MAX_BUF_LEN 4096
static int get_pack_name_len(struct tc_ns_dev_file *dev_file,
const uint8_t *cert_buffer)
{
if (memcpy_s(&dev_file->pkg_name_len, sizeof(dev_file->pkg_name_len),
cert_buffer, sizeof(dev_file->pkg_name_len)))
return -EFAULT;
if (!dev_file->pkg_name_len ||
dev_file->pkg_name_len >= MAX_PACKAGE_NAME_LEN) {
tloge("invalid pack name len: %u\n", dev_file->pkg_name_len);
return -EINVAL;
}
tlogd("package name len is %u\n", dev_file->pkg_name_len);
return 0;
}
static int get_public_key_len(struct tc_ns_dev_file *dev_file,
const uint8_t *cert_buffer)
{
if (memcpy_s(&dev_file->pub_key_len, sizeof(dev_file->pub_key_len),
cert_buffer, sizeof(dev_file->pub_key_len)))
return -EFAULT;
if (dev_file->pub_key_len > MAX_PUBKEY_LEN) {
tloge("invalid public key len: %u\n", dev_file->pub_key_len);
return -EINVAL;
}
tlogd("publick key len is %u\n", dev_file->pub_key_len);
return 0;
}
static int get_public_key(struct tc_ns_dev_file *dev_file,
const uint8_t *cert_buffer)
{
/* get public key */
if (!dev_file->pub_key_len)
return 0;
if (memcpy_s(dev_file->pub_key, MAX_PUBKEY_LEN, cert_buffer,
dev_file->pub_key_len)) {
tloge("failed to copy pub key len\n");
return -EINVAL;
}
return 0;
}
static bool is_cert_buffer_size_valid(int cert_buffer_size)
{
/*
* GET PACKAGE NAME AND APP CERTIFICATE:
* The proc_info format is as follows:
* package_name_len(4 bytes) || package_name ||
* apk_cert_len(4 bytes) || apk_cert.
* or package_name_len(4 bytes) || package_name
* || exe_uid_len(4 bytes) || exe_uid.
* The apk certificate format is as follows:
* modulus_size(4bytes) ||modulus buffer
* || exponent size || exponent buffer
*/
if (cert_buffer_size > MAX_BUF_LEN || !cert_buffer_size) {
tloge("cert buffer size is invalid!\n");
return false;
}
return true;
}
static int alloc_login_buf(struct tc_ns_dev_file *dev_file,
uint8_t **cert_buffer, unsigned int *cert_buffer_size)
{
*cert_buffer_size = (unsigned int)(MAX_PACKAGE_NAME_LEN +
MAX_PUBKEY_LEN + sizeof(dev_file->pkg_name_len) +
sizeof(dev_file->pub_key_len));
*cert_buffer = kmalloc(*cert_buffer_size, GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)(*cert_buffer))) {
tloge("failed to allocate login buffer!");
return -ENOMEM;
}
return 0;
}
static int client_login_prepare(uint8_t *cert_buffer,
const void __user *buffer, unsigned int cert_buffer_size)
{
if (!is_cert_buffer_size_valid(cert_buffer_size))
return -EINVAL;
if (copy_from_user(cert_buffer, buffer, cert_buffer_size)) {
tloge("Failed to get user login info!\n");
return -EINVAL;
}
return 0;
}
static int tc_ns_client_login_func_without_cert(struct tc_ns_dev_file *dev_file)
{
int ret;
uint8_t *cert_buffer = NULL;
uint8_t *temp_cert_buffer = NULL;
unsigned int cert_buffer_size = 0;
char *path = NULL;
errno_t sret;
if (!dev_file)
return -EINVAL;
mutex_lock(&dev_file->login_setup_lock);
if (dev_file->login_setup) {
tloge("login information cannot be set twice!\n");
mutex_unlock(&dev_file->login_setup_lock);
return -EINVAL;
}
ret = alloc_login_buf(dev_file, &cert_buffer,
&cert_buffer_size);
if (ret != 0) {
tloge("alloc fail\n");
goto error;
}
temp_cert_buffer = cert_buffer;
path = get_process_path(OsCurrTaskGet(), (char *)cert_buffer, MAX_PACKAGE_NAME_LEN);
if (path == NULL) {
tloge("get path fail\n");
ret = -EFAULT;
goto error;
}
dev_file->pkg_name_len = strlen(path);
sret = strncpy_s((char *)dev_file->pkg_name, MAX_PACKAGE_NAME_LEN, (char *)cert_buffer, dev_file->pkg_name_len);
if (sret != EOK) {
tloge("str cpy fail\n");
ret = -ENOMEM;
goto error;
}
int uid = get_task_uid(OsCurrTaskGet());
dev_file->pub_key_len = sizeof(uid);
if (memcpy_s((char *)dev_file->pub_key, MAX_PUBKEY_LEN, (char *)&uid, dev_file->pub_key_len)) {
tloge("failed to copy cert, pubkeylen = %u\n", dev_file->pub_key_len);
ret = -EINVAL;
goto error;
}
dev_file->login_setup = true;
error:
kfree(temp_cert_buffer);
mutex_unlock(&dev_file->login_setup_lock);
return ret;
}
static int tc_ns_client_login_func_with_cert(struct tc_ns_dev_file *dev_file,
const void __user *buffer)
{
int ret;
uint8_t *cert_buffer = NULL;
uint8_t *temp_cert_buffer = NULL;
unsigned int cert_buffer_size = 0;
if (!dev_file)
return -EINVAL;
if (!buffer) {
/*
* We accept no debug information
* because the daemon might have failed
*/
dev_file->pkg_name_len = 0;
dev_file->pub_key_len = 0;
return 0;
}
mutex_lock(&dev_file->login_setup_lock);
if (dev_file->login_setup) {
tloge("login information cannot be set twice!\n");
mutex_unlock(&dev_file->login_setup_lock);
return -EINVAL;
}
ret = alloc_login_buf(dev_file, &cert_buffer, &cert_buffer_size);
if (ret) {
mutex_unlock(&dev_file->login_setup_lock);
return ret;
}
temp_cert_buffer = cert_buffer;
if (client_login_prepare(cert_buffer, buffer, cert_buffer_size)) {
ret = -EINVAL;
goto error;
}
ret = get_pack_name_len(dev_file, cert_buffer);
if (ret)
goto error;
cert_buffer += sizeof(dev_file->pkg_name_len);
if (strncpy_s((char *)dev_file->pkg_name, MAX_PACKAGE_NAME_LEN, (char *)cert_buffer,
dev_file->pkg_name_len)) {
ret = -ENOMEM;
goto error;
}
cert_buffer += dev_file->pkg_name_len;
ret = get_public_key_len(dev_file, cert_buffer);
if (ret)
goto error;
cert_buffer += sizeof(dev_file->pub_key_len);
ret = get_public_key(dev_file, cert_buffer);
dev_file->login_setup = true;
error:
kfree(temp_cert_buffer);
mutex_unlock(&dev_file->login_setup_lock);
return ret;
}
static int tc_ns_client_login_func(struct tc_ns_dev_file *dev_file,
const void __user *buffer)
{
if (buffer == NULL)
return tc_ns_client_login_func_without_cert(dev_file);
else
return tc_ns_client_login_func_with_cert(dev_file, buffer);
}
int tc_ns_client_open(struct tc_ns_dev_file **dev_file, uint8_t kernel_api)
{
struct tc_ns_dev_file *dev = NULL;
tlogd("tc_client_open\n");
if (!dev_file) {
tloge("dev_file is NULL\n");
return -EINVAL;
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)dev)) {
tloge("dev malloc failed\n");
return -ENOMEM;
}
mutex_lock(&g_tc_ns_dev_list.dev_lock);
list_add_tail(&dev->head, &g_tc_ns_dev_list.dev_file_list);
mutex_unlock(&g_tc_ns_dev_list.dev_lock);
mutex_lock(&g_device_file_cnt_lock);
dev->dev_file_id = g_device_file_cnt;
g_device_file_cnt++;
mutex_unlock(&g_device_file_cnt_lock);
INIT_LIST_HEAD(&dev->shared_mem_list);
dev->login_setup = 0;
dev->kernel_api = kernel_api;
dev->load_app_flag = 0;
mutex_init(&dev->service_lock);
mutex_init(&dev->shared_mem_lock);
mutex_init(&dev->login_setup_lock);
*dev_file = dev;
return 0;
}
static void del_dev_node(struct tc_ns_dev_file *dev)
{
if (!dev)
return;
mutex_lock(&g_tc_ns_dev_list.dev_lock);
list_del(&dev->head);
mutex_unlock(&g_tc_ns_dev_list.dev_lock);
}
void free_dev(struct tc_ns_dev_file *dev)
{
del_dev_node(dev);
tee_agent_clear_dev_owner(dev);
if (memset_s(dev, sizeof(*dev), 0, sizeof(*dev)))
tloge("Caution, memset dev fail!\n");
kfree(dev);
}
int tc_ns_client_close(struct tc_ns_dev_file *dev)
{
if (!dev) {
tloge("invalid dev(null)\n");
return -EINVAL;
}
close_unclosed_session_in_kthread(dev);
/* for thirdparty agent, code runs here only when agent crashed */
send_crashed_event_response_all(dev);
free_dev(dev);
return 0;
}
static void release_vma_shared_mem(struct tc_ns_dev_file *dev_file,
const LosVmMapRegion *vma)
{
struct tc_ns_shared_mem *shared_mem = NULL;
struct tc_ns_shared_mem *shared_mem_temp = NULL;
bool find = false;
mutex_lock(&dev_file->shared_mem_lock);
list_for_each_entry_safe(shared_mem, shared_mem_temp,
&dev_file->shared_mem_list, head) {
if (shared_mem) {
if (shared_mem->user_addr ==
(void *)(uintptr_t)vma->range.base) {
shared_mem->user_addr = NULL;
find = true;
} else if (shared_mem->user_addr_ca ==
(void *)(uintptr_t)vma->range.base) {
shared_mem->user_addr_ca = NULL;
find = true;
}
if (!shared_mem->user_addr &&
!shared_mem->user_addr_ca)
list_del(&shared_mem->head);
/* pair with tc client mmap */
if (find) {
put_sharemem_struct(shared_mem);
break;
}
}
}
mutex_unlock(&dev_file->shared_mem_lock);
}
static int shared_vma_close(struct tc_ns_dev_file *dev_file, const unsigned int argp)
{
bool check_value = false;
if (dev_file == NULL) {
tloge("unmap input error\n");
return -EINVAL;
}
LosVmMapRegion *vma = LOS_RegionFind(OsCurrProcessGet()->vmSpace, (vaddr_t)argp);
if (!vma) {
tloge("vma is null\n");
return -EINVAL;
}
check_value = (is_teecd_process(g_teecd_task, OsCurrTaskGet())) &&
(!tc_ns_get_uid());
if (check_value) {
check_value = (g_teecd_task->taskStatus & OS_TASK_STATUS_EXIT) ||
(OsCurrTaskGet()->taskStatus & OS_TASK_STATUS_EXIT);
if (check_value) {
tlogd("teecd is killed, just return in vma close\n");
return -EINVAL;
}
}
release_vma_shared_mem(dev_file, vma);
return 0;
}
static struct tc_ns_shared_mem *find_sharedmem(
const LosVmMapRegion *vma,
const struct tc_ns_dev_file *dev_file, bool *only_remap)
{
struct tc_ns_shared_mem *shm_tmp = NULL;
unsigned long len = vma->range.size;
/*
* using vma->vm_pgoff as share_mem index
* check if aready allocated
*/
list_for_each_entry(shm_tmp, &dev_file->shared_mem_list, head) {
if (atomic_read(&shm_tmp->offset) == vma->pgOff) {
tlogd("sharemem already alloc, shm tmp->offset=%d\n",
atomic_read(&shm_tmp->offset));
/*
* args check:
* 1. this shared mem is already mapped
* 2. remap a different size shared_mem
*/
if (shm_tmp->user_addr_ca ||
vma->range.size != shm_tmp->len) {
tloge("already remap once!\n");
return NULL;
}
/* return the same sharedmem specified by vm_pgoff */
*only_remap = true;
get_sharemem_struct(shm_tmp);
return shm_tmp;
}
}
/* if not find, alloc a new sharemem */
return tc_mem_allocate(len);
}
static int remap_shared_mem(LosVmMapRegion *vma,
const struct tc_ns_shared_mem *shared_mem)
{
int ret;
ret = remap_vmalloc_range(vma, shared_mem->kernel_addr, 0);
if (ret)
tloge("can't remap to user, ret = %d\n", ret);
return ret;
}
/*
* in this func, we need to deal with follow cases:
* vendor CA alloc sharedmem (alloc and remap);
* HIDL alloc sharedmem (alloc and remap);
* system CA alloc sharedmem (only just remap);
*/
static int tc_client_mmap(struct file *filp, LosVmMapRegion *vma)
{
int ret;
struct tc_ns_dev_file *dev_file = NULL;
struct tc_ns_shared_mem *shared_mem = NULL;
bool only_remap = false;
if (!filp || !vma || !filp->f_priv) {
tloge("invalid args for tc mmap\n");
return -EINVAL;
}
dev_file = filp->f_priv;
mutex_lock(&dev_file->shared_mem_lock);
shared_mem = find_sharedmem(vma, dev_file, &only_remap);
if (IS_ERR_OR_NULL(shared_mem)) {
tloge("alloc shared mem failed\n");
mutex_unlock(&dev_file->shared_mem_lock);
return -ENOMEM;
}
ret = remap_shared_mem(vma, shared_mem);
if (ret) {
if (only_remap)
put_sharemem_struct(shared_mem);
else
tc_mem_free(shared_mem);
mutex_unlock(&dev_file->shared_mem_lock);
return ret;
}
if (only_remap) {
shared_mem->user_addr_ca = (void *)vma->range.base;
mutex_unlock(&dev_file->shared_mem_lock);
return ret;
}
shared_mem->user_addr = (void *)vma->range.base;
atomic_set(&shared_mem->offset, vma->pgOff);
get_sharemem_struct(shared_mem);
list_add_tail(&shared_mem->head, &dev_file->shared_mem_list);
mutex_unlock(&dev_file->shared_mem_lock);
return ret;
}
static int ioctl_register_agent(struct tc_ns_dev_file *dev_file, unsigned long arg)
{
int ret;
struct agent_ioctl_args args;
if (!arg) {
tloge("arg is NULL\n");
return -EFAULT;
}
if (copy_from_user(&args, (void *)(uintptr_t)arg, sizeof(args))) {
tloge("copy agent args failed\n");
return -EFAULT;
}
ret = tc_ns_register_agent(dev_file, args.id, args.buffer_size,
&args.buffer, true);
if (!ret) {
if (copy_to_user((void *)(uintptr_t)arg, &args, sizeof(args)))
tloge("copy agent user addr failed\n");
}
return ret;
}
static int ioctl_unregister_agent(const struct tc_ns_dev_file *dev_file,
unsigned long arg)
{
int ret;
struct smc_event_data *event_data = NULL;
event_data = find_event_control((unsigned int)arg);
if (!event_data) {
tloge("invalid agent id\n");
return -EINVAL;
}
if (event_data->owner != dev_file) {
tloge("invalid unregister request\n");
put_agent_event(event_data);
return -EINVAL;
}
put_agent_event(event_data);
ret = tc_ns_unregister_agent((unsigned int)arg);
return ret;
}
/* ioctls for the secure storage daemon */
static long tc_agent_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = -EINVAL;
struct tc_ns_dev_file *dev_file = file->f_priv;
if (!dev_file) {
tloge("invalid params\n");
return -EINVAL;
}
switch (cmd) {
case TC_NS_CLIENT_IOCTL_WAIT_EVENT:
ret = tc_ns_wait_event((unsigned int)arg);
break;
case TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE:
ret = tc_ns_send_event_response((unsigned int)arg);
break;
case TC_NS_CLIENT_IOCTL_REGISTER_AGENT:
ret = ioctl_register_agent(dev_file, arg);
break;
case TC_NS_CLIENT_IOCTL_UNREGISTER_AGENT:
ret = ioctl_unregister_agent(dev_file, arg);
break;
case TC_NS_CLIENT_IOCTL_SYC_SYS_TIME:
ret = tc_ns_sync_sys_time(
(struct tc_ns_client_time *)(uintptr_t)arg);
break;
case TC_NS_CLIENT_IOCTL_SET_NATIVE_IDENTITY:
ret = tc_ns_set_native_hash(arg, GLOBAL_CMD_ID_SET_CA_HASH);
break;
case TC_NS_CLIENT_IOCTL_LATEINIT:
ret = tc_ns_late_init(arg);
break;
default:
tloge("invalid cmd! 0x%x\n", cmd);
break;
}
return ret;
}
static int tc_ns_send_cancel_cmd(struct tc_ns_dev_file *dev_file,
void *argp, struct tc_ns_client_context *client_context)
{
if (!argp) {
tloge("argp is NULL input buffer\n");
return -EINVAL;
}
if (copy_from_user(client_context, argp, sizeof(*client_context))) {
tloge("copy from user failed\n");
return -ENOMEM;
}
client_context->returns.code = TEEC_ERROR_GENERIC;
client_context->returns.origin = TEEC_ORIGIN_COMMS;
tloge("not support send cancle cmd now\n");
if (copy_to_user(argp, client_context, sizeof(*client_context)))
return -EFAULT;
return 0;
}
uint32_t tc_ns_get_uid(void)
{
return get_task_uid(OsCurrTaskGet());
}
static int tc_client_ioctl(struct file *file, int cmd,
unsigned long arg)
{
int ret = -EFAULT;
void *argp = (void __user *)(uintptr_t)arg;
struct tc_ns_dev_file *dev_file = file->f_priv;
struct tc_ns_client_context client_context = {{0}};
switch (cmd) {
case TC_NS_CLIENT_IOCTL_SES_OPEN_REQ:
case TC_NS_CLIENT_IOCTL_SES_CLOSE_REQ:
case TC_NS_CLIENT_IOCTL_SEND_CMD_REQ:
ret = tc_client_session_ioctl(file, cmd, arg);
break;
case TC_NS_CLIENT_IOCTL_LOAD_APP_REQ:
ret = tc_ns_load_secfile(dev_file, argp);
break;
case TC_NS_CLIENT_IOCTL_CANCEL_CMD_REQ:
ret = tc_ns_send_cancel_cmd(dev_file, argp, &client_context);
break;
case TC_NS_CLIENT_IOCTL_LOGIN:
ret = tc_ns_client_login_func(dev_file, argp);
break;
case TC_NS_CLIENT_IOCTL_WAIT_EVENT:
case TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE:
case TC_NS_CLIENT_IOCTL_REGISTER_AGENT:
case TC_NS_CLIENT_IOCTL_UNREGISTER_AGENT:
case TC_NS_CLIENT_IOCTL_SYC_SYS_TIME:
case TC_NS_CLIENT_IOCTL_SET_NATIVE_IDENTITY:
case TC_NS_CLIENT_IOCTL_LATEINIT:
ret = tc_agent_ioctl(file, cmd, arg);
break;
case TC_NS_CLIENT_IOCTL_TST_CMD_REQ:
ret = tc_ns_tst_cmd(argp);
break;
case TC_NS_CLIENT_IOCTL_GET_TEE_VERSION:
ret = tc_ns_get_tee_version(dev_file, argp);
break;
case TC_NS_CLIENT_IOCTL_UNMAP_SHARED_MEM:
ret = shared_vma_close(file->f_priv, (unsigned int)(uintptr_t)argp);
break;
default:
tloge("invalid cmd 0x%x! arg 0x%lx\n", cmd, arg);
break;
}
return ret;
}
static int tc_client_open(struct file *file)
{
int ret;
struct tc_ns_dev_file *dev = NULL;
check_teecd_process();
file->f_priv = NULL;
ret = tc_ns_client_open(&dev, TEE_REQ_FROM_USER_MODE);
if (!ret)
file->f_priv = dev;
return ret;
}
static int teec_daemon_close(struct tc_ns_dev_file *dev)
{
if (!dev) {
tloge("invalid dev(null)\n");
return -EINVAL;
}
del_dev_node(dev);
kfree(dev);
return 0;
}
static int tc_client_close(struct file *file)
{
int ret = 0;
struct tc_ns_dev_file *dev = file->f_priv;
bool check_value = false;
clean_agent_pid_info(dev);
check_value = (is_teecd_process(g_teecd_task, OsCurrTaskGet())) &&
(!tc_ns_get_uid());
if (check_value) {
/* for teecd close fd */
check_value = (g_teecd_task->taskStatus & OS_TASK_STATUS_EXIT) ||
(OsCurrTaskGet()->taskStatus & OS_TASK_STATUS_EXIT);
if (check_value) {
tloge("teecd exit\n");
if (is_system_agent(dev)) {
/* for teecd agent close fd */
send_event_response_single(dev);
free_dev(dev);
} else {
/* for ca damon close fd */
ret = teec_daemon_close(dev);
}
} else {
/*
* for ca damon close fd when ca damon close fd
* later than HIDL thread
*/
ret = tc_ns_client_close(dev);
}
} else {
/* for CA(HIDL thread) close fd */
ret = tc_ns_client_close(dev);
}
file->f_priv = NULL;
return ret;
}
struct tc_ns_dev_file *tc_find_dev_file(unsigned int dev_file_id)
{
struct tc_ns_dev_file *dev_file = NULL;
mutex_lock(&g_tc_ns_dev_list.dev_lock);
list_for_each_entry(dev_file, &g_tc_ns_dev_list.dev_file_list, head) {
if (dev_file->dev_file_id == dev_file_id) {
mutex_unlock(&g_tc_ns_dev_list.dev_lock);
return dev_file;
}
}
mutex_unlock(&g_tc_ns_dev_list.dev_lock);
return NULL;
}
#ifdef CONFIG_COMPAT
long tc_compat_client_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
long ret;
if (!file)
return -EINVAL;
arg = (unsigned long)(uintptr_t)compat_ptr(arg);
ret = tc_client_ioctl(file, cmd, arg);
return ret;
}
#endif
static const struct file_operations_vfs g_tc_ns_client_fops = {
.open = tc_client_open,
.close = tc_client_close,
.ioctl = tc_client_ioctl,
.mmap = tc_client_mmap,
};
bool schedule_work_on(int cpu, struct work_struct *work)
{
return queue_work(g_tzdriver_wq, work);
}
static int tc_ns_client_init(void)
{
int ret;
tlogd("tc_ns_client_init");
ret = create_tc_client_device(TC_NS_CLIENT_DEV_NAME, &g_tc_ns_client_fops);
if (ret != EOK) {
tloge("create tee device error.\n");
return ret;
}
ret = memset_s(&g_tc_ns_dev_list, sizeof(g_tc_ns_dev_list), 0,
sizeof(g_tc_ns_dev_list));
if (ret != EOK)
goto destroy_dev;
INIT_LIST_HEAD(&g_tc_ns_dev_list.dev_file_list);
mutex_init(&g_tc_ns_dev_list.dev_lock);
init_srvc_list();
g_tzdriver_wq = create_workqueue("g_tzalloc_ordered_workqueuedriver_wq");
if (g_tzdriver_wq == NULL) {
tloge("create tzdriver workqueue failed\n");
ret = -EFAULT;
goto destroy_dev;
}
return ret;
destroy_dev:
(void)unregister_driver(TC_NS_CLIENT_DEV_NAME);
return ret;
}
static int tc_teeos_init(void)
{
int ret;
ret = smc_context_init();
if (ret)
return ret;
ret = mailbox_mempool_init();
if (ret) {
tloge("tz mailbox init failed\n");
goto smc_data_free;
}
ret = tz_spi_init();
if (ret)
goto release_mailbox;
return 0;
release_mailbox:
mailbox_mempool_destroy();
smc_data_free:
smc_free_data();
return ret;
}
static void tc_re_init(void)
{
int ret;
agent_init();
if (tzdebug_init())
tloge("tzdebug init failed\n");
ret = init_tlogger_service();
if (ret)
tloge("tlogger init failed\n");
#ifndef CONFIG_MINI_PLATFORM
if (init_smc_svc_thread()) {
tloge("init svc thread\n");
ret = -EFAULT;
}
#endif
if (ret)
tloge("Caution! Running environment init failed!\n");
}
__init int tc_init(void)
{
int ret = 0;
ret = tc_ns_client_init();
if (ret)
return ret;
ret = tc_teeos_init();
if (ret)
goto class_device_destroy;
/* run-time environment init failure don't block tzdriver init proc */
tc_re_init();
return 0;
class_device_destroy:
(void)unregister_driver(TC_NS_CLIENT_DEV_NAME);
if (g_tzdriver_wq != NULL)
destroy_workqueue(g_tzdriver_wq);
return ret;
}
#ifndef CONFIG_LITEOS_TZDRIVER
static void tc_exit(void)
{
tlogd("tz client exit");
tz_spi_exit();
/* run-time environment exit should before teeos exit */
smc_free_data();
agent_exit();
#ifdef CONFIG_TZDRIVER_MODULE
tzdebug_exit();
exit_tlogger_service();
#endif
mailbox_mempool_destroy();
tee_exit_shash_handle();
}
#endif
+34
View File
@@ -0,0 +1,34 @@
/*
* tc_client_driver.h
*
* function declaration for proc open,close session and invoke
*
* 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_CLIENT_DRIVER_H
#define TC_CLIENT_DRIVER_H
#include <linux/list.h>
#include "teek_ns_client.h"
struct tc_ns_dev_list *get_dev_list(void);
uint32_t tc_ns_get_uid(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
+668
View File
@@ -0,0 +1,668 @@
/*
* teek_client_api.c
*
* function definition 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.
*/
#include "teek_client_api.h"
#include <securec.h>
#include "teek_client_id.h"
#include "tc_ns_log.h"
#include "tc_ns_client.h"
#include "gp_ops.h"
#include "session_manager.h"
#include "tc_client_driver.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;
if (idex >= TEE_PARAM_NUM)
return;
if (param_type[idex] == TEEC_MEMREF_WHOLE) {
context->params[idex].memref.offset = 0;
context->params[idex].memref.size_addr =
(uint64_t)(uintptr_t)
(&(oper->params[idex].memref.parent->size));
} else {
context->params[idex].memref.offset =
oper->params[idex].memref.offset;
context->params[idex].memref.size_addr =
(uint64_t)(uintptr_t)
(&(oper->params[idex].memref.size));
}
if (oper->params[idex].memref.parent->is_allocated) {
context->params[idex].memref.buffer =
(uint64_t)(uintptr_t)
oper->params[idex].memref.parent->buffer;
} else {
context->params[idex].memref.buffer =
(uint64_t)(uintptr_t)
oper->params[idex].memref.parent->buffer +
oper->params[idex].memref.offset;
context->params[idex].memref.offset = 0;
}
/* 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;
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])) {
cli_context->params[idex].memref.buffer =
(uint64_t)(uintptr_t)
(operation->params[idex].tmpref.buffer);
cli_context->params[idex].memref.size_addr =
(uint64_t)(uintptr_t)
(&operation->params[idex].tmpref.size);
} 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])) {
cli_context->params[idex].value.a_addr =
(uint64_t)(uintptr_t)
(&(operation->params[idex].value.a));
cli_context->params[idex].value.b_addr =
(uint64_t)(uintptr_t)
(&(operation->params[idex].value.b));
} else if (is_ion_param(param_type[idex])) {
cli_context->params[idex].value.a_addr =
(uint64_t)(uintptr_t)
(&(operation->params[idex].ionref.ion_share_fd));
cli_context->params[idex].value.b_addr =
(uint64_t)(uintptr_t)
(&(operation->params[idex].ionref.ion_size));
} 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)
{
if (memset_s(cli_context, sizeof(*cli_context),
0x00, sizeof(*cli_context))) {
tloge("memset error, init cli context failed\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
if (memcpy_s(cli_context->uuid, sizeof(cli_context->uuid),
(uint8_t *)&service_id, sizeof(service_id))) {
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->returns.origin = 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) {
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))
return TEEC_ERROR_BAD_PARAMETERS;
} else if (param_type == TEEC_MEMREF_PARTIAL_OUTPUT) {
if (!(memref->parent->flags & TEEC_MEM_OUTPUT))
return TEEC_ERROR_BAD_PARAMETERS;
} else if (param_type == TEEC_MEMREF_PARTIAL_INOUT) {
if (!(memref->parent->flags & TEEC_MEM_INPUT))
return TEEC_ERROR_BAD_PARAMETERS;
if (!(memref->parent->flags & TEEC_MEM_OUTPUT))
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) {
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);
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;
}
/*
* This function finalizes an initialized TEE Context.
*/
void teek_finalize_context(struct teec_context *context)
{
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;
}
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)
{
struct tc_ns_dev_file *dev_file = NULL;
uint32_t teec_ret;
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)) {
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)) {
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) {
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};
/* connectionData current not used */
(void)(connection_data);
if (return_origin)
*return_origin = origin;
/* First, check parameters is valid or not */
if (!context || !operation || !destination ||
!session || connection_method != TEEC_LOGIN_IDENTIFY) {
tloge("invalid input params\n");
teec_ret = TEEC_ERROR_BAD_PARAMETERS;
goto set_ori;
}
cli_login.method = TEEC_LOGIN_IDENTIFY;
teec_ret = check_open_sess_params(context, operation);
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 = open_session_and_switch_ret(session, context,
destination, &cli_context, &origin);
set_ori:
if (teec_ret != TEEC_SUCCESS && return_origin != NULL)
*return_origin = origin;
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;
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;
}
/*
* This function closes an opened Session.
*/
static bool is_close_sess_param_valid(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 (!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;
}
ret = tc_ns_close_session(session->context->dev, &cli_context);
if (!ret) {
session->session_id = 0;
if (memset_s((uint8_t *)(&session->service_id),
sizeof(session->service_id), 0x00, UUID_LEN))
tloge("memset error\n");
session->ops_cnt = 0;
session->context = NULL;
} else {
tloge("close session failed\n");
}
}
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;
ret = tc_ns_send_cmd(session->context->dev, cli_context);
if (!ret) {
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 };
/* 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) {
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) {
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) {
goto set_ori;
}
}
teec_ret = proc_invoke_cmd(session, &cli_context, &origin);
set_ori:
if (teec_ret && return_origin)
*return_origin = origin;
return teec_ret;
}
uint32_t teek_send_secfile(struct teec_session *session,
const char *file_buffer, unsigned int file_size)
{
if (!file_buffer || !file_size || !session ||
!session->context || !session->context->dev) {
tloge("params error!\n");
return TEEC_ERROR_BAD_PARAMETERS;
}
return (uint32_t)tc_ns_load_image_with_lock(session->context->dev,
file_buffer, file_size, LOAD_TA);
}
/*
* 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)
{
tloge("teek_register_shared_memory not supported\n");
return TEEC_ERROR_NOT_SUPPORTED;
}
+31
View File
@@ -0,0 +1,31 @@
/*
* tz_pm.h
*
* suspend or freeze func declaration for tzdriver
*
* 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 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
+805
View File
@@ -0,0 +1,805 @@
/*
* tz_spi_notify.c
*
* exported funcs for spi interrupt actions
*
* 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 "tz_spi_notify.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"
#define MAX_CALLBACK_COUNT 100
#define UUID_SIZE 16
struct teec_timer_property;
#ifdef DEF_ENG
static int g_timer_type;
#endif
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;
};
struct notify_data_entry {
uint32_t entry_type : 31;
uint32_t filled : 1;
union notify_context context;
};
#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;
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];
mutex_t callback_lock;
void (*callback_func)(void *);
struct list_head head;
};
struct tc_ns_callback_list {
unsigned int callback_count;
mutex_t 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))
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);
mutex_unlock(&temp_dev_file->service_lock);
if (!temp_svc)
break;
get_service_struct(temp_svc);
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))
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;
}
/* 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 = NULL;
e = &g_notify_data->entry[i];
filled = e->filled;
DMB;
if (!filled)
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;
}
DMB;
e->filled = 0;
ret = 0;
break;
}
exit:
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))
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 (i = 0; i < (uint32_t)NR_CPUS; 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);
tlogi("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
static void spi_broadcast_notifications(void)
{
uint32_t missed;
DMB;
if (!g_notify_data) {
tloge("notify data is NULL\n");
return;
}
missed = LOS_AtomicXchg32bits((Atomic *)&g_notify_data->meta.context.meta.missed, 0);
if (!missed)
return;
if (missed & (1U << NOTIFY_DATA_ENTRY_WAKEUP)) {
smc_wakeup_broadcast();
missed &= ~(1U << NOTIFY_DATA_ENTRY_WAKEUP);
}
if (missed & (1U << NOTIFY_DATA_ENTRY_FIQSHD)) {
tc_notify_fiqshd_fn(NULL);
missed &= ~(1U << NOTIFY_DATA_ENTRY_FIQSHD);
}
if (missed)
tloge("missed spi notification mask %x\n", missed);
}
static int g_spi_inited = 0;
static void tc_notify_fn(struct work_struct *dummy)
{
struct notify_data_entry copy = {0};
if (!g_spi_inited)
return;
while (get_notify_data_entry(&copy) == 0) {
switch (copy.entry_type) {
case NOTIFY_DATA_ENTRY_TIMER:
case NOTIFY_DATA_ENTRY_RTC:
tc_notify_timer_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_WAKEUP:
tc_notify_wakeup_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_SHADOW:
tc_notify_shadow_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_FIQSHD:
tc_notify_fiqshd_fn(&copy);
break;
case NOTIFY_DATA_ENTRY_SHADOW_EXIT:
tc_notify_shadowexit_fn(&copy);
break;
#ifdef CONFIG_TA_AFFINITY
case NOTIFY_DATA_ENTRY_SET_AFFINITY:
tc_notify_set_affinity(&copy);
break;
#endif
default:
tloge("invalid entry type = %u\n", copy.entry_type);
}
if (memset_s(&copy, sizeof(copy), 0, sizeof(copy)))
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;
static struct work_struct tc_notify_works[N_WORK];
static int init;
if (!init) {
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]))
break;
}
#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)) {
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)) {
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;
}
#ifdef DEF_ENG
static void timer_callback_func(void *param)
{
struct teec_timer_property *timer_property =
(struct teec_timer_property *)param;
tlogd("timer property type = %x, timer property timer id = %x\n",
timer_property->type, timer_property->timer_id);
g_timer_type = (int)timer_property->type;
}
static void tst_get_timer_type(int *type)
{
*type = g_timer_type;
}
static void callback_demo_main(const char *uuid)
{
int ret;
tlogd("step into callback_demo_main\n");
ret = tc_ns_register_service_call_back_func(uuid,
timer_callback_func, NULL);
if (ret)
tloge("failed to tc_ns_register_service_call_back_func\n");
}
static int init_tst_test_context(struct tc_ns_client_context *client_context,
const void *argp, int *cmd_id)
{
struct tc_uuid secure_timer_uuid = {
0x19b39980, 0x2487, 0x7b84,
{0xf4, 0x1a, 0xbc, 0x89, 0x22, 0x62, 0xbb, 0x3d}
};
if (copy_from_user(client_context, argp, sizeof(*client_context))) {
tloge("copy from user failed\n");
return -ENOMEM;
}
if (!tc_user_param_valid(client_context, 0)) {
tloge("param 0 is invalid\n");
return -EFAULT;
}
/* a_addr contain the command id */
if (copy_from_user(cmd_id,
(void *)(uintptr_t)client_context->params[0].value.a_addr,
sizeof(*cmd_id))) {
tloge("copy from user failed:cmd_id\n");
return -ENOMEM;
}
if (memcmp((char *)client_context->uuid, (char *)&secure_timer_uuid,
sizeof(struct tc_uuid))) {
tloge("request not from secure_timer\n");
tloge("request uuid: %x %x %x %x\n",
*(client_context->uuid + 0),
*(client_context->uuid + 1),
*(client_context->uuid + 2),
*(client_context->uuid + 3));
/* just wanna print the first four characters of uuid */
return -EACCES;
}
return 0;
}
int tc_ns_tst_cmd(void *argp)
{
struct tc_ns_client_context client_context;
int ret;
int cmd_id;
int timer_type;
if (!argp) {
tloge("argp is NULL input buffer\n");
return -EINVAL;
}
ret = init_tst_test_context(&client_context, argp, &cmd_id);
if (ret)
return ret;
switch (cmd_id) {
case TST_CMD_01:
callback_demo_main((char *)client_context.uuid);
break;
case TST_CMD_02:
tst_get_timer_type(&timer_type);
if (!tc_user_param_valid(&client_context, (unsigned int)1)) {
tloge("param 1 is invalid\n");
ret = -EINVAL;
return ret;
}
if (copy_to_user(
(void *)(uintptr_t)
client_context.params[1].value.a_addr,
&timer_type, sizeof(timer_type))) {
tloge("copy to user failed:timer_type\n");
ret = -ENOMEM;
return ret;
}
break;
default:
ret = -EINVAL;
return ret;
}
if (copy_to_user(argp, &client_context, sizeof(client_context))) {
tloge("copy to user failed:client context\n");
ret = -ENOMEM;
return ret;
}
return ret;
}
#else
int tc_ns_tst_cmd(void *argp)
{
(void)argp;
tloge("usr img do not support this cmd\n");
return 0;
}
#endif
static 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 =
virt_to_phys(g_notify_data);
mb_pack->operation.params[0].value.b = 0;
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 =
virt_to_phys(&mb_pack->operation);
smc_cmd.operation_h_phys = 0;
if (tc_ns_smc(&smc_cmd)) {
ret = -EPERM;
tloge("register notify mem failed\n");
}
mailbox_free(mb_pack);
return ret;
}
static int config_spi_context(void)
{
unsigned int irq;
int ret;
/* Map IRQ 0 from the OF interrupts list */
irq = NUM_HAL_INTERRUPT_TEE_SPI_NOTIFY;
ret = devm_request_irq(irq, tc_secure_notify,
IRQF_NO_SUSPEND, TC_NS_CLIENT_DEV, NULL);
if (ret < 0) {
tloge("device irq %u request failed %u", 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()
{
int ret;
g_tz_spi_wq = alloc_ordered_workqueue("g_tz_spi_wq", WQ_HIGHPRI);
if (!g_tz_spi_wq) {
tloge("it failed to create workqueue g_tz_spi_wq\n");
return -ENOMEM;
}
ret = config_spi_context();
if (ret)
goto clean;
if (!g_notify_data) {
#ifdef CONFIG_BIG_SESSION
/* we should map at least 3 pages for 100 sessions, 2^2 > 3 */
g_notify_data = (struct notify_data_struct *)
(uintptr_t)__get_free_pages(
GFP_KERNEL | __GFP_ZERO, CONFIG_NOTIFY_PAGE_ORDER);
#else
g_notify_data = (struct notify_data_struct *)
(uintptr_t)__get_free_page(GFP_KERNEL | __GFP_ZERO);
#endif
if (!g_notify_data) {
tloge("get free page failed for notification data\n");
ret = -ENOMEM;
goto clean;
}
(void)memset_s(g_notify_data, sizeof(*g_notify_data), 0, sizeof(struct notify_data_struct));
ret = send_notify_cmd(GLOBAL_CMD_ID_REGISTER_NOTIFY_MEMORY);
if (ret) {
tloge("shared memory failed ret is 0x%x\n", ret);
ret = -EFAULT;
free_page(g_notify_data);
g_notify_data = NULL;
goto clean;
}
g_notify_data_entry_shadow =
&g_notify_data->entry[NOTIFY_DATA_ENTRY_SHADOW - 1];
tlogi("target is: %llx\n",
g_notify_data_entry_shadow->context.shadow.target_tcb);
}
g_spi_inited = 1;
return 0;
clean:
tz_spi_exit();
return ret;
}
void tz_spi_exit(void)
{
g_spi_inited = 0;
if (g_notify_data) {
if (send_notify_cmd(GLOBAL_CMD_ID_UNREGISTER_NOTIFY_MEMORY))
tloge("unregister notify data mem failed\n");
#ifdef CONFIG_BIG_SESSION
free_pages(g_notify_data,
CONFIG_NOTIFY_PAGE_ORDER);
#else
free_page(g_notify_data);
#endif
g_notify_data = NULL;
}
if (g_tz_spi_wq) {
destroy_workqueue(g_tz_spi_wq);
g_tz_spi_wq = NULL;
}
}
+25
View File
@@ -0,0 +1,25 @@
/*
* tz_spi_notify.h
*
* exported funcs for spi interrupt actions
*
* 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 TZ_SPI_NOTIFY_H
#define TZ_SPI_NOTIFY_H
#include "teek_ns_client.h"
int tz_spi_init(void);
void tz_spi_exit(void);
int tc_ns_tst_cmd(void *argp);
#endif
+315
View File
@@ -0,0 +1,315 @@
/*
* tzdebug.c
*
* for tzdriver debug
*
* 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 "tzdebug.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 "session_manager.h"
#include "cmdmonitor.h"
#define DEBUG_OPT_LEN 128
#ifdef CONFIG_TA_MEM_INUSE_ONLY
#define TA_MEMSTAT_ALL 0
#else
#define TA_MEMSTAT_ALL 1
#endif
typedef void (*tzdebug_opt_func)(const char *param);
struct opt_ops {
char *name;
tzdebug_opt_func func;
};
static mutex_t g_meminfo_lock = PTHREAD_MUTEX_INITIALIZER;
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 = virt_to_phys((void *)statmem);
mb_pack->operation.params[0].memref.size = sizeof(*statmem);
mb_pack->operation.buffer_h_addr[0] = 0;
mb_pack->operation.params[1].value.a = flag;
mb_pack->operation.params[1].value.b = history;
smc_cmd.operation_phys =
(unsigned int)virt_to_phys((void *)&mb_pack->operation);
smc_cmd.operation_h_phys = 0;
if (tc_ns_smc(&smc_cmd)) {
ret = -EPERM;
tloge("send dump mem failed\n");
}
mailbox_free(mb_pack);
return ret;
}
/* 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) {
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)
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 (!meminfo)
return -EINVAL;
if (atomic_read(&g_cmd_send)) {
if (get_tee_meminfo_cmd())
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)
return -1;
return 0;
}
static void archivelog(const char *param)
{
(void)param;
tzdebug_archivelog();
}
static void tzdump(const char *param)
{
(void)param;
show_cmd_bitmap();
wakeup_tc_siq();
}
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))
tloge("send dump mem failed\n");
mailbox_free(mem);
}
static void tzmemstat(const char *param)
{
(void)param;
tzdebug_memstat();
}
static void tzlogwrite(const char *param)
{
(void)param;
}
#define OFFSET_VALUE_BIT 8U
static void get_value(const char *param, uint32_t *value, uint32_t *index)
{
uint32_t i;
uint32_t val = 0;
for (i = 0; i < OFFSET_VALUE_BIT; i++) {
if (param[i] > '9' || param[i] < '0') {
*value = val;
*index = i;
return;
}
val = (val * 10) + param[i] - '0';
}
*value = val;
*index = i;
return;
}
#define MAX_CMD_NUM 3
#define MAX_CMD_LINE 20
#define MAX_PARAM_LINE 60
#define MAX_MEM_SIZE 0x4000U
#define MAX_VALUE_LEN 8
#define MAX_ADDRSTR_LEN 18
static struct opt_ops g_opt_arr[] = {
{"archivelog", archivelog},
{"dump", tzdump},
{"memdump", tzmemdump},
{"logwrite", tzlogwrite},
{"dump_service", dump_services_status},
{"memstat", tzmemstat},
};
static ssize_t tz_dbg_opt_write(struct file *filp,
const char __user *ubuf, size_t cnt)
{
char buf[128] = {0};
char *value = NULL;
char *p = NULL;
uint32_t i = 0;
if (!ubuf || !filp)
return -EINVAL;
if (cnt >= sizeof(buf))
return -EINVAL;
if (!cnt)
return -EINVAL;
if (copy_from_user(buf, ubuf, cnt))
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)) &&
strlen(p) == strlen(g_opt_arr[i].name)) {
g_opt_arr[i].func(value);
return cnt;
}
}
return -EFAULT;
}
#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;
mem_stat = kzalloc(sizeof(*mem_stat), GFP_KERNEL);
if (!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)
{
return single_open(file, memstat_debug_show, NULL);
}
static const struct file_operations g_tz_dbg_memstat_fops = {
.open = tz_memstat_open,
};
#endif
static const struct file_operations_vfs g_tz_dbg_opt_fops = {
.write = tz_dbg_opt_write,
};
#define TC_NS_CLIENT_TZDEBUG "/dev/tzdebug"
int tzdebug_init(void)
{
int ret = create_tc_client_device(TC_NS_CLIENT_TZDEBUG, &g_tz_dbg_opt_fops);
if (ret != EOK)
return ret;
return 0;
}
void tzdebug_exit(void)
{
}
+43
View File
@@ -0,0 +1,43 @@
/*
* tzdebug.h
*
* for tzdriver debug
*
* 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 tzdebug_exit(void);
#endif
+363
View File
@@ -0,0 +1,363 @@
/*
* los_adapt.h
*
* macros and interfaces for liteos tzdriver
*
* 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 LOS_ADAPT_H
#define LOS_ADAPT_H
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
#include "arm.h"
#include "fs/fs.h"
#include "fs_poll_pri.h"
#include "hisoc/random.h"
#include "los_process_pri.h"
#include "los_task.h"
#include "los_vm_lock.h"
#include "los_vm_map.h"
#include "los_vm_phys.h"
#include "mbedtls/sha256.h"
#define TEECD_UID 97
#define VERIFY_READ 0
#define VERIFY_WRITE 1
#define MAX_DEV_NAME_SIZE 32
#define SHA256_DIGEST_LENGTH 32
#define ALIGN_TZ(x, boundary) (((x) + ((boundary) - 1)) & ~((boundary) - 1))
#define MISC_DYNAMIC_MINOR 255
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
#define LIBTEEC_SO "/vendor/lib/libteec_vendor.so"
struct miscdevice_adapt {
int minor;
char *name;
const struct file_operations_vfs *op;
};
int misc_register_adapt(struct miscdevice_adapt *misc_device);
typedef pthread_mutex_t mutex_t;
#define MAX_PATH_SIZE 512
#ifndef IS_ERR_OR_NULL
#ifndef IS_ERR_VALUE
#define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long) - 4095)
#endif
#define IS_ERR_OR_NULL(x) ((!x) || IS_ERR_VALUE((uintptr_t)x))
#endif
#define TEE_DEV_PRI 0660
#define TASK_COMM_LEN OS_TCB_NAME_LEN
#define WQ_HIGHPRI (1 << 4)
#define IRQF_NO_SUSPEND 0x00004000
#define __GFP_ZERO 0x8000u
#define SZ_4K 0x1000UL
#define SZ_1M (1024 * 1024)
#define SZ_4M (4 * SZ_1M)
#define SZ_8M (8 * SZ_1M)
#define MAX_POW_TWO(n) \
( \
((n) >> 31) ? 31 : ((n) >> 30) ? 30 : \
((n) >> 29) ? 29 : ((n) >> 28) ? 28 : \
((n) >> 27) ? 27 : ((n) >> 26) ? 26 : \
((n) >> 25) ? 25 : ((n) >> 25) ? 25 : \
((n) >> 23) ? 23 : ((n) >> 22) ? 22 : \
((n) >> 21) ? 21 : ((n) >> 20) ? 20 : \
((n) >> 19) ? 19 : ((n) >> 18) ? 18 : \
((n) >> 17) ? 17 : ((n) >> 16) ? 16 : \
((n) >> 15) ? 15 : ((n) >> 14) ? 14 : \
((n) >> 13) ? 13 : ((n) >> 12) ? 12 : \
((n) >> 11) ? 11 : ((n) >> 10) ? 10 : \
((n) >> 9) ? 9: ((n) >> 8) ? 8 : \
((n) >> 7) ? 7: ((n) >> 6) ? 6 : \
((n) >> 5) ? 5: ((n) >> 4) ? 4 : \
((n) >> 3) ? 3: ((n) >> 2) ? 2 : 1)
#define GET_ORDER(n) \
( \
n <= PAGE_SIZE ? 0 : (MAX_POW_TWO(n - 1) - PAGE_SHIFT + 1) \
)
#ifndef MSEC_PER_SEC
#define MSEC_PER_SEC 1000
#endif
#ifndef NSEC_PER_MSEC
#define NSEC_PER_MSEC 1000000L
#endif
#ifndef USEC_PER_SEC
#define USEC_PER_SEC 1000000L
#endif
#ifndef NSEC_PER_USEC
#define NSEC_PER_USEC 1000
#endif
#define CRASH_RET_EXIT 0
#define CRASH_RET_TA 1
#define CRASH_RET_IP 2
#define INIT_WORK_ONSTACK(_work, _func) \
do { \
INIT_WORK(_work, _func); \
} while (0)
#define __WORK_INIT(n, f) { \
.data = 0, \
.entry = { &(n).entry, &(n).entry }, \
.func = f \
}
#define DECLARE_WORK(work, func) \
struct work_struct work = __WORK_INIT(work, func);
#define noinline __attribute__((noinline))
struct aes_param {
unsigned char *iv;
const unsigned char *key;
int size;
unsigned int encrypto_type;
};
bool schedule_work_on(int cpu, struct work_struct *work);
LosTaskCB *kthread_run(int (*threadfn)(uintptr_t data, int data_len), void *data, int len, char *name);
void kthread_stop(const LosTaskCB *k);
int kthread_should_stop(void);
int32_t do_vmalloc_remap(LosVmMapRegion *vma, void *kvaddr);
int remap_vmalloc_range(LosVmMapRegion *vma, void *addr, unsigned long pgoff);
int create_tc_client_device(const char *dev_name, const struct file_operations_vfs *op);
ssize_t simple_read_from_buffer(void *to, size_t count, const void *from, size_t available);
LosVmPage *mailbox_pool_alloc_pages(unsigned int order);
void mailbox_pool_free_pages(LosVmPage *page_array, size_t order);
char *get_process_path(LosTaskCB *task, char *tpath, int path_len);
int calc_task_so_hash(unsigned char *digest, uint32_t dig_len, LosTaskCB *cur_struct, int so_index);
LosTaskCB *get_teecd_task(void);
void set_teecd_task(LosTaskCB* task);
int crypto_aescbckey256(unsigned char *output, const unsigned char *input, struct aes_param *param);
void check_teecd_process(void);
#define INT_SIZE 4
static inline struct workqueue_struct *alloc_ordered_workqueue(const char *fmt, unsigned int flags)
{
return create_workqueue((char *)fmt);
}
static inline int access_ok(int type, unsigned long ptr, unsigned int size)
{
if (ptr + size < ptr)
return false;
return LOS_IsUserAddress(ptr + size);
}
static inline int get_task_uid(LosTaskCB *task)
{
#ifdef LOSCFG_SECURITY_CAPABILITY
int int_save = LOS_IntLock();
int uid = -1;
LosProcessCB *process = OS_PCB_FROM_PID(task->processID);
if (process->user)
uid = process->user->userID;
LOS_IntRestore(int_save);
return uid;
#else
return 0;
#endif
}
static inline int devm_request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irq_flags, const char *devname, void *dev_id)
{
return request_irq(irq, handler, irq_flags, devname, NULL);
}
static inline void *get_phy_page(void)
{
LosVmPage *page = LOS_PhysPageAlloc();
if (page == NULL)
return NULL;
return OsVmPageToVaddr(page);
}
static inline void *get_phy_pages(uint32_t size)
{
void *page = LOS_PhysPagesAllocContiguous(ROUNDUP(size, PAGE_SIZE) >> PAGE_SHIFT);
return page;
}
static inline void free_phy_page(void *ptr)
{
if (ptr == NULL)
return;
LosVmPage *page = OsVmVaddrToPage(ptr);
if (page != NULL)
LOS_PhysPageFree(page);
}
static inline void kthread_bind_mask(LosTaskCB *p, UINT16 mask)
{
if (p == NULL)
return;
LOS_TaskCpuAffiSet(p->taskID, mask);
}
static inline void preempt_disable(void)
{
uint32_t int_save = LOS_IntLock();
OsPercpuGet()->taskLockCnt++;
LOS_IntRestore(int_save);
}
static inline void preempt_enable(void)
{
uint32_t int_save = LOS_IntLock();
OsPercpuGet()->taskLockCnt--;
LOS_IntRestore(int_save);
}
static inline int cmpxchg(unsigned int *lock, int old, int new)
{
return LOS_AtomicCmpXchg32bits((Atomic *)lock, new, old);
}
static inline int raw_smp_processor_id(void)
{
return ArchCurrCpuid();
}
static inline int wake_up_process(LosTaskCB *p)
{
LOS_TaskYield();
return 0;
}
static inline void get_user(unsigned int *value, const unsigned int *user_ptr)
{
copy_from_user(value, user_ptr, sizeof(unsigned int));
}
static inline int get_current_pid(void)
{
return OsCurrTaskGet()->taskID;
}
/* unsupport restart syscall */
static inline int restart_syscall(void)
{
return 0;
}
static inline LosTaskCB *get_process_group_leader(LosTaskCB *task)
{
if (task == NULL)
return NULL;
return OS_TCB_FROM_TID(OS_PCB_FROM_PID(task->processID)->threadGroupID);
}
static inline unsigned long msecs_to_jiffies(const unsigned int m)
{
if ((int)m < 0)
return 0;
return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ);
}
static inline struct timespec current_kernel_time(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
return ts;
}
static inline void init_deferrable_work(struct delayed_work *w, void(* wq)(struct work_struct *))
{
INIT_DELAYED_WORK(w, wq);
}
static inline int is_kernel_thread(LosTaskCB *task)
{
if (task == NULL)
return true;
return (OS_PCB_FROM_PID(task->processID)->processMode == OS_KERNEL_MODE);
}
static inline int is_teecd_process(LosTaskCB *teecd, LosTaskCB *task)
{
if (teecd == NULL || task == NULL)
return 0;
return teecd->processID == task->processID;
}
typedef mbedtls_sha256_context tee_sha256_context;
static inline void init_tee_sha256(tee_sha256_context *ctx)
{
mbedtls_sha256_init(ctx);
(void)mbedtls_sha256_starts_ret(ctx, 0);
}
static inline void update_tee_sha256(tee_sha256_context *ctx, const unsigned char *input, size_t ilen)
{
(void)mbedtls_sha256_update_ret(ctx, input, ilen);
}
static inline void finish_tee_sha256(tee_sha256_context *ctx, unsigned char output[32])
{
(void)mbedtls_sha256_finish_ret(ctx, output);
}
#undef kmalloc
#define kmalloc(size, flags) malloc(size)
#undef kzalloc
#define kzalloc(size, flags) calloc(1, size)
#undef kfree
#define kfree(ptr) free(ptr)
#define virt_to_phys(addr) LOS_PaddrQuery(addr)
#define phys_to_virt(addr) LOS_PaddrToKVaddr(addr)
#define virt_addr_valid(addr) LOS_PaddrQuery(addr)
#define __get_free_page(flags) get_phy_page()
#define __get_free_pages(flags, size) get_phy_pages(size)
#define free_pages(page, flags) free_phy_page(page)
#define __free_pages(page, flags) free_phy_page(page)
#define free_page(page) free_phy_page(page)
#define page_address(page) OsVmPageToVaddr(page)
#define __init
#endif
+173
View File
@@ -0,0 +1,173 @@
/*
* 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 "teek_client_type.h"
#include "los_adapt.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
struct tc_ns_client_login {
uint32_t method;
uint32_t mdata;
};
union tc_ns_client_param {
struct {
unsigned int buffer;
unsigned int buffer_h_addr;
unsigned int offset;
unsigned int h_offset;
unsigned int size_addr;
unsigned int size_h_addr;
} memref;
struct {
unsigned int a_addr;
unsigned int a_h_addr;
unsigned int b_addr;
unsigned int b_h_addr;
} value;
};
struct tc_ns_client_return {
int code;
uint32_t origin;
};
struct tc_ns_client_context {
unsigned char uuid[UUID_LEN];
uint32_t session_id;
uint32_t cmd_id;
struct tc_ns_client_return returns;
struct tc_ns_client_login login;
union tc_ns_client_param params[PARAM_NUM];
uint32_t param_types;
bool started;
uint32_t calling_pid;
unsigned int file_size;
union {
char *file_buffer;
unsigned long long file_addr;
};
};
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,
};
struct load_secfile_ioctl_struct {
enum secfile_type_t secfile_type;
unsigned char uuid[UUID_LEN];
uint32_t file_size;
union {
char *file_buffer;
unsigned long long file_addr;
};
};
struct agent_ioctl_args {
uint32_t id;
uint32_t buffer_size;
union {
void *buffer;
unsigned long long addr;
};
};
#define vmalloc_addr_valid(kaddr) \
(((void *)(kaddr) >= (void *)VMALLOC_START) && \
((void *)(kaddr) < (void *)VMALLOC_END))
#define modules_addr_valid(kaddr) \
(((void *)(kaddr) >= (void *)MODULES_VADDR) && \
((void *)(kaddr) < (void *)MODULES_END))
#define TST_CMD_01 1
#define TST_CMD_02 2
#define TST_CMD_03 3
#define TST_CMD_04 4
#define TST_CMD_05 5
#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 \
_IO(TC_NS_CLIENT_IOC_MAGIC, 5)
#define TC_NS_CLIENT_IOCTL_SEND_EVENT_RESPONSE \
_IO(TC_NS_CLIENT_IOC_MAGIC, 6)
#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 \
_IO(TC_NS_CLIENT_IOC_MAGIC, 8)
#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 \
_IO(TC_NS_CLIENT_IOC_MAGIC, 14)
#define TC_NS_CLIENT_IOCTL_TST_CMD_REQ \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 15, int)
#define TC_NS_CLIENT_IOCTL_TUI_EVENT \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 16, int)
#define TC_NS_CLIENT_IOCTL_SYC_SYS_TIME \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 17, struct tc_ns_client_time)
#define TC_NS_CLIENT_IOCTL_SET_NATIVE_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 \
_IO(TC_NS_CLIENT_IOC_MAGIC, 20)
#define TC_NS_CLIENT_IOCTL_GET_TEE_VERSION \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 21, unsigned int)
#define TC_NS_CLIENT_IOCTL_UNMAP_SHARED_MEM \
_IOWR(TC_NS_CLIENT_IOC_MAGIC, 22, unsigned int)
#endif
+69
View File
@@ -0,0 +1,69 @@
/*
* 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/kernel.h>
enum {
TZ_DEBUG_VERBOSE = 0,
TZ_DEBUG_DEBUG,
TZ_DEBUG_INFO,
TZ_DEBUG_WARN,
TZ_DEBUG_ERROR,
};
#define MOD_TEE "tzdriver"
#ifdef DEF_ENG
#define TEE_ENG_LOG_MASK 2
#define TEE_LOG_MASK TEE_ENG_LOG_MASK
#else
#define TEE_USR_LOG_MASK 3
#define TEE_LOG_MASK TEE_USR_LOG_MASK
#endif
#define tlogv(fmt, args...) \
do { \
if (TZ_DEBUG_VERBOSE >= TEE_LOG_MASK) \
pr_info("([%s] %i, %s)%s: " fmt, MOD_TEE, OsCurrTaskGet()->taskID, OsCurrTaskGet()->taskName, __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, OsCurrTaskGet()->taskID, OsCurrTaskGet()->taskName, __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, OsCurrTaskGet()->taskID, OsCurrTaskGet()->taskName, __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, OsCurrTaskGet()->taskID, OsCurrTaskGet()->taskName, __func__, ## args); \
} while (0)
#define tloge(fmt, args...) \
pr_err("([%s] %i, %s)%s: " fmt, MOD_TEE, OsCurrTaskGet()->taskID, OsCurrTaskGet()->taskName, __func__, ## args)
#endif
+122
View File
@@ -0,0 +1,122 @@
/*
* 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
#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);
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);
#else
static inline int teek_is_agent_alive(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 void teek_finalize_context(struct 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 void teek_close_session(struct 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 uint32_t teek_send_secfile(struct teec_session *session,
const char *file_buffer, unsigned int file_size)
{
return TEEC_SUCCESS;
}
#endif
#endif
+168
View File
@@ -0,0 +1,168 @@
/*
* 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.
*/
#include <linux/types.h>
#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_LOAD_SECURE_APP_ION = 0x1e,
/* this cmd for tui to get notch_size */
GLOBAL_CMD_ID_TUI_NOTCH = 0x1f,
GLOBAL_CMD_ID_LATE_INIT = 0x20,
/* this cmd for tui to get information of foldable screen */
GLOBAL_CMD_ID_TUI_FOLD = 0x21,
GLOBAL_CMD_ID_GET_TEE_VERSION = 0x22,
GLOBAL_CMD_ID_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,
};
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_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,
};
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,
};
#endif
+79
View File
@@ -0,0 +1,79 @@
/*
* 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_ICC_OPEN_THREAD,
SECBOOT_CMD_ID_BSP_RFILE_RW_THREAD,
SECBOOT_CMD_ID_GET_RNG_NUM,
};
#endif
+192
View File
@@ -0,0 +1,192 @@
/*
* 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;
size_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;
size_t size;
};
struct teec_registeredmemory_reference {
struct teec_sharedmemory *parent;
size_t size;
size_t offset;
};
struct teec_value {
uint32_t a;
uint32_t b;
};
struct teec_ion_reference {
int ion_share_fd;
size_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 device */
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 {
uint32_t timeLow;
uint16_t timeMid;
uint16_t timeHiAndVersion;
uint8_t clockSeqAndNode[8];
} TEEC_UUID;
typedef struct {
void *dev;
uint8_t *ta_path;
struct list_head session_list;
struct list_head shrd_mem_list;
} TEEC_Context;
typedef struct {
uint32_t session_id;
TEEC_UUID service_id;
uint32_t ops_cnt;
struct list_head head;
TEEC_Context *context;
} TEEC_Session;
typedef struct {
void *buffer;
size_t size;
uint32_t flags;
uint32_t ops_cnt;
bool is_allocated;
struct list_head head;
TEEC_Context *context;
} TEEC_SharedMemory;
typedef struct {
void *buffer;
size_t size;
} TEEC_TempMemoryReference;
typedef struct {
TEEC_SharedMemory *parent;
size_t size;
size_t offset;
} TEEC_RegisteredMemoryReference;
typedef struct {
uint32_t a;
uint32_t b;
} TEEC_Value;
typedef struct {
int ion_share_fd;
size_t ion_size;
} TEEC_IonReference;
typedef union {
TEEC_TempMemoryReference tmpref;
TEEC_RegisteredMemoryReference memref;
TEEC_Value value;
TEEC_IonReference ionref;
} TEEC_Parameter;
typedef struct {
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 device */
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 */
} TEEC_TUI_Parameter;
typedef struct {
uint32_t started;
uint32_t paramTypes;
TEEC_Parameter params[4];
TEEC_Session *session;
bool cancel_flag;
} TEEC_Operation;
#endif
+196
View File
@@ -0,0 +1,196 @@
/*
* 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 <securec.h>
#include <linux/list.h>
#include <linux/slab.h>
#include "tc_ns_client.h"
#include "tc_ns_log.h"
#include "los_adapt.h"
#define TC_NS_CLIENT_IOC_MAGIC 't'
#define TC_NS_CLIENT_DEV "tc_ns_client"
#define TC_NS_CLIENT_DEV_NAME "/dev/tc_ns_client"
#define EXCEPTION_MEM_SIZE (8*1024) /* mem for exception handling */
#define TSP_REQUEST 0xB2000008
#define TSP_RESPONSE 0xB2000009
#define TSP_REE_SIQ 0xB200000A
#define TSP_CRASH 0xB200000B
#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
/* 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 {
mutex_t 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 */
};
struct tc_ns_shared_mem {
void *kernel_addr;
void *user_addr;
void *user_addr_ca; /* for ca alloc share mem */
unsigned int len;
struct list_head head;
atomic_t usage;
atomic_t offset;
};
struct tc_ns_service {
unsigned char uuid[UUID_LEN];
mutex_t session_lock; /* for session_list */
struct list_head session_list;
struct list_head head;
mutex_t 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;
mutex_t 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];
mutex_t 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;
mutex_t login_setup_lock; /* for login setup */
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;
};
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
#else
#define KIND_OF_SO 2
#endif
struct tc_ns_session {
unsigned int session_id;
struct list_head head;
struct tc_wait_data wait_data;
mutex_t 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];
};
#endif

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