mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
OP-TEE: add optee driver from GitHub: optee_linuxdriver
Commit 4136b9d5a139(Fix TEESMC{32,64}_FASTCALL_RETURN_FROM_RPC)
Change-Id: I389e4f79270e3bc6e8844ec81758f8b5546192a1
Signed-off-by: Zhang Zhijie <zhangzj@rock-chips.com>
This commit is contained in:
20
security/optee_linuxdriver/Kconfig
Normal file
20
security/optee_linuxdriver/Kconfig
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License Version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
|
||||
# Trursted Execution Environment Configuration
|
||||
config TEE_SUPPORT
|
||||
bool "Trusted Execution Environment Support"
|
||||
default y
|
||||
---help---
|
||||
This implements the Trusted Execution Environment (TEE) Client
|
||||
API Specification from GlobalPlatform Device Technology.
|
||||
339
security/optee_linuxdriver/LICENSE
Normal file
339
security/optee_linuxdriver/LICENSE
Normal file
@@ -0,0 +1,339 @@
|
||||
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.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
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
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
2
security/optee_linuxdriver/Makefile
Normal file
2
security/optee_linuxdriver/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
obj-y += core/
|
||||
obj-y += armtz/
|
||||
4
security/optee_linuxdriver/Notice.md
Normal file
4
security/optee_linuxdriver/Notice.md
Normal file
@@ -0,0 +1,4 @@
|
||||
To avoid duplicating information we link to the Notice.md file in optee_os which
|
||||
states the contributor agreement rules etc, i.e, optee_linuxdriver follows what
|
||||
is written in the Notice.md on the URL below
|
||||
https://github.com/OP-TEE/optee_os/blob/master/Notice.md
|
||||
91
security/optee_linuxdriver/README.md
Normal file
91
security/optee_linuxdriver/README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# OP-TEE Linux Driver
|
||||
The optee_linuxdriver git, containing the source code for the TEE driver
|
||||
module in Linux.
|
||||
It is distributed under the GPLv2 open-source license. For a general
|
||||
overview of OP-TEE, please see the [Notice.md](Notice.md) file.
|
||||
|
||||
In this git, the module to build is optee.ko.
|
||||
It allows communication between the Rich OS Client Application (unsecure
|
||||
world), the Trusted OS (secure world) and the tee-supplicant (unsecure
|
||||
world) which is a daemon serving the Trusted OS in secure world with
|
||||
miscellaneous features, such as file system access.
|
||||
|
||||
## License
|
||||
The software is provided under the
|
||||
[GPL-2.0](http://opensource.org/licenses/GPL-2.0) license.
|
||||
|
||||
## Platforms supported
|
||||
This software has hardware dependencies.
|
||||
The software has been tested using:
|
||||
|
||||
- STMicroelectronics b2020-h416 (orly-2) hardware (32-bits)
|
||||
- Some initial testing has been done using
|
||||
[Foundation FVP](http://www.arm.com/fvp), which can be downloaded free of
|
||||
charge.
|
||||
|
||||
## Get and build the software
|
||||
### Get the compiler
|
||||
We will strive to use the latest available compiler from Linaro. Start by
|
||||
downloading and unpacking the compiler. Then export the PATH to the bin folder.
|
||||
|
||||
$ cd $HOME
|
||||
$ mkdir toolchains
|
||||
$ cd toolchains
|
||||
$ wget http://releases.linaro.org/14.05/components/toolchain/binaries/gcc-linaro-arm-linux-gnueabihf-4.9-2014.05_linux.tar.xz
|
||||
$ tar xvf gcc-linaro-arm-linux-gnueabihf-4.9-2014.05_linux.tar.xz
|
||||
$ export PATH=$HOME/toolchains/gcc-linaro-arm-linux-gnueabihf-4.9-2014.05_linux/bin:$PATH
|
||||
|
||||
### Get the Linux kernel (from www.kernel.org)
|
||||
$ cd $HOME
|
||||
$ mkdir devel
|
||||
$ cd devel
|
||||
$ tar xf linux-3.10.32.tar.xz
|
||||
$ mv linux-3.10.32 linux
|
||||
|
||||
### Download the source code
|
||||
$ cd $HOME
|
||||
$ cd devel
|
||||
$ git clone https://github.com/OP-TEE/optee_linuxdriver.git
|
||||
|
||||
### Build
|
||||
$ cd $HOME/devel/linux
|
||||
$ make -j3 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mrproper
|
||||
$ make -j3 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig
|
||||
$ make -j3 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all
|
||||
$ make -j3 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- M=$HOME/devel/optee_linuxdriver modules
|
||||
|
||||
#### Compiler flags
|
||||
To be able to see the full command when building you could build using following
|
||||
flag:
|
||||
|
||||
`$ make V=1`
|
||||
|
||||
## Coding standards
|
||||
In this project we are trying to adhere to the same coding convention as used in
|
||||
the Linux kernel (see
|
||||
[CodingStyle](https://www.kernel.org/doc/Documentation/CodingStyle)). We achieve this by running
|
||||
[checkpatch](http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/scripts/checkpatch.pl) from Linux kernel.
|
||||
However there are a few exceptions that we had to make since the code also
|
||||
follows GlobalPlatform standards. The exceptions are as follows:
|
||||
|
||||
- CamelCase for GlobalPlatform types are allowed.
|
||||
- And we also exclude checking third party code that we might use in this
|
||||
project, such as LibTomCrypt, MPA, newlib (not in this particular git, but
|
||||
those are also part of the complete TEE solution). The reason for excluding
|
||||
and not fixing third party code is because we would probably deviate too much
|
||||
from upstream and therefore it would be hard to rebase against those projects
|
||||
later on (and we don't expect that it is easy to convince other software
|
||||
projects to change coding style).
|
||||
|
||||
### checkpatch
|
||||
Since checkpatch is licensed under the terms of GNU GPL License Version 2, we
|
||||
cannot include this script directly into this project. Therefore we have
|
||||
written the Makefile so you need to explicitly point to the script by exporting
|
||||
an environment variable, namely CHECKPATCH. So, suppose that the source code for
|
||||
the Linux kernel is at `$HOME/devel/linux`, then you have to export like follows:
|
||||
|
||||
$ export CHECKPATCH=$HOME/devel/linux/scripts/checkpatch.pl
|
||||
thereafter it should be possible to use one of the different checkpatch targets
|
||||
in the [Makefile](Makefile). There are targets for checking all files, checking
|
||||
against latest commit, against a certain base-commit etc. For the details, read
|
||||
the [Makefile](Makefile).
|
||||
40
security/optee_linuxdriver/armtz/Makefile
Normal file
40
security/optee_linuxdriver/armtz/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
#########################################################################
|
||||
# Set Internal Variables #
|
||||
# May be modified to match your setup #
|
||||
#########################################################################
|
||||
CFG_TEE_DRV_DEBUGFS?=0
|
||||
CFG_TEE_CORE_LOG_LEVEL?=2
|
||||
CFG_TEE_TA_LOG_LEVEL?=2
|
||||
|
||||
ccflags-y+=-Werror
|
||||
ccflags-y+=-I$(M)/include/arm_common
|
||||
ccflags-y+=-I$(M)/include/linux
|
||||
ccflags-y+=-I$(M)/include
|
||||
ccflags-y+=-I$(M)/core
|
||||
|
||||
ccflags-y+=-DCFG_TEE_DRV_DEBUGFS=${CFG_TEE_DRV_DEBUGFS}
|
||||
ccflags-y+=-DCFG_TEE_CORE_LOG_LEVEL=${CFG_TEE_CORE_LOG_LEVEL}
|
||||
ccflags-y+=-DCFG_TEE_TA_LOG_LEVEL=${CFG_TEE_TA_LOG_LEVEL}
|
||||
|
||||
obj-m += optee_armtz.o
|
||||
|
||||
optee_armtz-objs:= \
|
||||
tee_tz_drv.o \
|
||||
tee_mem.o \
|
||||
handle.o
|
||||
|
||||
|
||||
ifeq ($(CONFIG_ARM),y)
|
||||
# "smc" assembly intruction requires dedicated "armv7 secure extension"
|
||||
secext := $(call as-instr,.arch_extension sec,+sec)
|
||||
AFLAGS_tee_smc-arm.o := -Wa,-march=armv7-a$(secext)
|
||||
optee_armtz-objs += \
|
||||
tee_smc-arm.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARM64),y)
|
||||
optee_armtz-objs += \
|
||||
tee_smc-arm64.o
|
||||
endif
|
||||
|
||||
87
security/optee_linuxdriver/armtz/handle.c
Normal file
87
security/optee_linuxdriver/armtz/handle.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include "handle.h"
|
||||
|
||||
/*
|
||||
* Define the initial capacity of the database. It should be a low number
|
||||
* multiple of 2 since some databases a likely to only use a few handles.
|
||||
* Since the algorithm is to doubles up when growing it shouldn't cause a
|
||||
* noticable overhead on large databases.
|
||||
*/
|
||||
#define HANDLE_DB_INITIAL_MAX_PTRS 4
|
||||
|
||||
void handle_db_destroy(struct handle_db *db)
|
||||
{
|
||||
if (db) {
|
||||
kfree(db->ptrs);
|
||||
db->ptrs = NULL;
|
||||
db->max_ptrs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int handle_get(struct handle_db *db, void *ptr)
|
||||
{
|
||||
unsigned n;
|
||||
void *p;
|
||||
unsigned new_max_ptrs;
|
||||
|
||||
if (!db || !ptr)
|
||||
return -1;
|
||||
|
||||
/* Try to find an empty location */
|
||||
for (n = 0; n < db->max_ptrs; n++) {
|
||||
if (!db->ptrs[n]) {
|
||||
db->ptrs[n] = ptr;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
/* No location available, grow the ptrs array */
|
||||
if (db->max_ptrs)
|
||||
new_max_ptrs = db->max_ptrs * 2;
|
||||
else
|
||||
new_max_ptrs = HANDLE_DB_INITIAL_MAX_PTRS;
|
||||
p = krealloc(db->ptrs, new_max_ptrs * sizeof(void *), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -1;
|
||||
db->ptrs = p;
|
||||
memset(db->ptrs + db->max_ptrs, 0,
|
||||
(new_max_ptrs - db->max_ptrs) * sizeof(void *));
|
||||
db->max_ptrs = new_max_ptrs;
|
||||
|
||||
/* Since n stopped at db->max_ptrs there is an empty location there */
|
||||
db->ptrs[n] = ptr;
|
||||
return n;
|
||||
}
|
||||
|
||||
void *handle_put(struct handle_db *db, int handle)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (!db || handle < 0 || (unsigned)handle >= db->max_ptrs)
|
||||
return NULL;
|
||||
|
||||
p = db->ptrs[handle];
|
||||
db->ptrs[handle] = NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
void *handle_lookup(struct handle_db *db, int handle)
|
||||
{
|
||||
if (!db || handle < 0 || (unsigned)handle >= db->max_ptrs)
|
||||
return NULL;
|
||||
|
||||
return db->ptrs[handle];
|
||||
}
|
||||
52
security/optee_linuxdriver/armtz/handle.h
Normal file
52
security/optee_linuxdriver/armtz/handle.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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 HANDLE_H
|
||||
#define HANDLE_H
|
||||
|
||||
struct handle_db {
|
||||
void **ptrs;
|
||||
unsigned max_ptrs;
|
||||
};
|
||||
|
||||
#define HANDLE_DB_INITIALIZER { NULL, 0 }
|
||||
|
||||
/*
|
||||
* Frees all internal data structures of the database, but does not free
|
||||
* the db pointer. The database is safe to reuse after it's destroyed, it
|
||||
* just be empty again.
|
||||
*/
|
||||
void handle_db_destroy(struct handle_db *db);
|
||||
|
||||
/*
|
||||
* Allocates a new handle and assigns the supplied pointer to it,
|
||||
* ptr must not be NULL.
|
||||
* The function returns
|
||||
* >= 0 on success and
|
||||
* -1 on failure
|
||||
*/
|
||||
int handle_get(struct handle_db *db, void *ptr);
|
||||
|
||||
/*
|
||||
* Deallocates a handle. Returns the associated pointer of the handle
|
||||
* the the handle was valid or NULL if it's invalid.
|
||||
*/
|
||||
void *handle_put(struct handle_db *db, int handle);
|
||||
|
||||
/*
|
||||
* Returns the associated pointer of the handle if the handle is a valid
|
||||
* handle.
|
||||
* Returns NULL on failure.
|
||||
*/
|
||||
void *handle_lookup(struct handle_db *db, int handle);
|
||||
|
||||
#endif /*HANDLE_H*/
|
||||
675
security/optee_linuxdriver/armtz/tee_mem.c
Normal file
675
security/optee_linuxdriver/armtz/tee_mem.c
Normal file
@@ -0,0 +1,675 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
/**
|
||||
* \file tee_mem.c
|
||||
* \brief Functions to manage a pool of memory chunks.
|
||||
*
|
||||
* This module provides basic functions to manage dynamically a fixed amount
|
||||
* of memory (memory region). For this current implementation the provided
|
||||
* memory region used for the allocations should be physically AND logically
|
||||
* contiguous (only one region is supported for a given allocator).
|
||||
*
|
||||
* Principle of the allocator algorithm: "best fit"
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "tee_mem.h"
|
||||
|
||||
#define _DUMP_INFO_ALLOCATOR 0
|
||||
#define USE_DEVM_ALLOC 1
|
||||
|
||||
#ifndef USE_DEVM_ALLOC
|
||||
#define _KMALLOC(s, f) kmalloc(s, f)
|
||||
#define _KFREE(a) kfree(a)
|
||||
#else
|
||||
#define _KMALLOC(s, f) devm_kzalloc(dev, s, f)
|
||||
#define _KFREE(a) devm_kfree(dev, a)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \struct mem_chunk
|
||||
* \brief Elementary descriptor of an allocated memory block
|
||||
*
|
||||
* \param node Node for linked list
|
||||
* \param counter Reference counter
|
||||
* (0 indicates that the block is not used/freed)
|
||||
* \param size Total size in bytes
|
||||
* \param paddr Physical base address
|
||||
*
|
||||
* Elementary memory block definition
|
||||
*/
|
||||
struct mem_chunk {
|
||||
struct list_head node;
|
||||
uint32_t counter;
|
||||
size_t size;
|
||||
unsigned long paddr;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct shm_pool
|
||||
* \brief Main structure to describe a shared memory pool
|
||||
*
|
||||
* \param size Total size in bytes of the associated memory region
|
||||
* \param vaddr Logical base address
|
||||
* \param paddr Physical base address
|
||||
* \param used Total size in bytes of the used memory
|
||||
* \param mchunks List head for handle the elementary memory blocks
|
||||
*
|
||||
* Shared memory pool structure definition
|
||||
*/
|
||||
struct shm_pool {
|
||||
struct mutex lock;
|
||||
size_t size; /* Size of pool/heap memory segment */
|
||||
size_t used; /* Number of bytes allocated */
|
||||
void *vaddr; /* Associated Virtual address */
|
||||
unsigned long paddr; /* Associated Physical address */
|
||||
bool cached; /* true if pool is cacheable */
|
||||
struct list_head mchunks; /* Head of memory chunk/block list */
|
||||
};
|
||||
|
||||
#define __CALCULATE_RATIO_MEM_USED(a) (((a->used)*100)/(a->size))
|
||||
|
||||
/**
|
||||
* \brief Dumps the information of the shared memory pool
|
||||
*
|
||||
* \param pool Pointer on the pool
|
||||
* \param detailforced Flag to force the log for the detailed informations
|
||||
*
|
||||
* Dump/log the meta data of the shared memory pool on the standard output.
|
||||
*
|
||||
*/
|
||||
void tee_shm_pool_dump(struct device *dev, struct shm_pool *pool, bool forced)
|
||||
{
|
||||
struct mem_chunk *chunk;
|
||||
|
||||
if (WARN_ON(!dev || !pool))
|
||||
return;
|
||||
|
||||
dev_info(dev,
|
||||
"tee_shm_pool_dump() poolH(0x%p) pAddr=0x%p vAddr=0x%p size=%zu used=%zu(%zu%%)\n",
|
||||
(void *)pool,
|
||||
(void *)pool->paddr,
|
||||
(void *)pool->vaddr,
|
||||
pool->size, pool->used, __CALCULATE_RATIO_MEM_USED(pool));
|
||||
|
||||
if ((pool->used != 0) || (forced == true)) {
|
||||
dev_info(dev, " \\ HEAD next:[0x%p] prev:[0x%p]\n",
|
||||
(void *)pool->mchunks.next,
|
||||
(void *)pool->mchunks.prev);
|
||||
|
||||
dev_info(dev,
|
||||
" |-[@] next prev pAddr size refCount\n");
|
||||
|
||||
list_for_each_entry(chunk, &pool->mchunks, node) {
|
||||
dev_info(dev, " | [0x%p] 0x%p 0x%p 0x%p %08zu %d\n",
|
||||
(void *)chunk,
|
||||
(void *)chunk->node.next,
|
||||
(void *)chunk->node.prev,
|
||||
(void *)chunk->paddr,
|
||||
chunk->size, chunk->counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool tee_shm_pool_is_cached(struct shm_pool *pool)
|
||||
{
|
||||
return pool->cached;
|
||||
}
|
||||
|
||||
void tee_shm_pool_set_cached(struct shm_pool *pool)
|
||||
{
|
||||
pool->cached = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates and returns a new shared memory pool manager structure
|
||||
*
|
||||
* \param shm_size Size of the associated memory chunk
|
||||
* \param shm_vaddr Virtual/logical base address
|
||||
* \param shm_paddr Physical base address
|
||||
*
|
||||
* \return Reference of the created shared memory pool manager
|
||||
*
|
||||
* Create and initialize a shared memory pool manager.
|
||||
* The description of the memory region (shm_size, shm_vaddr, shm_paddr)
|
||||
* which is passed should be a physically AND virtually contiguous
|
||||
* (no check is performed by the function).
|
||||
* If a error is detected returned pool is NULL.
|
||||
*/
|
||||
struct shm_pool *tee_shm_pool_create(struct device *dev, size_t shm_size,
|
||||
void *shm_vaddr, unsigned long shm_paddr)
|
||||
{
|
||||
struct mem_chunk *chunk = NULL;
|
||||
struct shm_pool *pool = NULL;
|
||||
|
||||
if (WARN_ON(!dev))
|
||||
goto alloc_failed;
|
||||
|
||||
dev_dbg(dev, "> vaddr=0x%p, paddr=0x%p, size=%zuKiB\n",
|
||||
shm_vaddr, (void *)shm_paddr, shm_size / 1024);
|
||||
|
||||
/* Alloc and initialize the shm_pool structure */
|
||||
pool = _KMALLOC(sizeof(struct shm_pool), GFP_KERNEL);
|
||||
if (!pool) {
|
||||
dev_err(dev, "kmalloc <struct shm_pool> failed\n");
|
||||
goto alloc_failed;
|
||||
}
|
||||
memset(pool, 0, sizeof(*pool));
|
||||
mutex_init(&pool->lock);
|
||||
mutex_lock(&pool->lock);
|
||||
|
||||
INIT_LIST_HEAD(&(pool->mchunks));
|
||||
pool->size = shm_size;
|
||||
pool->vaddr = shm_vaddr;
|
||||
pool->paddr = shm_paddr;
|
||||
|
||||
/* Create the initial elementary memory chunk */
|
||||
/* which handles the whole memory region */
|
||||
chunk = _KMALLOC(sizeof(struct mem_chunk), GFP_KERNEL);
|
||||
if (!chunk) {
|
||||
dev_err(dev, "kmalloc <struct MemChunk> failed\n");
|
||||
goto alloc_failed;
|
||||
}
|
||||
memset(chunk, 0, sizeof(*chunk));
|
||||
chunk->paddr = shm_paddr;
|
||||
chunk->size = shm_size;
|
||||
|
||||
/* Adds the new entry immediately after the list head */
|
||||
list_add(&(chunk->node), &(pool->mchunks));
|
||||
|
||||
#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 0)
|
||||
tee_shm_pool_dump(dev, pool, true);
|
||||
#endif
|
||||
dev_dbg(dev, "< poolH(0x%p) chunkH=0x%p\n",
|
||||
(void *)(pool), (void *)chunk);
|
||||
|
||||
mutex_unlock(&pool->lock);
|
||||
return pool;
|
||||
|
||||
alloc_failed:
|
||||
if (chunk)
|
||||
_KFREE(chunk);
|
||||
|
||||
if (pool)
|
||||
_KFREE(pool);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local helper function to check that the physical address is valid
|
||||
*/
|
||||
static inline int is_valid_paddr(struct shm_pool *pool, unsigned long paddr)
|
||||
{
|
||||
return (paddr >= pool->paddr && paddr < (pool->paddr + pool->size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Local helper function to check that the virtual address is valid
|
||||
*/
|
||||
static inline int is_valid_vaddr(struct shm_pool *pool, void *vaddr)
|
||||
{
|
||||
return (vaddr >= pool->vaddr && vaddr < (pool->vaddr + pool->size));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Destroy the shared memory pool manager
|
||||
*
|
||||
* \param pool Pointer on the pool
|
||||
*
|
||||
* Destroy a memory pool manager
|
||||
*
|
||||
*/
|
||||
void tee_shm_pool_destroy(struct device *dev, struct shm_pool *pool)
|
||||
{
|
||||
struct mem_chunk *chunk;
|
||||
|
||||
if (WARN_ON(!dev || !pool))
|
||||
return;
|
||||
|
||||
dev_dbg(dev, "> poolH(0x%p)\n", (void *)pool);
|
||||
|
||||
#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 0)
|
||||
tee_shm_pool_dump(dev, pool, true);
|
||||
#endif
|
||||
|
||||
tee_shm_pool_reset(dev, pool);
|
||||
|
||||
chunk = list_first_entry(&pool->mchunks, struct mem_chunk, node);
|
||||
dev_dbg(dev, "free chunkH=0x%p\n", (void *)chunk);
|
||||
_KFREE(chunk);
|
||||
_KFREE(pool);
|
||||
|
||||
dev_dbg(dev, "<\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Free all reserved chunk if any, and set pool at it initial state
|
||||
*
|
||||
* \param pool Pointer on the pool
|
||||
*
|
||||
*/
|
||||
void tee_shm_pool_reset(struct device *dev, struct shm_pool *pool)
|
||||
{
|
||||
struct mem_chunk *chunk;
|
||||
struct mem_chunk *tmp;
|
||||
struct mem_chunk *first = NULL;
|
||||
|
||||
if (WARN_ON(!dev || !pool))
|
||||
return;
|
||||
|
||||
mutex_lock(&pool->lock);
|
||||
|
||||
list_for_each_entry_safe(chunk, tmp, &pool->mchunks, node) {
|
||||
if (first != NULL) {
|
||||
dev_err(dev, "Free lost chunkH=0x%p\n", (void *)chunk);
|
||||
list_del(&chunk->node);
|
||||
_KFREE(chunk);
|
||||
} else {
|
||||
first = chunk;
|
||||
}
|
||||
}
|
||||
|
||||
first->counter = 0;
|
||||
first->paddr = pool->paddr;
|
||||
first->size = pool->size;
|
||||
pool->used = 0;
|
||||
|
||||
mutex_unlock(&pool->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the logical address
|
||||
*
|
||||
* \param pool Pointer on the pool
|
||||
* \param paddr Physical address
|
||||
*
|
||||
* \return Virtual/logical address
|
||||
*
|
||||
* Return the associated virtual/logical address. The address should be inside
|
||||
* the range of addresses managed by the shm pool.
|
||||
*
|
||||
*/
|
||||
void *tee_shm_pool_p2v(struct device *dev, struct shm_pool *pool,
|
||||
unsigned long paddr)
|
||||
{
|
||||
if (WARN_ON(!dev || !pool))
|
||||
return NULL;
|
||||
|
||||
mutex_lock(&pool->lock);
|
||||
if (!is_valid_paddr(pool, paddr)) {
|
||||
mutex_unlock(&pool->lock);
|
||||
dev_err(dev,
|
||||
"tee_shm_pool_p2v() paddr=0x%p not in the shm pool\n",
|
||||
(void *)paddr);
|
||||
return NULL;
|
||||
} else {
|
||||
unsigned long offset = paddr - pool->paddr;
|
||||
void *p = (void *)((unsigned long)pool->vaddr + offset);
|
||||
|
||||
mutex_unlock(&pool->lock);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the physical address
|
||||
*
|
||||
* \param pool Pointer on the pool
|
||||
* \param vaddr Logical/Virtual address
|
||||
*
|
||||
* \return Physical address
|
||||
*
|
||||
* Return the associated physical address. The address should be inside
|
||||
* the range of addresses managed by the pool.
|
||||
*
|
||||
*/
|
||||
unsigned long tee_shm_pool_v2p(struct device *dev, struct shm_pool *pool,
|
||||
void *vaddr)
|
||||
{
|
||||
if (WARN_ON(!dev || !pool))
|
||||
return 0UL;
|
||||
|
||||
mutex_lock(&pool->lock);
|
||||
if (!is_valid_vaddr(pool, vaddr)) {
|
||||
dev_err(dev,
|
||||
"tee_shm_pool_v2p() vaddr=0x%p not in shm pool\n",
|
||||
(void *)vaddr);
|
||||
mutex_unlock(&pool->lock);
|
||||
return 0UL;
|
||||
} else {
|
||||
unsigned long offset = vaddr - pool->vaddr;
|
||||
unsigned long p = pool->paddr + offset;
|
||||
|
||||
mutex_unlock(&pool->lock);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate a new block of memory
|
||||
*
|
||||
* \param pool Pointer on the pool
|
||||
* \param size Expected size (in byte)
|
||||
* \param alignment Alignment constraint (in byte)
|
||||
*
|
||||
* \return Physical base address of the allocated block
|
||||
*
|
||||
* Allocate a memory chunk inside the memory region managed by the pool.
|
||||
*
|
||||
*/
|
||||
unsigned long tee_shm_pool_alloc(struct device *dev,
|
||||
struct shm_pool *pool,
|
||||
size_t size, size_t alignment)
|
||||
{
|
||||
struct mem_chunk *chunk;
|
||||
struct mem_chunk *betterchunk = NULL;
|
||||
struct mem_chunk *prev_chunk = NULL;
|
||||
struct mem_chunk *next_chunk = NULL;
|
||||
unsigned long begAddr;
|
||||
unsigned long endAddr;
|
||||
|
||||
if (WARN_ON(!dev || !pool))
|
||||
return 0UL;
|
||||
|
||||
dev_dbg(dev, "> poolH(%p:%p:%x) size=0x%zx align=0x%zx\n",
|
||||
pool, (void *)pool->paddr, (unsigned int)pool->size, size,
|
||||
alignment);
|
||||
|
||||
/* Align on cache line of the target */
|
||||
/* \todo(jmd) Should be defined by a global target specific parameter */
|
||||
/* size = (size + (32-1)) & ~(32-1) */
|
||||
|
||||
if (ALIGN(size, 0x20) < size)
|
||||
goto failed_out;
|
||||
|
||||
if (alignment == 0)
|
||||
alignment = 1;
|
||||
|
||||
size = ALIGN(size, 0x20);
|
||||
|
||||
alignment = ALIGN(alignment, 0x20);
|
||||
|
||||
if (size > (pool->size - pool->used))
|
||||
goto failed_out;
|
||||
|
||||
mutex_lock(&pool->lock);
|
||||
|
||||
/**
|
||||
* Algorithm: Smallest waste (best fit): We choose the block that has the
|
||||
* smallest waste. In other words we choose the block so that
|
||||
* size(b) - size is as small as possible.
|
||||
*/
|
||||
list_for_each_entry(chunk, &pool->mchunks, node) {
|
||||
if (chunk->counter == 0) { /* Free chunk */
|
||||
begAddr = ALIGN(chunk->paddr, alignment);
|
||||
endAddr = begAddr + size;
|
||||
|
||||
if (begAddr >= chunk->paddr
|
||||
&& endAddr <= (chunk->paddr + chunk->size)
|
||||
&& (betterchunk == NULL
|
||||
/* Always split smaller block */
|
||||
|| chunk->size < betterchunk->size))
|
||||
betterchunk = chunk;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the linked list
|
||||
*/
|
||||
if (betterchunk != NULL) {
|
||||
prev_chunk = _KMALLOC(sizeof(struct mem_chunk), GFP_KERNEL);
|
||||
next_chunk = _KMALLOC(sizeof(struct mem_chunk), GFP_KERNEL);
|
||||
|
||||
if ((!prev_chunk) || (!next_chunk))
|
||||
goto failed_out_unlock;
|
||||
|
||||
begAddr = ALIGN(betterchunk->paddr, alignment);
|
||||
endAddr = begAddr + size;
|
||||
|
||||
if (betterchunk->paddr < begAddr) {
|
||||
/* memory between begin of chunk and begin
|
||||
* of created memory => create a free chunk */
|
||||
prev_chunk->counter = 0;
|
||||
prev_chunk->paddr = betterchunk->paddr;
|
||||
prev_chunk->size = begAddr - betterchunk->paddr;
|
||||
|
||||
betterchunk->paddr = begAddr;
|
||||
betterchunk->size -= prev_chunk->size;
|
||||
|
||||
dev_dbg(dev,
|
||||
"create p_chunkH=0x%p paddr=0x%p (s=%zu)\n",
|
||||
(void *)prev_chunk,
|
||||
(void *)prev_chunk->paddr, prev_chunk->size);
|
||||
|
||||
list_add_tail(&(prev_chunk->node),
|
||||
&(betterchunk->node));
|
||||
prev_chunk = NULL;
|
||||
} else {
|
||||
_KFREE(prev_chunk);
|
||||
}
|
||||
|
||||
if (betterchunk->paddr + betterchunk->size > endAddr) {
|
||||
/* memory between end of chunk and end of
|
||||
* created memory => create a free chunk */
|
||||
next_chunk->counter = 0;
|
||||
next_chunk->paddr = endAddr;
|
||||
next_chunk->size = betterchunk->size - size;
|
||||
|
||||
dev_dbg(dev,
|
||||
"create n_chunkH=0x%p paddr=0x%p (s=%zu)\n",
|
||||
(void *)next_chunk,
|
||||
(void *)next_chunk->paddr, next_chunk->size);
|
||||
|
||||
betterchunk->size = size;
|
||||
|
||||
list_add(&(next_chunk->node), &(betterchunk->node));
|
||||
next_chunk = NULL;
|
||||
} else {
|
||||
_KFREE(next_chunk);
|
||||
}
|
||||
|
||||
betterchunk->counter = 1;
|
||||
pool->used += size;
|
||||
|
||||
mutex_unlock(&pool->lock);
|
||||
|
||||
#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 1)
|
||||
tee_shm_pool_dump(dev, pool, false);
|
||||
#endif
|
||||
|
||||
dev_dbg(dev,
|
||||
"< chunkH=0x%p paddr=%p (s=%zu) align=0x%zx\n",
|
||||
(void *)betterchunk,
|
||||
(void *)betterchunk->paddr,
|
||||
betterchunk->size, alignment);
|
||||
|
||||
return betterchunk->paddr;
|
||||
}
|
||||
|
||||
failed_out_unlock:
|
||||
mutex_unlock(&pool->lock);
|
||||
failed_out:
|
||||
if (prev_chunk)
|
||||
_KFREE(prev_chunk);
|
||||
if (next_chunk)
|
||||
_KFREE(next_chunk);
|
||||
|
||||
dev_err(dev,
|
||||
"tee_shm_pool_alloc() FAILED, size=0x%zx, align=0x%zx free=%zu\n",
|
||||
size, alignment, pool->size - pool->used);
|
||||
|
||||
#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 1)
|
||||
tee_shm_pool_dump(dev, pool, true);
|
||||
#endif
|
||||
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Release a allocated block of memory
|
||||
*
|
||||
* \param pool Pointer on the pool
|
||||
* \param paddr Physical @ of the block which must be released
|
||||
* \param size Reference to return the size of the block
|
||||
*
|
||||
* Free a allocated memory block inside
|
||||
* the memory region managed by the pool.
|
||||
*
|
||||
*/
|
||||
int tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
|
||||
unsigned long paddr, size_t *size)
|
||||
{
|
||||
struct mem_chunk *chunk;
|
||||
|
||||
if (WARN_ON(!dev || !pool))
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(dev, "> Try to free ... poolH(0x%p) paddr=0x%p\n",
|
||||
(void *)pool, (void *)paddr);
|
||||
|
||||
#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 1)
|
||||
tee_shm_pool_dump(dev, pool, false);
|
||||
#endif
|
||||
|
||||
mutex_lock(&pool->lock);
|
||||
|
||||
if (!is_valid_paddr(pool, paddr))
|
||||
goto out_failed;
|
||||
|
||||
list_for_each_entry(chunk, &pool->mchunks, node) {
|
||||
if (chunk->paddr == paddr) {
|
||||
if (size != NULL)
|
||||
*size = chunk->size;
|
||||
|
||||
if (chunk->counter == 0) {
|
||||
dev_warn(dev,
|
||||
"< tee_shm_pool_free() WARNING, paddr=0x%p already released\n",
|
||||
(void *)paddr);
|
||||
return -EINVAL;
|
||||
} else if (--chunk->counter == 0) {
|
||||
dev_dbg(dev, "paddr=%p\n", (void *)paddr);
|
||||
|
||||
pool->used -= chunk->size;
|
||||
|
||||
/* Merge with previous */
|
||||
if (chunk->node.prev != &pool->mchunks) {
|
||||
struct mem_chunk *prev =
|
||||
list_entry(chunk->node.prev,
|
||||
struct mem_chunk, node);
|
||||
if (prev->counter == 0) {
|
||||
dev_dbg(dev,
|
||||
"chunkH=0x%p paddr=0x%p free ok\n",
|
||||
(void *)chunk,
|
||||
(void *)paddr);
|
||||
prev->size += chunk->size;
|
||||
list_del(&chunk->node);
|
||||
_KFREE(chunk);
|
||||
chunk = prev;
|
||||
}
|
||||
}
|
||||
/* Merge with next */
|
||||
if (chunk->node.next != &pool->mchunks) {
|
||||
struct mem_chunk *next =
|
||||
list_entry(chunk->node.next,
|
||||
struct mem_chunk, node);
|
||||
if (next->counter == 0) {
|
||||
dev_dbg(dev,
|
||||
"chunkH=0x%p paddr=0x%p free ok\n",
|
||||
(void *)chunk,
|
||||
(void *)paddr);
|
||||
chunk->size += next->size;
|
||||
list_del(&next->node);
|
||||
_KFREE(next);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&pool->lock);
|
||||
|
||||
#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 1)
|
||||
tee_shm_pool_dump(dev, pool, false);
|
||||
#endif
|
||||
dev_dbg(dev, "< freed\n");
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
mutex_unlock(&pool->lock);
|
||||
dev_dbg(dev,
|
||||
"< paddr=0x%p (--) refcounter is decremented ret=1\n",
|
||||
(void *)paddr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out_failed:
|
||||
mutex_unlock(&pool->lock);
|
||||
#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 1)
|
||||
tee_shm_pool_dump(dev, pool, false);
|
||||
#endif
|
||||
dev_err(dev,
|
||||
"< tee_shm_pool_free() FAILED, pAddr=0x%p not found\n",
|
||||
(void *)paddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Increase the reference count of the memory chunk
|
||||
*
|
||||
* \param pool Pointer on the pool
|
||||
* \param paddr Physical address
|
||||
*
|
||||
* \return true if successful (false otherwise)
|
||||
*
|
||||
* Increment the reference count of the allocated block of memory.
|
||||
* paddr should a valid address returned by the tee_shm_pool_alloc().
|
||||
*
|
||||
*/
|
||||
bool tee_shm_pool_incref(struct device *dev, struct shm_pool *pool,
|
||||
unsigned long paddr)
|
||||
{
|
||||
struct mem_chunk *chunk;
|
||||
|
||||
if (WARN_ON(!dev || !pool))
|
||||
return false;
|
||||
|
||||
mutex_lock(&pool->lock);
|
||||
|
||||
if (!is_valid_paddr(pool, paddr))
|
||||
goto out_failed;
|
||||
|
||||
list_for_each_entry(chunk, &pool->mchunks, node) {
|
||||
if (chunk->paddr == paddr) {
|
||||
dev_dbg(dev,
|
||||
"pAddr=%p (++) refcounter is incremented\n",
|
||||
(void *)paddr);
|
||||
chunk->counter++;
|
||||
|
||||
#if defined(_DUMP_INFO_ALLOCATOR) && (_DUMP_INFO_ALLOCATOR > 0)
|
||||
tee_shm_pool_dump(dev, pool, false);
|
||||
#endif
|
||||
mutex_unlock(&pool->lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
out_failed:
|
||||
mutex_unlock(&pool->lock);
|
||||
|
||||
dev_err(dev,
|
||||
"tee_shm_pool_incref() FAILED, pAddr=%p is not a valid @\n",
|
||||
(void *)paddr);
|
||||
|
||||
return false;
|
||||
}
|
||||
50
security/optee_linuxdriver/armtz/tee_mem.h
Normal file
50
security/optee_linuxdriver/armtz/tee_mem.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_MEM_H
|
||||
#define TEE_MEM_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
struct shm_pool;
|
||||
|
||||
struct shm_pool *tee_shm_pool_create(struct device *dev, size_t shm_size,
|
||||
void *shm_vaddr, unsigned long shm_paddr);
|
||||
|
||||
void tee_shm_pool_destroy(struct device *dev, struct shm_pool *pool);
|
||||
|
||||
void *tee_shm_pool_p2v(struct device *dev, struct shm_pool *pool,
|
||||
unsigned long paddr);
|
||||
|
||||
unsigned long tee_shm_pool_v2p(struct device *dev, struct shm_pool *pool,
|
||||
void *vaddr);
|
||||
|
||||
unsigned long tee_shm_pool_alloc(struct device *dev,
|
||||
struct shm_pool *pool,
|
||||
size_t size, size_t alignment);
|
||||
|
||||
int tee_shm_pool_free(struct device *dev, struct shm_pool *pool,
|
||||
unsigned long paddr, size_t *size);
|
||||
|
||||
bool tee_shm_pool_incref(struct device *dev, struct shm_pool *pool,
|
||||
unsigned long paddr);
|
||||
|
||||
void tee_shm_pool_dump(struct device *dev, struct shm_pool *pool, bool forced);
|
||||
|
||||
void tee_shm_pool_reset(struct device *dev, struct shm_pool *pool);
|
||||
|
||||
bool tee_shm_pool_is_cached(struct shm_pool *pool);
|
||||
|
||||
void tee_shm_pool_set_cached(struct shm_pool *pool);
|
||||
|
||||
#endif
|
||||
29
security/optee_linuxdriver/armtz/tee_smc-arm.S
Normal file
29
security/optee_linuxdriver/armtz/tee_smc-arm.S
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/linkage.h>
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.code 32
|
||||
|
||||
/* void tee_smc_call(struct smc_param *param); */
|
||||
.globl tee_smc_call
|
||||
ENTRY(tee_smc_call)
|
||||
push {r4-r8, lr}
|
||||
mov r8, r0
|
||||
ldm r8, {r0-r7}
|
||||
.arch_extension sec
|
||||
smc #0
|
||||
stm r8, {r0-r7}
|
||||
pop {r4-r8, pc}
|
||||
ENDPROC(tee_smc_call)
|
||||
36
security/optee_linuxdriver/armtz/tee_smc-arm64.S
Normal file
36
security/optee_linuxdriver/armtz/tee_smc-arm64.S
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/linkage.h>
|
||||
|
||||
.text
|
||||
|
||||
#define SMC_PARAM_X0_OFFS 0
|
||||
#define SMC_PARAM_X2_OFFS 16
|
||||
#define SMC_PARAM_X4_OFFS 32
|
||||
#define SMC_PARAM_X6_OFFS 48
|
||||
|
||||
/* void tee_smc_call(struct smc_param *param); */
|
||||
.globl tee_smc_call
|
||||
ENTRY(tee_smc_call)
|
||||
stp x28, x30, [sp, #-16]!
|
||||
mov x28, x0
|
||||
ldp x0, x1, [x28, #SMC_PARAM_X0_OFFS]
|
||||
ldp x2, x3, [x28, #SMC_PARAM_X2_OFFS]
|
||||
ldp x4, x5, [x28, #SMC_PARAM_X4_OFFS]
|
||||
ldp x6, x7, [x28, #SMC_PARAM_X6_OFFS]
|
||||
smc #0
|
||||
stp x0, x1, [x28, #SMC_PARAM_X0_OFFS]
|
||||
stp x2, x3, [x28, #SMC_PARAM_X2_OFFS]
|
||||
ldp x28, x30, [sp], #16
|
||||
ret
|
||||
ENDPROC(tee_smc_call)
|
||||
1369
security/optee_linuxdriver/armtz/tee_tz_drv.c
Normal file
1369
security/optee_linuxdriver/armtz/tee_tz_drv.c
Normal file
File diff suppressed because it is too large
Load Diff
270
security/optee_linuxdriver/armtz/tee_tz_op.h
Normal file
270
security/optee_linuxdriver/armtz/tee_tz_op.h
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_ARMV7_OP_H__
|
||||
#define __TEE_ARMV7_OP_H__
|
||||
|
||||
enum t_issw_service_id {
|
||||
/*
|
||||
* ("SSAPI_PRE_INIT_SERV")
|
||||
*/
|
||||
SSAPI_PRE_INIT_SERV = 1,
|
||||
|
||||
/*
|
||||
* ("SSAPI_POST_SPEEDUP_INIT_SERV")
|
||||
* Reserved, Not used
|
||||
*/
|
||||
SSAPI_POST_SPEEDUP_INIT_SERV = 2,
|
||||
|
||||
/*
|
||||
* ("SSAPI_ISSW_IMPORT_SERV")
|
||||
*/
|
||||
SSAPI_ISSW_IMPORT_SERV = 3,
|
||||
|
||||
/*
|
||||
* ("SSAPI_RET_FROM_INT_SERV")
|
||||
*/
|
||||
SSAPI_RET_FROM_INT_SERV = 4,
|
||||
|
||||
/*
|
||||
* ("SSAPI_RET_FROM_RPC_SERV")
|
||||
*/
|
||||
SSAPI_RET_FROM_RPC_SERV = 5,
|
||||
|
||||
/*
|
||||
* "ISSWAPI_ISSW_EXECUTE_SERV" is linked to ROM code
|
||||
* ("SSAPI_ISSW_EXECUTE_SERV")
|
||||
*/
|
||||
ISSWAPI_ISSW_EXECUTE_SERV = 6,
|
||||
ISSWAPI_PROT_APPL_MSG_SEND = 0x10000000,
|
||||
ISSWAPI_EXTERNAL_CODE_CHECK = 0x10000001,
|
||||
ISSWAPI_SECURE_LOAD = 0x10000002,
|
||||
ISSWAPI_ISSW_REIMPORT_PUB_KEYS = 0x10000003,
|
||||
|
||||
/* Accessible only on request */
|
||||
ISSWAPI_WRITE_L2CC = 0x10000004,
|
||||
ISSWAPI_WRITE_CP15_SCTLR = 0x10000005,
|
||||
ISSWAPI_READ_CP15_SCTLR = 0x10000006,
|
||||
ISSWAPI_WRITE_CP15_ACTLR = 0x10000007,
|
||||
ISSWAPI_READ_CP15_ACTLR = 0x10000008,
|
||||
ISSWAPI_WRITE_CP15_DIAGR = 0x10000009,
|
||||
ISSWAPI_READ_CP15_DIAGR = 0x1000000A,
|
||||
|
||||
ISSWAPI_EXECUTE_TA = 0x11000001,
|
||||
ISSWAPI_CLOSE_TA = 0x11000002,
|
||||
ISSWAPI_FLUSH_BOOT_CODE = 0x11000003,
|
||||
/* Generic, restricted to be used by u-boot */
|
||||
ISSWAPI_VERIFY_SIGNED_HEADER = 0x11000005,
|
||||
ISSWAPI_VERIFY_HASH = 0x11000006,
|
||||
/* 8500 only, restricted to be used by u-boot */
|
||||
ISSWAPI_GET_RT_FLAGS = 0x11000007,
|
||||
|
||||
/* For TEE Client API 1.0 */
|
||||
ISSWAPI_TEEC_OPEN_SESSION = 0x11000008,
|
||||
ISSWAPI_TEEC_CLOSE_SESSION = 0x11000009,
|
||||
ISSWAPI_TEEC_INVOKE_COMMAND = 0x1100000a,
|
||||
ISSWAPI_REGISTER_RPC = 0x1100000b, /* this is NOT a GP TEE API ! */
|
||||
ISSWAPI_SET_SEC_DDR = 0x1100000c, /* this is NOT a GP TEE API ! */
|
||||
ISSWAPI_TEEC_CANCEL_COMMAND = 0x1100000d,
|
||||
ISSWAPI_TEEC_REGISTER_MEMORY = 0x1100000e,
|
||||
ISSWAPI_TEEC_UNREGISTER_MEMORY = 0x1100000f,
|
||||
|
||||
/* Internal command */
|
||||
ISSWAPI_TEE_DEINIT_CPU = 0x11000010,
|
||||
ISSWAPI_TEE_CRASH_CPU = 0x11000011,
|
||||
ISSWAPI_TEE_SET_CORE_TRACE_LEVEL = 0x11000012,
|
||||
ISSWAPI_TEE_GET_CORE_TRACE_LEVEL = 0x11000013,
|
||||
ISSWAPI_TEE_SET_TA_TRACE_LEVEL = 0x11000014,
|
||||
ISSWAPI_TEE_GET_TA_TRACE_LEVEL = 0x11000015,
|
||||
ISSWAPI_TEE_GET_CORE_STATUS = 0x11000016,
|
||||
ISSWAPI_TEE_FLUSH_CACHE = 0x11000017,
|
||||
|
||||
ISSWAPI_REGISTER_DEF_SHM = 0x11000020,
|
||||
ISSWAPI_UNREGISTER_DEF_SHM = 0x11000021,
|
||||
ISSWAPI_REGISTER_IRQFWD = 0x11000022,
|
||||
ISSWAPI_UNREGISTER_IRQFWD = 0x11000023,
|
||||
ISSWAPI_GET_SHM_START = 0x11000024,
|
||||
ISSWAPI_GET_SHM_SIZE = 0x11000025,
|
||||
ISSWAPI_GET_SHM_CACHED = 0x11000026,
|
||||
|
||||
ISSWAPI_ENABLE_L2CC_MUTEX = 0x20000000,
|
||||
ISSWAPI_DISABLE_L2CC_MUTEX = 0x20000001,
|
||||
ISSWAPI_GET_L2CC_MUTEX = 0x20000002,
|
||||
ISSWAPI_SET_L2CC_MUTEX = 0x20000003,
|
||||
|
||||
ISSWAPI_LOAD_TEE = 0x20000004,
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_msg_send - generic part of the msg sent to the TEE
|
||||
*/
|
||||
struct tee_msg_send {
|
||||
unsigned int service;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_msg_recv - default strcutre of TEE service output message
|
||||
*/
|
||||
struct tee_msg_recv {
|
||||
int duration;
|
||||
uint32_t res;
|
||||
uint32_t origin;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_register_irqfwd_xxx - (un)register callback for interrupt forwarding
|
||||
*/
|
||||
struct tee_register_irqfwd_send {
|
||||
struct tee_msg_send header;
|
||||
struct {
|
||||
unsigned long cb;
|
||||
} data;
|
||||
};
|
||||
struct tee_register_irqfwd_recv {
|
||||
struct tee_msg_recv header;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_get_l2cc_mutex - input/output argument structures
|
||||
*/
|
||||
struct tee_get_l2cc_mutex_send {
|
||||
struct tee_msg_send header;
|
||||
};
|
||||
struct tee_get_l2cc_mutex_recv {
|
||||
struct tee_msg_recv header;
|
||||
struct {
|
||||
unsigned long paddr;
|
||||
} data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_identity - Represents the identity of the client
|
||||
* @login: Login id
|
||||
* @uuid: UUID as defined above
|
||||
*/
|
||||
struct tee_identity {
|
||||
uint32_t login;
|
||||
TEEC_UUID uuid;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_open_session_data - input arg structure for TEE open session service
|
||||
*/
|
||||
struct tee_open_session_data {
|
||||
struct ta_signed_header_t *ta;
|
||||
TEEC_UUID uuid;
|
||||
uint32_t param_types;
|
||||
TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
struct tee_identity client_id;
|
||||
uint32_t params_flags[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_open_session_send - input arg msg for TEE open session service
|
||||
*/
|
||||
struct tee_open_session_send {
|
||||
struct tee_msg_send header;
|
||||
struct tee_open_session_data data;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_open_session_recv - output arg structure for TEE open session service
|
||||
*/
|
||||
struct tee_open_session_recv {
|
||||
struct tee_msg_recv header;
|
||||
uint32_t sess;
|
||||
TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_invoke_command_data - input arg structure for TEE invoke cmd service
|
||||
*/
|
||||
struct tee_invoke_command_data {
|
||||
uint32_t sess;
|
||||
uint32_t cmd;
|
||||
uint32_t param_types;
|
||||
TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
uint32_t params_flags[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
};
|
||||
|
||||
struct tee_invoke_command_send {
|
||||
struct tee_msg_send header;
|
||||
struct tee_invoke_command_data data;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_invoke_command_recv - output arg structure for TEE invoke cmd service
|
||||
*/
|
||||
struct tee_invoke_command_recv {
|
||||
struct tee_msg_recv header;
|
||||
TEEC_Value params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_cancel_command_data - input arg structure for TEE cancel service
|
||||
*/
|
||||
struct tee_cancel_command_data {
|
||||
uint32_t sess;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_cancel_command_send - input msg structure for TEE cancel service
|
||||
*/
|
||||
struct tee_cancel_command_send {
|
||||
struct tee_msg_send header;
|
||||
struct tee_cancel_command_data data;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_close_session_data - input arg structure for TEE close session service
|
||||
*/
|
||||
struct tee_close_session_data {
|
||||
uint32_t sess;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_close_session_send - input arg msg for TEE close session service
|
||||
*/
|
||||
struct tee_close_session_send {
|
||||
struct tee_msg_send header;
|
||||
struct tee_close_session_data data;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_register_rpc_send_data - input arg structure for TEE register rpc service
|
||||
*/
|
||||
struct tee_register_rpc_send_data {
|
||||
uint32_t fnk;
|
||||
uint32_t bf;
|
||||
uint32_t nbr_bf;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_register_rpc_send - input msg structure for TEE register rpc service
|
||||
*/
|
||||
struct tee_register_rpc_send {
|
||||
struct tee_msg_send header;
|
||||
struct tee_register_rpc_send_data data;
|
||||
};
|
||||
|
||||
/*
|
||||
* tee_core_status_out - output arg structure for TEE status service
|
||||
*/
|
||||
#define TEEC_STATUS_MSG_SIZE 80
|
||||
|
||||
struct tee_core_status_out {
|
||||
struct tee_msg_recv header;
|
||||
char raw[TEEC_STATUS_MSG_SIZE];
|
||||
};
|
||||
|
||||
#endif /* __TEE_ARMV7_OP_H__ */
|
||||
64
security/optee_linuxdriver/armtz/tee_tz_priv.h
Normal file
64
security/optee_linuxdriver/armtz/tee_tz_priv.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_TZ_PRIV__
|
||||
#define __TEE_TZ_PRIV__
|
||||
|
||||
struct tee;
|
||||
struct shm_pool;
|
||||
struct tee_rpc_bf;
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
struct smc_param {
|
||||
uint32_t a0;
|
||||
uint32_t a1;
|
||||
uint32_t a2;
|
||||
uint32_t a3;
|
||||
uint32_t a4;
|
||||
uint32_t a5;
|
||||
uint32_t a6;
|
||||
uint32_t a7;
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64
|
||||
struct smc_param {
|
||||
uint64_t a0;
|
||||
uint64_t a1;
|
||||
uint64_t a2;
|
||||
uint64_t a3;
|
||||
uint64_t a4;
|
||||
uint64_t a5;
|
||||
uint64_t a6;
|
||||
uint64_t a7;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct tee_tz {
|
||||
uint32_t sess_id;
|
||||
bool started;
|
||||
struct tee *tee;
|
||||
unsigned long shm_paddr;
|
||||
void *shm_vaddr;
|
||||
struct shm_pool *shm_pool;
|
||||
struct mutex mutex;
|
||||
struct completion c;
|
||||
int c_waiters;
|
||||
void *tz_outer_cache_mutex;
|
||||
struct tee_rpc_bf *rpc_buffers;
|
||||
bool shm_cached;
|
||||
struct tee_mutex_wait_private mutex_wait;
|
||||
struct tee_wait_queue_private wait_queue;
|
||||
};
|
||||
|
||||
int tee_smc_call(struct smc_param *param);
|
||||
|
||||
#endif /* __TEE_TZ_PRIV__ */
|
||||
33
security/optee_linuxdriver/core/Makefile
Normal file
33
security/optee_linuxdriver/core/Makefile
Normal file
@@ -0,0 +1,33 @@
|
||||
CFG_TEE_CORE_CORE_TARGET := armv7
|
||||
|
||||
#########################################################################
|
||||
# Set Internal Variables #
|
||||
# May be modified to match your setup #
|
||||
#########################################################################
|
||||
CFG_TEE_DRV_DEBUGFS?=0
|
||||
CFG_TEE_CORE_LOG_LEVEL?=2
|
||||
CFG_TEE_TA_LOG_LEVEL?=2
|
||||
|
||||
ccflags-y+=-Werror
|
||||
ccflags-y+=-I$(M)/include/linux
|
||||
ccflags-y+=-I$(M)/include
|
||||
|
||||
ccflags-y+=-DCFG_TEE_DRV_DEBUGFS=${CFG_TEE_DRV_DEBUGFS}
|
||||
ccflags-y+=-DCFG_TEE_CORE_LOG_LEVEL=${CFG_TEE_CORE_LOG_LEVEL}
|
||||
ccflags-y+=-DCFG_TEE_TA_LOG_LEVEL=${CFG_TEE_TA_LOG_LEVEL}
|
||||
|
||||
obj-m += optee.o
|
||||
|
||||
optee-objs:= \
|
||||
tee_core.o \
|
||||
tee_context.o \
|
||||
tee_session.o \
|
||||
tee_shm.o \
|
||||
tee_supp_com.o \
|
||||
tee_sysfs.o \
|
||||
tee_debugfs.o \
|
||||
tee_kernel_api.o \
|
||||
tee_mutex_wait.o \
|
||||
tee_wait_queue.o \
|
||||
|
||||
|
||||
317
security/optee_linuxdriver/core/tee_context.c
Normal file
317
security/optee_linuxdriver/core/tee_context.c
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "tee_shm.h"
|
||||
#include "tee_core_priv.h"
|
||||
|
||||
|
||||
/**
|
||||
* tee_context_dump - Dump in a buffer the informations (ctx, sess & shm)
|
||||
* associated to a tee.
|
||||
*/
|
||||
int tee_context_dump(struct tee *tee, char *buff, size_t len)
|
||||
{
|
||||
struct list_head *ptr_ctx, *ptr_sess, *ptr_shm;
|
||||
struct tee_context *ctx;
|
||||
struct tee_session *sess;
|
||||
struct tee_shm *shm;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
int pos = 0;
|
||||
|
||||
BUG_ON(!tee);
|
||||
|
||||
if (len < 80 || list_empty(&tee->list_ctx))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&tee->lock);
|
||||
|
||||
list_for_each(ptr_ctx, &tee->list_ctx) {
|
||||
ctx = list_entry(ptr_ctx, struct tee_context, entry);
|
||||
|
||||
pos += sprintf(buff + pos,
|
||||
"[%02d] ctx=%p (refcount=%d) (usr=%d)",
|
||||
i, ctx,
|
||||
(int)atomic_read(&ctx->refcount.
|
||||
refcount),
|
||||
ctx->usr_client);
|
||||
pos += sprintf(buff + pos, "name=\"%s\" (tgid=%d)\n",
|
||||
ctx->name,
|
||||
ctx->tgid);
|
||||
if ((len - pos) < 80) {
|
||||
pos = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (list_empty(&ctx->list_sess))
|
||||
goto out;
|
||||
|
||||
j = 0;
|
||||
list_for_each(ptr_sess, &ctx->list_sess) {
|
||||
sess = list_entry(ptr_sess,
|
||||
struct tee_session,
|
||||
entry);
|
||||
|
||||
pos += sprintf(buff + pos,
|
||||
"[%02d.%d] sess=%p sessid=%08x\n",
|
||||
i, j, sess,
|
||||
sess->sessid);
|
||||
|
||||
if ((len - pos) < 80) {
|
||||
pos = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
if (list_empty(&ctx->list_shm))
|
||||
goto out;
|
||||
|
||||
j = 0;
|
||||
list_for_each(ptr_shm, &ctx->list_shm) {
|
||||
shm = list_entry(ptr_shm, struct tee_shm, entry);
|
||||
|
||||
pos += sprintf(buff + pos,
|
||||
"[%02d.%d] shm=%p paddr=%p kaddr=%p",
|
||||
i, j, shm,
|
||||
&shm->paddr,
|
||||
shm->kaddr);
|
||||
pos += sprintf(buff + pos,
|
||||
" s=%zu(%zu)\n",
|
||||
shm->size_req,
|
||||
shm->size_alloc);
|
||||
if ((len - pos) < 80) {
|
||||
pos = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&tee->lock);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* tee_context_create - Allocate and create a new context.
|
||||
* Reference on the back-end is requested.
|
||||
*/
|
||||
struct tee_context *tee_context_create(struct tee *tee)
|
||||
{
|
||||
int ret;
|
||||
struct tee_context *ctx;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: >\n", __func__);
|
||||
|
||||
ctx = devm_kzalloc(_DEV(tee), sizeof(struct tee_context), GFP_KERNEL);
|
||||
if (!ctx) {
|
||||
dev_err(_DEV(tee), "%s: tee_context allocation failed\n",
|
||||
__func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
kref_init(&ctx->refcount);
|
||||
INIT_LIST_HEAD(&ctx->list_sess);
|
||||
INIT_LIST_HEAD(&ctx->list_shm);
|
||||
|
||||
ctx->tee = tee;
|
||||
snprintf(ctx->name, sizeof(ctx->name), "%s", current->comm);
|
||||
ctx->tgid = current->tgid;
|
||||
|
||||
ret = tee_get(tee);
|
||||
if (ret) {
|
||||
devm_kfree(_DEV(tee), ctx);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
mutex_lock(&tee->lock);
|
||||
tee_inc_stats(&tee->stats[TEE_STATS_CONTEXT_IDX]);
|
||||
list_add_tail(&ctx->entry, &tee->list_ctx);
|
||||
mutex_unlock(&tee->lock);
|
||||
|
||||
dev_dbg(_DEV(ctx->tee), "%s: < ctx=%p is created\n", __func__, ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* _tee_context_do_release - Final function to release
|
||||
* and free a context.
|
||||
*/
|
||||
static void _tee_context_do_release(struct kref *kref)
|
||||
{
|
||||
struct tee_context *ctx;
|
||||
struct tee *tee;
|
||||
|
||||
ctx = container_of(kref, struct tee_context, refcount);
|
||||
|
||||
BUG_ON(!ctx || !ctx->tee);
|
||||
|
||||
tee = ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > ctx=%p\n", __func__, ctx);
|
||||
|
||||
mutex_lock(&tee->lock);
|
||||
tee_dec_stats(&tee->stats[TEE_STATS_CONTEXT_IDX]);
|
||||
list_del(&ctx->entry);
|
||||
mutex_unlock(&tee->lock);
|
||||
|
||||
devm_kfree(_DEV(tee), ctx);
|
||||
tee_put(tee);
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: < ctx=%p is destroyed\n", __func__, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* tee_context_get - Increase the reference count of
|
||||
* the context.
|
||||
*/
|
||||
void tee_context_get(struct tee_context *ctx)
|
||||
{
|
||||
BUG_ON(!ctx || !ctx->tee);
|
||||
|
||||
kref_get(&ctx->refcount);
|
||||
|
||||
dev_dbg(_DEV(ctx->tee), "%s: ctx=%p, kref=%d\n", __func__,
|
||||
ctx, (int)atomic_read(&ctx->refcount.refcount));
|
||||
}
|
||||
|
||||
static int is_in_list(struct tee *tee, struct list_head *entry)
|
||||
{
|
||||
int present = 1;
|
||||
|
||||
mutex_lock(&tee->lock);
|
||||
if ((entry->next == LIST_POISON1) && (entry->prev == LIST_POISON2))
|
||||
present = 0;
|
||||
mutex_unlock(&tee->lock);
|
||||
return present;
|
||||
}
|
||||
|
||||
/**
|
||||
* tee_context_put - Decreases the reference count of
|
||||
* the context. If 0, the final
|
||||
* release function is called.
|
||||
*/
|
||||
void tee_context_put(struct tee_context *ctx)
|
||||
{
|
||||
struct tee_context *_ctx = ctx;
|
||||
struct tee *tee;
|
||||
|
||||
BUG_ON(!ctx || !ctx->tee);
|
||||
tee = ctx->tee;
|
||||
|
||||
if (!is_in_list(tee, &ctx->entry))
|
||||
return;
|
||||
|
||||
kref_put(&ctx->refcount, _tee_context_do_release);
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: ctx=%p, kref=%d\n", __func__,
|
||||
_ctx, (int)atomic_read(&ctx->refcount.refcount));
|
||||
}
|
||||
|
||||
/**
|
||||
* tee_context_destroy - Request to destroy a context.
|
||||
*/
|
||||
void tee_context_destroy(struct tee_context *ctx)
|
||||
{
|
||||
struct tee *tee;
|
||||
|
||||
if (!ctx || !ctx->tee)
|
||||
return;
|
||||
|
||||
tee = ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: ctx=%p\n", __func__, ctx);
|
||||
|
||||
tee_context_put(ctx);
|
||||
}
|
||||
|
||||
int tee_context_copy_from_client(const struct tee_context *ctx,
|
||||
void *dest, const void *src, size_t size)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (dest && src && (size > 0)) {
|
||||
if (ctx->usr_client)
|
||||
res = copy_from_user(dest, src, size);
|
||||
else
|
||||
memcpy(dest, src, size);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct tee_shm *tee_context_alloc_shm_tmp(struct tee_context *ctx,
|
||||
size_t size, const void *src,
|
||||
int type)
|
||||
{
|
||||
struct tee_shm *shm;
|
||||
|
||||
type &= (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT);
|
||||
|
||||
shm = tee_shm_alloc(ctx->tee, size,
|
||||
TEE_SHM_MAPPED | TEE_SHM_TEMP | type);
|
||||
if (IS_ERR_OR_NULL(shm)) {
|
||||
dev_err(_DEV(ctx->tee), "%s: buffer allocation failed (%ld)\n",
|
||||
__func__, PTR_ERR(shm));
|
||||
return shm;
|
||||
}
|
||||
|
||||
shm->ctx = ctx;
|
||||
|
||||
if (type & TEEC_MEM_INPUT) {
|
||||
if (tee_context_copy_from_client(ctx, shm->kaddr, src, size)) {
|
||||
dev_err(_DEV(ctx->tee),
|
||||
"%s: tee_context_copy_from_client failed\n",
|
||||
__func__);
|
||||
tee_shm_free(shm);
|
||||
shm = NULL;
|
||||
}
|
||||
}
|
||||
return shm;
|
||||
}
|
||||
|
||||
struct tee_shm *tee_context_create_tmpref_buffer(struct tee_context *ctx,
|
||||
size_t size,
|
||||
const void *buffer, int type)
|
||||
{
|
||||
struct tee_shm *shm = NULL;
|
||||
int flags;
|
||||
|
||||
switch (type) {
|
||||
case TEEC_MEMREF_TEMP_OUTPUT:
|
||||
flags = TEEC_MEM_OUTPUT;
|
||||
break;
|
||||
case TEEC_MEMREF_TEMP_INPUT:
|
||||
flags = TEEC_MEM_INPUT;
|
||||
break;
|
||||
case TEEC_MEMREF_TEMP_INOUT:
|
||||
flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
};
|
||||
shm = tee_context_alloc_shm_tmp(ctx, size, buffer, flags);
|
||||
return shm;
|
||||
}
|
||||
549
security/optee_linuxdriver/core/tee_core.c
Normal file
549
security/optee_linuxdriver/core/tee_core.c
Normal file
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
/* #define DEBUG */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm-generic/ioctl.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "linux/tee_core.h"
|
||||
#include "linux/tee_ioc.h"
|
||||
|
||||
#include "tee_core_priv.h"
|
||||
|
||||
#include "tee_sysfs.h"
|
||||
#include "tee_debugfs.h"
|
||||
#include "tee_shm.h"
|
||||
#include "tee_supp_com.h"
|
||||
|
||||
#define _TEE_CORE_FW_VER "1:0.1"
|
||||
|
||||
static char *_tee_supp_app_name = "tee-supplicant";
|
||||
|
||||
/* Store the class misc reference */
|
||||
static struct class *misc_class;
|
||||
|
||||
static int device_match(struct device *device, const void *devname)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
int ret = strncmp(devname, tee->name, sizeof(tee->name));
|
||||
|
||||
BUG_ON(!tee);
|
||||
if (ret == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the kernel api.
|
||||
* Get a reference on a device tee from the device needed
|
||||
*/
|
||||
struct tee *tee_get_tee(const char *devname)
|
||||
{
|
||||
struct device *device;
|
||||
|
||||
if (!devname)
|
||||
return NULL;
|
||||
device = class_find_device(misc_class, NULL, devname, device_match);
|
||||
if (!device) {
|
||||
pr_err("%s:%d - can't find device [%s]\n", __func__, __LINE__,
|
||||
devname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev_get_drvdata(device);
|
||||
}
|
||||
|
||||
void tee_inc_stats(struct tee_stats_entry *entry)
|
||||
{
|
||||
entry->count++;
|
||||
if (entry->count > entry->max)
|
||||
entry->max = entry->count;
|
||||
}
|
||||
|
||||
void tee_dec_stats(struct tee_stats_entry *entry)
|
||||
{
|
||||
entry->count--;
|
||||
}
|
||||
|
||||
/**
|
||||
* tee_get - increases refcount of the tee
|
||||
* @tee: [in] tee to increase refcount of
|
||||
*
|
||||
* @note: If tee.ops.start() callback function is available,
|
||||
* it is called when refcount is equal at 1.
|
||||
*/
|
||||
int tee_get(struct tee *tee)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(!tee);
|
||||
|
||||
if (atomic_inc_return(&tee->refcount) == 1) {
|
||||
BUG_ON(!try_module_get(tee->ops->owner));
|
||||
dev_dbg(_DEV(tee), "%s: refcount=1 call %s::start()...\n",
|
||||
__func__, tee->name);
|
||||
get_device(tee->dev);
|
||||
if (tee->ops->start)
|
||||
ret = tee->ops->start(tee);
|
||||
}
|
||||
if (ret) {
|
||||
put_device(tee->dev);
|
||||
module_put(tee->ops->owner);
|
||||
dev_err(_DEV(tee), "%s: %s::start() failed, err=%d\n",
|
||||
__func__, tee->name, ret);
|
||||
atomic_dec(&tee->refcount);
|
||||
} else {
|
||||
int count = (int)atomic_read(&tee->refcount);
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: refcount=%d\n", __func__, count);
|
||||
if (count > tee->max_refcount)
|
||||
tee->max_refcount = count;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tee_put - decreases refcount of the tee
|
||||
* @tee: [in] tee to reduce refcount of
|
||||
*
|
||||
* @note: If tee.ops.stop() callback function is available,
|
||||
* it is called when refcount is equal at 0.
|
||||
*/
|
||||
int tee_put(struct tee *tee)
|
||||
{
|
||||
int ret = 0;
|
||||
int count;
|
||||
|
||||
BUG_ON(!tee);
|
||||
|
||||
if (atomic_dec_and_test(&tee->refcount)) {
|
||||
dev_dbg(_DEV(tee), "%s: refcount=0 call %s::stop()...\n",
|
||||
__func__, tee->name);
|
||||
if (tee->ops->stop)
|
||||
ret = tee->ops->stop(tee);
|
||||
module_put(tee->ops->owner);
|
||||
put_device(tee->dev);
|
||||
}
|
||||
if (ret) {
|
||||
dev_err(_DEV(tee), "%s: %s::stop() has failed, ret=%d\n",
|
||||
__func__, tee->name, ret);
|
||||
}
|
||||
|
||||
count = (int)atomic_read(&tee->refcount);
|
||||
dev_dbg(_DEV(tee), "%s: refcount=%d\n", __func__, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tee_supp_open(struct tee *tee)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: appclient=\"%s\" pid=%d\n", __func__,
|
||||
current->comm, current->pid);
|
||||
|
||||
BUG_ON(!tee->rpc);
|
||||
|
||||
if (strncmp(_tee_supp_app_name, current->comm,
|
||||
strlen(_tee_supp_app_name)) == 0) {
|
||||
if (atomic_add_return(1, &tee->rpc->used) > 1) {
|
||||
ret = -EBUSY;
|
||||
dev_err(tee->dev, "%s: ERROR Only one Supplicant is allowed\n",
|
||||
__func__);
|
||||
atomic_sub(1, &tee->rpc->used);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tee_supp_release(struct tee *tee)
|
||||
{
|
||||
dev_dbg(_DEV(tee), "%s: appclient=\"%s\" pid=%d\n", __func__,
|
||||
current->comm, current->pid);
|
||||
|
||||
BUG_ON(!tee->rpc);
|
||||
|
||||
if ((atomic_read(&tee->rpc->used) == 1) &&
|
||||
(strncmp(_tee_supp_app_name, current->comm,
|
||||
strlen(_tee_supp_app_name)) == 0))
|
||||
atomic_sub(1, &tee->rpc->used);
|
||||
}
|
||||
|
||||
static int tee_ctx_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct tee_context *ctx;
|
||||
struct tee *tee;
|
||||
int ret;
|
||||
|
||||
tee = container_of(filp->private_data, struct tee, miscdev);
|
||||
|
||||
BUG_ON(!tee);
|
||||
BUG_ON(tee->miscdev.minor != iminor(inode));
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > name=\"%s\"\n", __func__, tee->name);
|
||||
|
||||
ret = tee_supp_open(tee);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctx = tee_context_create(tee);
|
||||
if (IS_ERR_OR_NULL(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
||||
ctx->usr_client = 1;
|
||||
filp->private_data = ctx;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: < ctx=%p is created\n", __func__, (void *)ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tee_ctx_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct tee_context *ctx = filp->private_data;
|
||||
struct tee *tee;
|
||||
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
BUG_ON(!ctx->tee);
|
||||
tee = ctx->tee;
|
||||
BUG_ON(tee->miscdev.minor != iminor(inode));
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > ctx=%p\n", __func__, ctx);
|
||||
|
||||
tee_context_destroy(ctx);
|
||||
tee_supp_release(tee);
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: < ctx=%p is destroyed\n", __func__, ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tee_do_create_session(struct tee_context *ctx,
|
||||
struct tee_cmd_io __user *u_cmd)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee_cmd_io k_cmd;
|
||||
struct tee *tee;
|
||||
|
||||
tee = ctx->tee;
|
||||
BUG_ON(!ctx->usr_client);
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: >\n", __func__);
|
||||
|
||||
if (copy_from_user(&k_cmd, (void *)u_cmd, sizeof(struct tee_cmd_io))) {
|
||||
dev_err(_DEV(tee), "%s: copy_from_user failed\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (k_cmd.fd_sess > 0) {
|
||||
dev_err(_DEV(tee), "%s: invalid fd_sess %d\n", __func__,
|
||||
k_cmd.fd_sess);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((k_cmd.op == NULL) || (k_cmd.uuid == NULL) ||
|
||||
((k_cmd.data != NULL) && (k_cmd.data_size == 0)) ||
|
||||
((k_cmd.data == NULL) && (k_cmd.data_size != 0))) {
|
||||
dev_err(_DEV(tee),
|
||||
"%s: op or/and data parameters are not valid\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = tee_session_create_fd(ctx, &k_cmd);
|
||||
put_user(k_cmd.err, &u_cmd->err);
|
||||
put_user(k_cmd.origin, &u_cmd->origin);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
put_user(k_cmd.fd_sess, &u_cmd->fd_sess);
|
||||
|
||||
exit:
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d, sessfd=%d\n", __func__, ret,
|
||||
k_cmd.fd_sess);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tee_do_shm_alloc(struct tee_context *ctx,
|
||||
struct tee_shm_io __user *u_shm)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee_shm_io k_shm;
|
||||
struct tee *tee = ctx->tee;
|
||||
|
||||
BUG_ON(!ctx->usr_client);
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: >\n", __func__);
|
||||
|
||||
if (copy_from_user(&k_shm, (void *)u_shm, sizeof(struct tee_shm_io))) {
|
||||
dev_err(_DEV(tee), "%s: copy_from_user failed\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((k_shm.buffer != NULL) || (k_shm.fd_shm != 0) ||
|
||||
/*(k_shm.flags & ~(tee->shm_flags)) ||*/
|
||||
((k_shm.flags & tee->shm_flags) == 0) || (k_shm.registered != 0)) {
|
||||
dev_err(_DEV(tee),
|
||||
"%s: shm parameters are not valid %p %d %08x %08x %d\n",
|
||||
__func__, (void *)k_shm.buffer, k_shm.fd_shm,
|
||||
(unsigned int)k_shm.flags, (unsigned int)tee->shm_flags,
|
||||
k_shm.registered);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = tee_shm_alloc_io(ctx, &k_shm);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
put_user(k_shm.fd_shm, &u_shm->fd_shm);
|
||||
put_user(k_shm.flags, &u_shm->flags);
|
||||
|
||||
exit:
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d, shmfd=%d\n", __func__, ret,
|
||||
k_shm.fd_shm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tee_do_get_fd_for_rpc_shm(struct tee_context *ctx,
|
||||
struct tee_shm_io __user *u_shm)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee_shm_io k_shm;
|
||||
struct tee *tee = ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: >\n", __func__);
|
||||
BUG_ON(!ctx->usr_client);
|
||||
|
||||
if (copy_from_user(&k_shm, (void *)u_shm, sizeof(struct tee_shm_io))) {
|
||||
dev_err(_DEV(tee), "%s: copy_from_user failed\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((k_shm.buffer == NULL) || (k_shm.size == 0) || (k_shm.fd_shm != 0)
|
||||
|| (k_shm.flags & ~(tee->shm_flags))
|
||||
|| ((k_shm.flags & tee->shm_flags) == 0)
|
||||
|| (k_shm.registered != 0)) {
|
||||
dev_err(_DEV(tee), "%s: shm parameters are not valid\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = tee_shm_fd_for_rpc(ctx, &k_shm);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
put_user(k_shm.fd_shm, &u_shm->fd_shm);
|
||||
|
||||
exit:
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d, shmfd=%d\n", __func__, ret,
|
||||
k_shm.fd_shm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee_context *ctx = filp->private_data;
|
||||
|
||||
BUG_ON(!ctx);
|
||||
BUG_ON(!ctx->tee);
|
||||
|
||||
dev_dbg(_DEV(ctx->tee), "%s: > cmd nr=%d\n", __func__, _IOC_NR(cmd));
|
||||
|
||||
switch (cmd) {
|
||||
case TEE_OPEN_SESSION_IOC:
|
||||
ret =
|
||||
tee_do_create_session(ctx, (struct tee_cmd_io __user *)arg);
|
||||
break;
|
||||
case TEE_ALLOC_SHM_IOC:
|
||||
ret = tee_do_shm_alloc(ctx, (struct tee_shm_io __user *)arg);
|
||||
break;
|
||||
case TEE_GET_FD_FOR_RPC_SHM_IOC:
|
||||
ret =
|
||||
tee_do_get_fd_for_rpc_shm(ctx,
|
||||
(struct tee_shm_io __user *)arg);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(_DEV(ctx->tee), "%s: < ret=%d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct file_operations tee_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = tee_supp_read,
|
||||
.write = tee_supp_write,
|
||||
.open = tee_ctx_open,
|
||||
.release = tee_ctx_release,
|
||||
.unlocked_ioctl = tee_ioctl
|
||||
};
|
||||
|
||||
static void tee_plt_device_release(struct device *dev)
|
||||
{
|
||||
pr_debug("%s: (dev=%p)....\n", __func__, dev);
|
||||
}
|
||||
|
||||
struct tee *tee_core_alloc(struct device *dev, char *name, int id,
|
||||
const struct tee_ops *ops, size_t len)
|
||||
{
|
||||
struct tee *tee;
|
||||
|
||||
if (!dev || !name || !ops ||
|
||||
!ops->open || !ops->close || !ops->alloc || !ops->free)
|
||||
return NULL;
|
||||
|
||||
tee = devm_kzalloc(dev, sizeof(struct tee) + len, GFP_KERNEL);
|
||||
if (!tee) {
|
||||
dev_err(dev, "%s: kzalloc failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!dev->release)
|
||||
dev->release = tee_plt_device_release;
|
||||
|
||||
tee->dev = dev;
|
||||
tee->id = id;
|
||||
tee->ops = ops;
|
||||
tee->priv = &tee[1];
|
||||
|
||||
snprintf(tee->name, sizeof(tee->name), "optee%s%02d", name, tee->id);
|
||||
pr_info("TEE core: Alloc the misc device \"%s\" (id=%d)\n", tee->name,
|
||||
tee->id);
|
||||
|
||||
tee->miscdev.parent = dev;
|
||||
tee->miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
tee->miscdev.name = tee->name;
|
||||
tee->miscdev.fops = &tee_fops;
|
||||
|
||||
mutex_init(&tee->lock);
|
||||
atomic_set(&tee->refcount, 0);
|
||||
INIT_LIST_HEAD(&tee->list_ctx);
|
||||
INIT_LIST_HEAD(&tee->list_rpc_shm);
|
||||
|
||||
tee->state = TEE_OFFLINE;
|
||||
tee->shm_flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
|
||||
tee->test = 0;
|
||||
|
||||
tee_supp_init(tee);
|
||||
|
||||
return tee;
|
||||
}
|
||||
EXPORT_SYMBOL(tee_core_alloc);
|
||||
|
||||
int tee_core_free(struct tee *tee)
|
||||
{
|
||||
if (tee) {
|
||||
tee_supp_deinit(tee);
|
||||
devm_kfree(tee->dev, tee);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tee_core_free);
|
||||
|
||||
int tee_core_add(struct tee *tee)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!tee)
|
||||
return -EINVAL;
|
||||
|
||||
rc = misc_register(&tee->miscdev);
|
||||
if (rc != 0) {
|
||||
pr_err("TEE Core: misc_register() failed name=\"%s\"\n",
|
||||
tee->name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
dev_set_drvdata(tee->miscdev.this_device, tee);
|
||||
|
||||
tee_init_sysfs(tee);
|
||||
tee_create_debug_dir(tee);
|
||||
|
||||
/* Register a static reference on the class misc
|
||||
* to allow finding device by class */
|
||||
BUG_ON(!tee->miscdev.this_device->class);
|
||||
if (misc_class)
|
||||
BUG_ON(misc_class != tee->miscdev.this_device->class);
|
||||
else
|
||||
misc_class = tee->miscdev.this_device->class;
|
||||
|
||||
pr_info("TEE Core: Register the misc device \"%s\" (id=%d,minor=%d)\n",
|
||||
dev_name(tee->miscdev.this_device), tee->id,
|
||||
tee->miscdev.minor);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(tee_core_add);
|
||||
|
||||
int tee_core_del(struct tee *tee)
|
||||
{
|
||||
if (tee) {
|
||||
pr_info("TEE Core: Destroy the misc device \"%s\" (id=%d)\n",
|
||||
dev_name(tee->miscdev.this_device), tee->id);
|
||||
|
||||
tee_cleanup_sysfs(tee);
|
||||
tee_delete_debug_dir(tee);
|
||||
|
||||
if (tee->miscdev.minor != MISC_DYNAMIC_MINOR) {
|
||||
pr_info("TEE Core: Deregister the misc device \"%s\" (id=%d)\n",
|
||||
dev_name(tee->miscdev.this_device), tee->id);
|
||||
misc_deregister(&tee->miscdev);
|
||||
}
|
||||
}
|
||||
|
||||
tee_core_free(tee);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tee_core_del);
|
||||
|
||||
static int __init tee_core_init(void)
|
||||
{
|
||||
pr_info("\nTEE Core Framework initialization (ver %s)\n",
|
||||
_TEE_CORE_FW_VER);
|
||||
tee_init_debugfs();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit tee_core_exit(void)
|
||||
{
|
||||
tee_exit_debugfs();
|
||||
pr_info("TEE Core Framework unregistered\n");
|
||||
}
|
||||
|
||||
module_init(tee_core_init);
|
||||
module_exit(tee_core_exit);
|
||||
|
||||
MODULE_AUTHOR("STMicroelectronics");
|
||||
MODULE_DESCRIPTION("STM Secure TEE Framework/Core TEEC v1.0");
|
||||
MODULE_SUPPORTED_DEVICE("");
|
||||
MODULE_VERSION(_TEE_CORE_FW_VER);
|
||||
MODULE_LICENSE("GPL");
|
||||
52
security/optee_linuxdriver/core/tee_core_priv.h
Normal file
52
security/optee_linuxdriver/core/tee_core_priv.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_CORE_PRIV_H__
|
||||
#define __TEE_CORE_PRIV_H__
|
||||
|
||||
#include "linux/tee_core.h"
|
||||
#include "linux/tee_ioc.h"
|
||||
|
||||
/* from tee_core_module.c */
|
||||
int tee_get(struct tee *tee);
|
||||
int tee_put(struct tee *tee);
|
||||
|
||||
void tee_inc_stats(struct tee_stats_entry *entry);
|
||||
void tee_dec_stats(struct tee_stats_entry *entry);
|
||||
|
||||
/* from tee_context.c */
|
||||
int tee_context_dump(struct tee *tee, char *buff, size_t len);
|
||||
|
||||
struct tee_context *tee_context_create(struct tee *tee);
|
||||
void tee_context_destroy(struct tee_context *ctx);
|
||||
|
||||
void tee_context_get(struct tee_context *ctx);
|
||||
void tee_context_put(struct tee_context *ctx);
|
||||
|
||||
struct tee_shm *tee_context_create_tmpref_buffer(struct tee_context *ctx,
|
||||
size_t size,
|
||||
const void *buffer, int type);
|
||||
struct tee_shm *tee_context_alloc_shm_tmp(struct tee_context *ctx, size_t size,
|
||||
const void *data, int type);
|
||||
int tee_context_copy_from_client(const struct tee_context *ctx, void *dest,
|
||||
const void *src, size_t size);
|
||||
|
||||
/* from tee_session.c */
|
||||
int tee_session_create_fd(struct tee_context *ctx, struct tee_cmd_io *cmd_io);
|
||||
struct tee_session *tee_session_create_and_open(struct tee_context *ctx,
|
||||
struct tee_cmd_io *cmd_io);
|
||||
int tee_session_close_and_destroy(struct tee_session *sess);
|
||||
|
||||
struct tee *tee_get_tee(const char *devname);
|
||||
int tee_session_invoke_be(struct tee_session *sess, struct tee_cmd_io *cmd_io);
|
||||
|
||||
#endif
|
||||
85
security/optee_linuxdriver/core/tee_debugfs.c
Normal file
85
security/optee_linuxdriver/core/tee_debugfs.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/kernel.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "linux/tee_core.h"
|
||||
#include "tee_debugfs.h"
|
||||
|
||||
static struct dentry *tee_debugfs_dir;
|
||||
|
||||
static ssize_t tee_trace_read(struct file *filp, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct tee *tee = filp->private_data;
|
||||
|
||||
char buff[258];
|
||||
int len = sprintf(buff, "device=%s\n NO LOG AVAILABLE\n", tee->name);
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buff, len);
|
||||
}
|
||||
|
||||
static const struct file_operations log_tee_ops = {
|
||||
.read = tee_trace_read,
|
||||
.open = simple_open,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
void tee_create_debug_dir(struct tee *tee)
|
||||
{
|
||||
struct dentry *entry;
|
||||
struct device *dev = tee->miscdev.this_device;
|
||||
|
||||
if (!tee_debugfs_dir)
|
||||
return;
|
||||
|
||||
tee->dbg_dir = debugfs_create_dir(dev_name(dev), tee_debugfs_dir);
|
||||
if (!tee->dbg_dir)
|
||||
goto error_create_file;
|
||||
|
||||
entry = debugfs_create_file("log", S_IRUGO, tee->dbg_dir,
|
||||
tee, &log_tee_ops);
|
||||
if (!entry)
|
||||
goto error_create_file;
|
||||
|
||||
return;
|
||||
|
||||
error_create_file:
|
||||
dev_err(dev, "can't create debugfs file\n");
|
||||
tee_delete_debug_dir(tee);
|
||||
}
|
||||
|
||||
void tee_delete_debug_dir(struct tee *tee)
|
||||
{
|
||||
if (!tee || !tee->dbg_dir)
|
||||
return;
|
||||
|
||||
debugfs_remove_recursive(tee->dbg_dir);
|
||||
}
|
||||
|
||||
void __init tee_init_debugfs(void)
|
||||
{
|
||||
if (debugfs_initialized()) {
|
||||
tee_debugfs_dir = debugfs_create_dir("tee", NULL);
|
||||
if (IS_ERR(tee_debugfs_dir))
|
||||
pr_err("can't create debugfs dir\n");
|
||||
}
|
||||
}
|
||||
|
||||
void __exit tee_exit_debugfs(void)
|
||||
{
|
||||
if (tee_debugfs_dir)
|
||||
debugfs_remove(tee_debugfs_dir);
|
||||
}
|
||||
24
security/optee_linuxdriver/core/tee_debugfs.h
Normal file
24
security/optee_linuxdriver/core/tee_debugfs.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_DEBUGFS_H__
|
||||
#define __TEE_DEBUGFS_H__
|
||||
|
||||
struct tee;
|
||||
|
||||
void tee_create_debug_dir(struct tee *tee);
|
||||
void tee_delete_debug_dir(struct tee *tee);
|
||||
|
||||
void __init tee_init_debugfs(void);
|
||||
void __exit tee_exit_debugfs(void);
|
||||
|
||||
#endif /* __TEE_DEBUGFS_H__ */
|
||||
255
security/optee_linuxdriver/core/tee_kernel_api.c
Normal file
255
security/optee_linuxdriver/core/tee_kernel_api.c
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "linux/tee_kernel_api.h"
|
||||
#include "linux/tee_core.h"
|
||||
#include "linux/tee_ioc.h"
|
||||
|
||||
#include "tee_core_priv.h"
|
||||
#include "tee_shm.h"
|
||||
#include "tee_supp_com.h"
|
||||
|
||||
#define TEE_TZ_DEVICE_NAME "opteearmtz00"
|
||||
|
||||
static void reset_tee_cmd(struct tee_cmd_io *cmd)
|
||||
{
|
||||
cmd->fd_sess = -1;
|
||||
cmd->cmd = 0;
|
||||
cmd->uuid = NULL;
|
||||
cmd->origin = TEEC_ORIGIN_API;
|
||||
cmd->err = TEEC_SUCCESS;
|
||||
cmd->data = NULL;
|
||||
cmd->data_size = 0;
|
||||
cmd->op = NULL;
|
||||
}
|
||||
|
||||
TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context)
|
||||
{
|
||||
struct tee *tee;
|
||||
struct tee_context *ctx;
|
||||
pr_cont("%s: > name=\"%s\"\n", __func__, name);
|
||||
|
||||
if (!context)
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
|
||||
context->fd = 0;
|
||||
|
||||
if (name == NULL)
|
||||
strncpy(context->devname, TEE_TZ_DEVICE_NAME,
|
||||
sizeof(context->devname));
|
||||
else
|
||||
strncpy(context->devname, name, sizeof(context->devname));
|
||||
|
||||
tee = tee_get_tee(context->devname);
|
||||
if (!tee) {
|
||||
pr_err("%s - can't get device [%s]\n", __func__, name);
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
ctx = tee_context_create(tee);
|
||||
if (IS_ERR_OR_NULL(ctx))
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
|
||||
ctx->usr_client = 0;
|
||||
|
||||
/* TODO fixme will not work on 64-bit platform */
|
||||
context->fd = (int)(uintptr_t)ctx;
|
||||
BUG_ON(ctx != (struct tee_context *)(uintptr_t)context->fd);
|
||||
|
||||
pr_cont("%s: < ctx=%p is created\n", __func__, (void *)ctx);
|
||||
return TEEC_SUCCESS;
|
||||
}
|
||||
EXPORT_SYMBOL(TEEC_InitializeContext);
|
||||
|
||||
void TEEC_FinalizeContext(TEEC_Context *context)
|
||||
{
|
||||
if (!context || !context->fd) {
|
||||
pr_err("%s - can't release context %p:[%s]\n", __func__,
|
||||
context, (context
|
||||
&& context->devname) ? context->devname : "");
|
||||
return;
|
||||
}
|
||||
/* TODO fixme will not work on 64-bit platform */
|
||||
tee_context_destroy((struct tee_context *)(uintptr_t)context->fd);
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(TEEC_FinalizeContext);
|
||||
|
||||
TEEC_Result TEEC_OpenSession(TEEC_Context *context,
|
||||
TEEC_Session *session,
|
||||
const TEEC_UUID *destination,
|
||||
uint32_t connectionMethod,
|
||||
const void *connectionData,
|
||||
TEEC_Operation *operation,
|
||||
uint32_t *return_origin)
|
||||
{
|
||||
TEEC_Operation dummy_op;
|
||||
struct tee_cmd_io cmd;
|
||||
struct tee_session *sess;
|
||||
struct tee_context *ctx;
|
||||
|
||||
if (!operation) {
|
||||
/*
|
||||
* The code here exist because Global Platform API states that
|
||||
* it is allowed to give operation as a NULL pointer.
|
||||
* In kernel and secure world we in most cases don't want
|
||||
* this to be NULL, hence we use this dummy operation when
|
||||
* a client doesn't provide any operation.
|
||||
*/
|
||||
memset(&dummy_op, 0, sizeof(TEEC_Operation));
|
||||
operation = &dummy_op;
|
||||
}
|
||||
|
||||
if (!context || !session || !destination || !operation
|
||||
|| !return_origin)
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
|
||||
session->fd = 0;
|
||||
|
||||
/* TODO fixme will not work on 64-bit platform */
|
||||
ctx = (struct tee_context *)(uintptr_t)context->fd;
|
||||
reset_tee_cmd(&cmd);
|
||||
cmd.op = operation;
|
||||
cmd.uuid = (TEEC_UUID *) destination;
|
||||
|
||||
sess = tee_session_create_and_open(ctx, &cmd);
|
||||
if (IS_ERR_OR_NULL(sess)) {
|
||||
if (cmd.origin)
|
||||
*return_origin = cmd.origin;
|
||||
else
|
||||
*return_origin = TEEC_ORIGIN_COMMS;
|
||||
if (cmd.err)
|
||||
return cmd.err;
|
||||
else
|
||||
return TEEC_ERROR_COMMUNICATION;
|
||||
} else {
|
||||
*return_origin = cmd.origin;
|
||||
/* TODO fixme will not work on 64-bit platform */
|
||||
session->fd = (int)(uintptr_t)sess;
|
||||
BUG_ON(sess != (struct tee_session *)(uintptr_t)session->fd);
|
||||
return cmd.err;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(TEEC_OpenSession);
|
||||
|
||||
void TEEC_CloseSession(TEEC_Session *session)
|
||||
{
|
||||
if (session && session->fd) {
|
||||
/* TODO fixme will not work on 64-bit platform */
|
||||
struct tee_session *sess =
|
||||
(struct tee_session *)(uintptr_t)session->fd;
|
||||
tee_session_close_and_destroy(sess);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(TEEC_CloseSession);
|
||||
|
||||
TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
|
||||
uint32_t commandID,
|
||||
TEEC_Operation *operation,
|
||||
uint32_t *return_origin)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tee_cmd_io cmd;
|
||||
struct tee_session *sess;
|
||||
|
||||
if (!session || !operation || !return_origin || !session->fd)
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
|
||||
/* TODO fixme will not work on 64-bit platform */
|
||||
sess = (struct tee_session *)(uintptr_t)session->fd;
|
||||
reset_tee_cmd(&cmd);
|
||||
cmd.cmd = commandID;
|
||||
cmd.op = operation;
|
||||
|
||||
ret = tee_session_invoke_be(sess, &cmd);
|
||||
if (ret) {
|
||||
if (cmd.origin)
|
||||
*return_origin = cmd.origin;
|
||||
else
|
||||
*return_origin = TEEC_ORIGIN_COMMS;
|
||||
if (cmd.err)
|
||||
return cmd.err;
|
||||
else
|
||||
return TEEC_ERROR_COMMUNICATION;
|
||||
} else {
|
||||
*return_origin = cmd.origin;
|
||||
return cmd.err;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(TEEC_InvokeCommand);
|
||||
|
||||
TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
|
||||
TEEC_SharedMemory *sharedMem)
|
||||
{
|
||||
if (!sharedMem)
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
|
||||
sharedMem->registered = 1;
|
||||
return TEEC_SUCCESS;
|
||||
}
|
||||
EXPORT_SYMBOL(TEEC_RegisterSharedMemory);
|
||||
|
||||
TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
|
||||
TEEC_SharedMemory *shared_memory)
|
||||
{
|
||||
struct tee_shm_io shm_io;
|
||||
int ret;
|
||||
struct tee_shm *shm;
|
||||
|
||||
if (!context || !context->ctx || !shared_memory)
|
||||
return TEEC_ERROR_BAD_PARAMETERS;
|
||||
|
||||
shm_io.size = shared_memory->size;
|
||||
shm_io.flags = shared_memory->flags | TEEC_MEM_KAPI;
|
||||
ret = tee_shm_alloc_io(context->ctx, &shm_io);
|
||||
if (ret) {
|
||||
pr_err("%s: tee_shm_alloc_io(%zd) failed\n", __func__,
|
||||
shared_memory->size);
|
||||
return TEEC_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
shared_memory->registered = 0;
|
||||
shared_memory->flags = shm_io.flags;
|
||||
shared_memory->d.fd = shm_io.fd_shm;
|
||||
|
||||
shm = (struct tee_shm *)(long)shm_io.fd_shm;
|
||||
shared_memory->buffer = shm->kaddr;
|
||||
|
||||
pr_debug("%s(%zd) => fd=%d, kaddr=%p\n", __func__,
|
||||
shm_io.size, shm_io.fd_shm, (void *)shared_memory->buffer);
|
||||
|
||||
return TEEC_SUCCESS;
|
||||
}
|
||||
EXPORT_SYMBOL(TEEC_AllocateSharedMemory);
|
||||
|
||||
void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *shared_memory)
|
||||
{
|
||||
struct tee_shm *shm;
|
||||
|
||||
if (!shared_memory || shared_memory->registered)
|
||||
return;
|
||||
|
||||
pr_debug("%s (vaddr = %p)\n", __func__, shared_memory->buffer);
|
||||
|
||||
shm = (struct tee_shm *)(long)shared_memory->d.fd;
|
||||
tee_shm_free_io(shm);
|
||||
|
||||
shared_memory->buffer = NULL;
|
||||
shared_memory->d.fd = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(TEEC_ReleaseSharedMemory);
|
||||
144
security/optee_linuxdriver/core/tee_mutex_wait.c
Normal file
144
security/optee_linuxdriver/core/tee_mutex_wait.c
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/slab.h>
|
||||
#include "tee_mutex_wait.h"
|
||||
|
||||
struct tee_mutex_wait {
|
||||
struct list_head link;
|
||||
struct completion comp;
|
||||
struct mutex mu;
|
||||
u32 wait_after;
|
||||
u32 key;
|
||||
};
|
||||
|
||||
/*
|
||||
* Compares two serial numbers using Serial Number Arithmetic
|
||||
* (https://www.ietf.org/rfc/rfc1982.txt).
|
||||
*/
|
||||
#define TICK_GT(t1, t2) \
|
||||
(((t1) < (t2) && (t2) - (t1) > 0xFFFFFFFFu) || \
|
||||
((t1) > (t2) && (t1) - (t2) < 0xFFFFFFFFu))
|
||||
|
||||
static struct tee_mutex_wait *tee_mutex_wait_get(struct device *dev,
|
||||
struct tee_mutex_wait_private *priv, u32 key)
|
||||
{
|
||||
struct tee_mutex_wait *w;
|
||||
|
||||
mutex_lock(&priv->mu);
|
||||
|
||||
list_for_each_entry(w, &priv->db, link)
|
||||
if (w->key == key)
|
||||
goto out;
|
||||
|
||||
w = kmalloc(sizeof(struct tee_mutex_wait), GFP_KERNEL);
|
||||
if (!w) {
|
||||
dev_err(dev, "kmalloc <struct tee_mutex_wait> failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
init_completion(&w->comp);
|
||||
mutex_init(&w->mu);
|
||||
w->wait_after = 0;
|
||||
w->key = key;
|
||||
list_add_tail(&w->link, &priv->db);
|
||||
out:
|
||||
mutex_unlock(&priv->mu);
|
||||
return w;
|
||||
}
|
||||
|
||||
static void tee_mutex_wait_delete_entry(struct tee_mutex_wait *w)
|
||||
{
|
||||
list_del(&w->link);
|
||||
mutex_destroy(&w->mu);
|
||||
kfree(w);
|
||||
}
|
||||
|
||||
void tee_mutex_wait_delete(struct device *dev,
|
||||
struct tee_mutex_wait_private *priv,
|
||||
u32 key)
|
||||
{
|
||||
struct tee_mutex_wait *w;
|
||||
|
||||
mutex_lock(&priv->mu);
|
||||
|
||||
list_for_each_entry(w, &priv->db, link) {
|
||||
if (w->key == key) {
|
||||
tee_mutex_wait_delete_entry(w);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->mu);
|
||||
}
|
||||
EXPORT_SYMBOL(tee_mutex_wait_delete);
|
||||
|
||||
void tee_mutex_wait_wakeup(struct device *dev,
|
||||
struct tee_mutex_wait_private *priv,
|
||||
u32 key, u32 wait_after)
|
||||
{
|
||||
struct tee_mutex_wait *w = tee_mutex_wait_get(dev, priv, key);
|
||||
|
||||
if (!w)
|
||||
return;
|
||||
|
||||
mutex_lock(&w->mu);
|
||||
w->wait_after = wait_after;
|
||||
mutex_unlock(&w->mu);
|
||||
complete(&w->comp);
|
||||
}
|
||||
EXPORT_SYMBOL(tee_mutex_wait_wakeup);
|
||||
|
||||
void tee_mutex_wait_sleep(struct device *dev,
|
||||
struct tee_mutex_wait_private *priv,
|
||||
u32 key, u32 wait_tick)
|
||||
{
|
||||
struct tee_mutex_wait *w = tee_mutex_wait_get(dev, priv, key);
|
||||
u32 wait_after;
|
||||
|
||||
if (!w)
|
||||
return;
|
||||
|
||||
mutex_lock(&w->mu);
|
||||
wait_after = w->wait_after;
|
||||
mutex_unlock(&w->mu);
|
||||
|
||||
if (TICK_GT(wait_tick, wait_after))
|
||||
wait_for_completion_timeout(&w->comp, HZ);
|
||||
}
|
||||
EXPORT_SYMBOL(tee_mutex_wait_sleep);
|
||||
|
||||
int tee_mutex_wait_init(struct tee_mutex_wait_private *priv)
|
||||
{
|
||||
mutex_init(&priv->mu);
|
||||
INIT_LIST_HEAD(&priv->db);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(tee_mutex_wait_init);
|
||||
|
||||
void tee_mutex_wait_exit(struct tee_mutex_wait_private *priv)
|
||||
{
|
||||
/*
|
||||
* It's the callers responibility to ensure that no one is using
|
||||
* anything inside priv.
|
||||
*/
|
||||
|
||||
mutex_destroy(&priv->mu);
|
||||
while (!list_empty(&priv->db)) {
|
||||
struct tee_mutex_wait *w =
|
||||
list_first_entry(&priv->db,
|
||||
struct tee_mutex_wait,
|
||||
link);
|
||||
tee_mutex_wait_delete_entry(w);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(tee_mutex_wait_exit);
|
||||
38
security/optee_linuxdriver/core/tee_mutex_wait.h
Normal file
38
security/optee_linuxdriver/core/tee_mutex_wait.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_MUTEX_WAIT_H
|
||||
#define TEE_MUTEX_WAIT_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
struct tee_mutex_wait_private {
|
||||
struct mutex mu;
|
||||
struct list_head db;
|
||||
};
|
||||
|
||||
int tee_mutex_wait_init(struct tee_mutex_wait_private *priv);
|
||||
void tee_mutex_wait_exit(struct tee_mutex_wait_private *priv);
|
||||
|
||||
void tee_mutex_wait_delete(struct device *dev,
|
||||
struct tee_mutex_wait_private *priv,
|
||||
u32 key);
|
||||
void tee_mutex_wait_wakeup(struct device *dev,
|
||||
struct tee_mutex_wait_private *priv,
|
||||
u32 key, u32 wait_after);
|
||||
void tee_mutex_wait_sleep(struct device *dev,
|
||||
struct tee_mutex_wait_private *priv,
|
||||
u32 key, u32 wait_tick);
|
||||
|
||||
#endif /*TEE_MUTEX_WAIT_H*/
|
||||
852
security/optee_linuxdriver/core/tee_session.c
Normal file
852
security/optee_linuxdriver/core/tee_session.c
Normal file
@@ -0,0 +1,852 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
|
||||
#include "tee_shm.h"
|
||||
#include "tee_core_priv.h"
|
||||
|
||||
static int _init_tee_cmd(struct tee_session *sess, struct tee_cmd_io *cmd_io,
|
||||
struct tee_cmd *cmd);
|
||||
static void _update_client_tee_cmd(struct tee_session *sess,
|
||||
struct tee_cmd_io *cmd_io,
|
||||
struct tee_cmd *cmd);
|
||||
static void _release_tee_cmd(struct tee_session *sess, struct tee_cmd *cmd);
|
||||
|
||||
#define _DEV_TEE _DEV(sess->ctx->tee)
|
||||
|
||||
#define INMSG dev_dbg(_DEV_TEE, "%s: >\n", __func__)
|
||||
#define OUTMSG(val) dev_dbg(_DEV_TEE, "%s: < %d\n", __func__, (int)val)
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static inline bool flag_set(int val, int flags)
|
||||
{
|
||||
return (val & flags) == flags;
|
||||
}
|
||||
|
||||
static inline bool is_mapped_temp(int flags)
|
||||
{
|
||||
return flag_set(flags, TEE_SHM_MAPPED | TEE_SHM_TEMP);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#define _UUID_STR_SIZE 35
|
||||
static char *_uuid_to_str(const TEEC_UUID *uuid)
|
||||
{
|
||||
static char uuid_str[_UUID_STR_SIZE];
|
||||
|
||||
if (uuid) {
|
||||
sprintf(uuid_str,
|
||||
"%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
|
||||
uuid->clockSeqAndNode[0], uuid->clockSeqAndNode[1],
|
||||
uuid->clockSeqAndNode[2], uuid->clockSeqAndNode[3],
|
||||
uuid->clockSeqAndNode[4], uuid->clockSeqAndNode[5],
|
||||
uuid->clockSeqAndNode[6], uuid->clockSeqAndNode[7]);
|
||||
} else {
|
||||
sprintf(uuid_str, "NULL");
|
||||
}
|
||||
|
||||
return uuid_str;
|
||||
}
|
||||
|
||||
static int tee_copy_from_user(struct tee_context *ctx, void *to, void *from,
|
||||
size_t size)
|
||||
{
|
||||
if ((!to) || (!from) || (!size))
|
||||
return 0;
|
||||
if (ctx->usr_client)
|
||||
return copy_from_user(to, from, size);
|
||||
else {
|
||||
memcpy(to, from, size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int tee_copy_to_user(struct tee_context *ctx, void *to, void *from,
|
||||
size_t size)
|
||||
{
|
||||
if ((!to) || (!from) || (!size))
|
||||
return 0;
|
||||
if (ctx->usr_client)
|
||||
return copy_to_user(to, from, size);
|
||||
else {
|
||||
memcpy(to, from, size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Defined as macro to let the put_user macro see the types */
|
||||
#define tee_put_user(ctx, from, to) \
|
||||
do { \
|
||||
if ((ctx)->usr_client) \
|
||||
put_user(from, to); \
|
||||
else \
|
||||
*to = from; \
|
||||
} while (0)
|
||||
|
||||
static inline int tee_session_is_opened(struct tee_session *sess)
|
||||
{
|
||||
if (sess && sess->sessid)
|
||||
return (sess->sessid != 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tee_session_open_be(struct tee_session *sess,
|
||||
struct tee_cmd_io *cmd_io)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee *tee;
|
||||
struct tee_cmd cmd;
|
||||
|
||||
BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
|
||||
|
||||
tee = sess->ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > open a new session", __func__);
|
||||
|
||||
sess->sessid = 0;
|
||||
ret = _init_tee_cmd(sess, cmd_io, &cmd);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (cmd.uuid) {
|
||||
dev_dbg(_DEV(tee), "%s: UUID=%s\n", __func__,
|
||||
_uuid_to_str((TEEC_UUID *) cmd.uuid->kaddr));
|
||||
}
|
||||
|
||||
ret = tee->ops->open(sess, &cmd);
|
||||
if (ret == 0)
|
||||
_update_client_tee_cmd(sess, cmd_io, &cmd);
|
||||
else {
|
||||
/* propagate the reason of the error */
|
||||
cmd_io->origin = cmd.origin;
|
||||
cmd_io->err = cmd.err;
|
||||
}
|
||||
|
||||
out:
|
||||
_release_tee_cmd(sess, &cmd);
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d, sessid=%08x", __func__, ret,
|
||||
sess->sessid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tee_session_invoke_be(struct tee_session *sess, struct tee_cmd_io *cmd_io)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee *tee;
|
||||
struct tee_cmd cmd;
|
||||
|
||||
BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
|
||||
|
||||
tee = sess->ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > sessid=%08x, cmd=0x%08x\n", __func__,
|
||||
sess->sessid, cmd_io->cmd);
|
||||
|
||||
ret = _init_tee_cmd(sess, cmd_io, &cmd);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = tee->ops->invoke(sess, &cmd);
|
||||
if (!ret)
|
||||
_update_client_tee_cmd(sess, cmd_io, &cmd);
|
||||
else {
|
||||
/* propagate the reason of the error */
|
||||
cmd_io->origin = cmd.origin;
|
||||
cmd_io->err = cmd.err;
|
||||
}
|
||||
|
||||
out:
|
||||
_release_tee_cmd(sess, &cmd);
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tee_session_close_be(struct tee_session *sess)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee *tee;
|
||||
|
||||
BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
|
||||
|
||||
tee = sess->ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > sessid=%08x", __func__, sess->sessid);
|
||||
|
||||
ret = tee->ops->close(sess);
|
||||
sess->sessid = 0;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tee_session_cancel_be(struct tee_session *sess,
|
||||
struct tee_cmd_io *cmd_io)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee *tee;
|
||||
struct tee_cmd cmd;
|
||||
|
||||
BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
|
||||
|
||||
tee = sess->ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > sessid=%08x, cmd=0x%08x\n", __func__,
|
||||
sess->sessid, cmd_io->cmd);
|
||||
|
||||
ret = _init_tee_cmd(sess, cmd_io, &cmd);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = tee->ops->cancel(sess, &cmd);
|
||||
|
||||
out:
|
||||
_release_tee_cmd(sess, &cmd);
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tee_do_invoke_command(struct tee_session *sess,
|
||||
struct tee_cmd_io __user *u_cmd)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee *tee;
|
||||
struct tee_cmd_io k_cmd;
|
||||
struct tee_context *ctx;
|
||||
|
||||
BUG_ON(!sess->ctx);
|
||||
BUG_ON(!sess->ctx->tee);
|
||||
ctx = sess->ctx;
|
||||
tee = sess->ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > sessid=%08x\n", __func__, sess->sessid);
|
||||
|
||||
BUG_ON(!sess->sessid);
|
||||
|
||||
if (tee_copy_from_user
|
||||
(ctx, &k_cmd, (void *)u_cmd, sizeof(struct tee_cmd_io))) {
|
||||
dev_err(_DEV(tee), "%s: tee_copy_from_user failed\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((k_cmd.op == NULL) || (k_cmd.uuid != NULL) ||
|
||||
(k_cmd.data != NULL) || (k_cmd.data_size != 0)) {
|
||||
dev_err(_DEV(tee),
|
||||
"%s: op or/and data parameters are not valid\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = tee_session_invoke_be(sess, &k_cmd);
|
||||
if (ret)
|
||||
dev_err(_DEV(tee), "%s: tee_invoke_command failed\n", __func__);
|
||||
|
||||
tee_put_user(ctx, k_cmd.err, &u_cmd->err);
|
||||
tee_put_user(ctx, k_cmd.origin, &u_cmd->origin);
|
||||
|
||||
exit:
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tee_do_cancel_cmd(struct tee_session *sess,
|
||||
struct tee_cmd_io __user *u_cmd)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct tee *tee;
|
||||
struct tee_cmd_io k_cmd;
|
||||
struct tee_context *ctx;
|
||||
|
||||
BUG_ON(!sess->ctx);
|
||||
BUG_ON(!sess->ctx->tee);
|
||||
ctx = sess->ctx;
|
||||
tee = sess->ctx->tee;
|
||||
|
||||
dev_dbg(sess->ctx->tee->dev, "%s: > sessid=%08x\n", __func__,
|
||||
sess->sessid);
|
||||
|
||||
BUG_ON(!sess->sessid);
|
||||
|
||||
if (tee_copy_from_user
|
||||
(ctx, &k_cmd, (void *)u_cmd, sizeof(struct tee_cmd_io))) {
|
||||
dev_err(_DEV(tee), "%s: tee_copy_from_user failed\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((k_cmd.op == NULL) || (k_cmd.uuid != NULL) ||
|
||||
(k_cmd.data != NULL) || (k_cmd.data_size != 0)) {
|
||||
dev_err(_DEV(tee),
|
||||
"%s: op or/and data parameters are not valid\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = tee_session_cancel_be(sess, &k_cmd);
|
||||
if (ret)
|
||||
dev_err(_DEV(tee), "%s: tee_invoke_command failed\n", __func__);
|
||||
|
||||
tee_put_user(ctx, k_cmd.err, &u_cmd->err);
|
||||
tee_put_user(ctx, k_cmd.origin, &u_cmd->origin);
|
||||
|
||||
exit:
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long tee_session_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct tee *tee;
|
||||
struct tee_session *sess = filp->private_data;
|
||||
int ret;
|
||||
|
||||
BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
|
||||
|
||||
tee = sess->ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > cmd nr=%d\n", __func__, _IOC_NR(cmd));
|
||||
|
||||
switch (cmd) {
|
||||
case TEE_INVOKE_COMMAND_IOC:
|
||||
ret =
|
||||
tee_do_invoke_command(sess,
|
||||
(struct tee_cmd_io __user *)arg);
|
||||
break;
|
||||
case TEE_REQUEST_CANCELLATION_IOC:
|
||||
ret = tee_do_cancel_cmd(sess, (struct tee_cmd_io __user *)arg);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tee_session_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct tee_session *sess = filp->private_data;
|
||||
int ret = 0;
|
||||
struct tee *tee;
|
||||
|
||||
BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
|
||||
tee = sess->ctx->tee;
|
||||
|
||||
ret = tee_session_close_and_destroy(sess);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct file_operations tee_session_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = tee_session_ioctl,
|
||||
.release = tee_session_release,
|
||||
};
|
||||
|
||||
int tee_session_close_and_destroy(struct tee_session *sess)
|
||||
{
|
||||
int ret;
|
||||
struct tee *tee;
|
||||
struct tee_context *ctx;
|
||||
|
||||
if (!sess || !sess->ctx || !sess->ctx->tee)
|
||||
return -EINVAL;
|
||||
|
||||
ctx = sess->ctx;
|
||||
tee = ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > sess=%p\n", __func__, sess);
|
||||
|
||||
if (!tee_session_is_opened(sess))
|
||||
return -EINVAL;
|
||||
|
||||
ret = tee_session_close_be(sess);
|
||||
|
||||
mutex_lock(&sess->ctx->tee->lock);
|
||||
tee_dec_stats(&tee->stats[TEE_STATS_SESSION_IDX]);
|
||||
list_del(&sess->entry);
|
||||
mutex_unlock(&sess->ctx->tee->lock);
|
||||
|
||||
devm_kfree(_DEV(tee), sess);
|
||||
tee_context_put(ctx);
|
||||
tee_put(tee);
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: <\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct tee_session *tee_session_create_and_open(struct tee_context *ctx,
|
||||
struct tee_cmd_io *cmd_io)
|
||||
{
|
||||
int ret = 0;
|
||||
struct tee_session *sess;
|
||||
struct tee *tee;
|
||||
|
||||
BUG_ON(!ctx->tee);
|
||||
|
||||
tee = ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: >\n", __func__);
|
||||
ret = tee_get(tee);
|
||||
if (ret)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
sess = devm_kzalloc(_DEV(tee), sizeof(struct tee_session), GFP_KERNEL);
|
||||
if (!sess) {
|
||||
dev_err(_DEV(tee), "%s: tee_session allocation() failed\n",
|
||||
__func__);
|
||||
tee_put(tee);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
tee_context_get(ctx);
|
||||
sess->ctx = ctx;
|
||||
|
||||
ret = tee_session_open_be(sess, cmd_io);
|
||||
if (ret || !sess->sessid || cmd_io->err) {
|
||||
dev_err(_DEV(tee), "%s: ERROR ret=%d (err=0x%08x, org=%d, sessid=0x%08x)\n",
|
||||
__func__, ret, cmd_io->err,
|
||||
cmd_io->origin, sess->sessid);
|
||||
tee_put(tee);
|
||||
tee_context_put(ctx);
|
||||
devm_kfree(_DEV(tee), sess);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mutex_lock(&tee->lock);
|
||||
tee_inc_stats(&tee->stats[TEE_STATS_SESSION_IDX]);
|
||||
list_add_tail(&sess->entry, &ctx->list_sess);
|
||||
mutex_unlock(&tee->lock);
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: < sess=%p\n", __func__, sess);
|
||||
return sess;
|
||||
}
|
||||
|
||||
int tee_session_create_fd(struct tee_context *ctx, struct tee_cmd_io *cmd_io)
|
||||
{
|
||||
int ret;
|
||||
struct tee_session *sess;
|
||||
struct tee *tee = ctx->tee;
|
||||
|
||||
BUG_ON(cmd_io->fd_sess > 0);
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: >\n", __func__);
|
||||
|
||||
sess = tee_session_create_and_open(ctx, cmd_io);
|
||||
if (IS_ERR_OR_NULL(sess)) {
|
||||
ret = PTR_ERR(sess);
|
||||
dev_dbg(_DEV(tee), "%s: ERROR can't create the session (ret=%d, err=0x%08x, org=%d)\n",
|
||||
__func__, ret, cmd_io->err, cmd_io->origin);
|
||||
cmd_io->fd_sess = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Retrieve a fd */
|
||||
cmd_io->fd_sess = -1;
|
||||
ret =
|
||||
anon_inode_getfd("tee_session", &tee_session_fops, sess, O_CLOEXEC);
|
||||
if (ret < 0) {
|
||||
dev_err(_DEV(tee), "%s: ERROR can't get a fd (ret=%d)\n",
|
||||
__func__, ret);
|
||||
tee_session_close_and_destroy(sess);
|
||||
goto out;
|
||||
}
|
||||
cmd_io->fd_sess = ret;
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
dev_dbg(_DEV(tee), "%s: < ret=%d, sess=%p, fd=%d\n", __func__,
|
||||
ret, sess, cmd_io->fd_sess);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool tee_session_is_supported_type(struct tee_session *sess, int type)
|
||||
{
|
||||
switch (type) {
|
||||
case TEEC_NONE:
|
||||
case TEEC_VALUE_INPUT:
|
||||
case TEEC_VALUE_OUTPUT:
|
||||
case TEEC_VALUE_INOUT:
|
||||
case TEEC_MEMREF_TEMP_INPUT:
|
||||
case TEEC_MEMREF_TEMP_OUTPUT:
|
||||
case TEEC_MEMREF_TEMP_INOUT:
|
||||
case TEEC_MEMREF_WHOLE:
|
||||
case TEEC_MEMREF_PARTIAL_INPUT:
|
||||
case TEEC_MEMREF_PARTIAL_OUTPUT:
|
||||
case TEEC_MEMREF_PARTIAL_INOUT:
|
||||
return true;
|
||||
default:
|
||||
dev_err(_DEV_TEE, "type is invalid (type %02x)\n", type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int to_memref_type(int flags)
|
||||
{
|
||||
if (flag_set(flags, TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))
|
||||
return TEEC_MEMREF_TEMP_INOUT;
|
||||
|
||||
if (flag_set(flags, TEEC_MEM_INPUT))
|
||||
return TEEC_MEMREF_TEMP_INPUT;
|
||||
|
||||
if (flag_set(flags, TEEC_MEM_OUTPUT))
|
||||
return TEEC_MEMREF_TEMP_OUTPUT;
|
||||
|
||||
pr_err("%s: bad flags=%x\n", __func__, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _init_tee_cmd(struct tee_session *sess, struct tee_cmd_io *cmd_io,
|
||||
struct tee_cmd *cmd)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
int idx;
|
||||
TEEC_Operation op;
|
||||
struct tee_data *param = &cmd->param;
|
||||
struct tee *tee;
|
||||
struct tee_context *ctx;
|
||||
|
||||
BUG_ON(!sess->ctx);
|
||||
BUG_ON(!sess->ctx->tee);
|
||||
ctx = sess->ctx;
|
||||
tee = sess->ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > sessid=%08x\n", __func__, sess->sessid);
|
||||
|
||||
memset(cmd, 0, sizeof(struct tee_cmd));
|
||||
|
||||
cmd->cmd = cmd_io->cmd;
|
||||
cmd->origin = TEEC_ORIGIN_TEE;
|
||||
cmd->err = TEEC_ERROR_BAD_PARAMETERS;
|
||||
cmd_io->origin = cmd->origin;
|
||||
cmd_io->err = cmd->err;
|
||||
|
||||
if (tee_context_copy_from_client(ctx, &op, cmd_io->op, sizeof(op)))
|
||||
goto out;
|
||||
|
||||
cmd->param.type_original = op.paramTypes;
|
||||
|
||||
for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
|
||||
uint32_t offset = 0;
|
||||
uint32_t size = 0;
|
||||
int type = TEEC_PARAM_TYPE_GET(op.paramTypes, idx);
|
||||
|
||||
switch (type) {
|
||||
case TEEC_NONE:
|
||||
break;
|
||||
|
||||
case TEEC_VALUE_INPUT:
|
||||
case TEEC_VALUE_OUTPUT:
|
||||
case TEEC_VALUE_INOUT:
|
||||
param->params[idx].value = op.params[idx].value;
|
||||
dev_dbg(_DEV_TEE,
|
||||
"%s: param[%d]:type=%d,a=%08x,b=%08x (VALUE)\n",
|
||||
__func__, idx, type, param->params[idx].value.a,
|
||||
param->params[idx].value.b);
|
||||
break;
|
||||
|
||||
case TEEC_MEMREF_TEMP_INPUT:
|
||||
case TEEC_MEMREF_TEMP_OUTPUT:
|
||||
case TEEC_MEMREF_TEMP_INOUT:
|
||||
dev_dbg(_DEV_TEE,
|
||||
"> param[%d]:type=%d,buffer=%p,s=%zu (TMPREF)\n",
|
||||
idx, type, op.params[idx].tmpref.buffer,
|
||||
op.params[idx].tmpref.size);
|
||||
|
||||
param->params[idx].shm =
|
||||
tee_context_create_tmpref_buffer(ctx,
|
||||
op.params[idx].tmpref.size,
|
||||
op.params[idx].tmpref.buffer,
|
||||
type);
|
||||
if (IS_ERR_OR_NULL(param->params[idx].shm))
|
||||
goto out;
|
||||
|
||||
dev_dbg(_DEV_TEE, "< %d %p:%zd\n", idx,
|
||||
(void *)param->params[idx].shm->paddr,
|
||||
param->params[idx].shm->size_alloc);
|
||||
break;
|
||||
|
||||
case TEEC_MEMREF_PARTIAL_INPUT:
|
||||
case TEEC_MEMREF_PARTIAL_OUTPUT:
|
||||
case TEEC_MEMREF_PARTIAL_INOUT:
|
||||
case TEEC_MEMREF_WHOLE:
|
||||
if (tee_copy_from_user(ctx, ¶m->c_shm[idx],
|
||||
op.params[idx].memref.parent,
|
||||
sizeof(param->c_shm[idx]))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (type == TEEC_MEMREF_WHOLE) {
|
||||
offset = 0;
|
||||
size = param->c_shm[idx].size;
|
||||
} else { /* for PARTIAL, check the size */
|
||||
offset = op.params[idx].memref.offset;
|
||||
size = op.params[idx].memref.size;
|
||||
if (param->c_shm[idx].size < size + offset) {
|
||||
dev_err(_DEV(tee), "A PARTIAL parameter is bigger than the parent %zd < %d + %d\n",
|
||||
param->c_shm[idx].size, size,
|
||||
offset);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(_DEV_TEE, "> param[%d]:type=%d,buffer=%p, offset=%d size=%d\n",
|
||||
idx, type, param->c_shm[idx].buffer,
|
||||
offset, size);
|
||||
|
||||
type = to_memref_type(param->c_shm[idx].flags);
|
||||
if (type == 0)
|
||||
goto out;
|
||||
|
||||
param->params[idx].shm = tee_shm_get(ctx,
|
||||
¶m->c_shm[idx], size, offset);
|
||||
|
||||
if (IS_ERR_OR_NULL(param->params[idx].shm)) {
|
||||
param->params[idx].shm =
|
||||
tee_context_create_tmpref_buffer(ctx, size,
|
||||
param->c_shm[idx].buffer + offset, type);
|
||||
|
||||
if (IS_ERR_OR_NULL(param->params[idx].shm))
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_dbg(_DEV_TEE, "< %d %p:%zd\n", idx,
|
||||
(void *)param->params[idx].shm->paddr,
|
||||
param->params[idx].shm->size_req);
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
||||
param->type |= (type << (idx * 4));
|
||||
}
|
||||
|
||||
if (cmd_io->uuid != NULL) {
|
||||
dev_dbg(_DEV_TEE, "%s: copy UUID value...\n", __func__);
|
||||
cmd->uuid = tee_context_alloc_shm_tmp(sess->ctx,
|
||||
sizeof(*cmd_io->uuid), cmd_io->uuid, TEEC_MEM_INPUT);
|
||||
if (IS_ERR_OR_NULL(cmd->uuid)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
_release_tee_cmd(sess, cmd);
|
||||
|
||||
dev_dbg(_DEV_TEE, "%s: < ret=%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _update_client_tee_cmd(struct tee_session *sess,
|
||||
struct tee_cmd_io *cmd_io,
|
||||
struct tee_cmd *cmd)
|
||||
{
|
||||
int idx;
|
||||
struct tee_context *ctx;
|
||||
|
||||
BUG_ON(!cmd_io);
|
||||
BUG_ON(!cmd_io->op);
|
||||
BUG_ON(!cmd_io->op->params);
|
||||
BUG_ON(!cmd);
|
||||
BUG_ON(!sess->ctx);
|
||||
ctx = sess->ctx;
|
||||
|
||||
dev_dbg(_DEV_TEE, "%s: returned err=0x%08x (origin=%d)\n", __func__,
|
||||
cmd->err, cmd->origin);
|
||||
|
||||
cmd_io->origin = cmd->origin;
|
||||
cmd_io->err = cmd->err;
|
||||
|
||||
if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
|
||||
TEEC_NONE, TEEC_NONE, TEEC_NONE))
|
||||
return;
|
||||
|
||||
for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
|
||||
int type = TEEC_PARAM_TYPE_GET(cmd->param.type_original, idx);
|
||||
int offset = 0;
|
||||
size_t size;
|
||||
size_t size_new;
|
||||
TEEC_SharedMemory *parent;
|
||||
|
||||
dev_dbg(_DEV_TEE, "%s: id %d type %d\n", __func__, idx, type);
|
||||
BUG_ON(!tee_session_is_supported_type(sess, type));
|
||||
switch (type) {
|
||||
case TEEC_NONE:
|
||||
case TEEC_VALUE_INPUT:
|
||||
case TEEC_MEMREF_TEMP_INPUT:
|
||||
case TEEC_MEMREF_PARTIAL_INPUT:
|
||||
break;
|
||||
case TEEC_VALUE_OUTPUT:
|
||||
case TEEC_VALUE_INOUT:
|
||||
dev_dbg(_DEV_TEE, "%s: a=%08x, b=%08x\n",
|
||||
__func__,
|
||||
cmd->param.params[idx].value.a,
|
||||
cmd->param.params[idx].value.b);
|
||||
if (tee_copy_to_user
|
||||
(ctx, &cmd_io->op->params[idx].value,
|
||||
&cmd->param.params[idx].value,
|
||||
sizeof(cmd_io->op->params[idx].value)))
|
||||
dev_err(_DEV_TEE,
|
||||
"%s:%d: can't update %d result to user\n",
|
||||
__func__, __LINE__, idx);
|
||||
break;
|
||||
case TEEC_MEMREF_TEMP_OUTPUT:
|
||||
case TEEC_MEMREF_TEMP_INOUT:
|
||||
/* Returned updated size */
|
||||
size_new = cmd->param.params[idx].shm->size_req;
|
||||
if (size_new !=
|
||||
cmd_io->op->params[idx].tmpref.size) {
|
||||
dev_dbg(_DEV_TEE,
|
||||
"Size has been updated by the TA %zd != %zd\n",
|
||||
size_new,
|
||||
cmd_io->op->params[idx].tmpref.
|
||||
size);
|
||||
tee_put_user(ctx, size_new,
|
||||
&cmd_io->op->params[idx].tmpref.size);
|
||||
}
|
||||
|
||||
dev_dbg(_DEV_TEE, "%s: tmpref %p\n", __func__,
|
||||
cmd->param.params[idx].shm->kaddr);
|
||||
|
||||
/* ensure we do not exceed the shared buffer length */
|
||||
if (size_new > cmd_io->op->params[idx].tmpref.size)
|
||||
dev_err(_DEV_TEE,
|
||||
" *** Wrong returned size from %d:%zd > %zd\n",
|
||||
idx, size_new,
|
||||
cmd_io->op->params[idx].tmpref.
|
||||
size);
|
||||
|
||||
else if (tee_copy_to_user
|
||||
(ctx,
|
||||
cmd_io->op->params[idx].tmpref.buffer,
|
||||
cmd->param.params[idx].shm->kaddr,
|
||||
size_new))
|
||||
dev_err(_DEV_TEE,
|
||||
"%s:%d: can't update %d result to user\n",
|
||||
__func__, __LINE__, idx);
|
||||
break;
|
||||
|
||||
case TEEC_MEMREF_PARTIAL_OUTPUT:
|
||||
case TEEC_MEMREF_PARTIAL_INOUT:
|
||||
case TEEC_MEMREF_WHOLE:
|
||||
if (type == TEEC_MEMREF_WHOLE) {
|
||||
offset = 0;
|
||||
size = parent->size;
|
||||
} else {
|
||||
offset = cmd_io->op->params[idx].memref.offset;
|
||||
size = cmd_io->op->params[idx].memref.size;
|
||||
}
|
||||
parent = &cmd->param.c_shm[idx];
|
||||
|
||||
/* Returned updated size */
|
||||
size_new = cmd->param.params[idx].shm->size_req;
|
||||
tee_put_user(ctx, size_new,
|
||||
&cmd_io->op->params[idx].memref.size);
|
||||
|
||||
/*
|
||||
* If we allocated a tmpref buffer,
|
||||
* copy back data to the user buffer
|
||||
*/
|
||||
if (is_mapped_temp(cmd->param.params[idx].shm->flags)) {
|
||||
if (parent->buffer &&
|
||||
offset + size_new <= parent->size) {
|
||||
if (tee_copy_to_user(ctx,
|
||||
parent->buffer + offset,
|
||||
cmd->param.params[idx].shm->kaddr,
|
||||
size_new))
|
||||
dev_err(_DEV_TEE,
|
||||
"%s: can't update %d data to user\n",
|
||||
__func__, idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void _release_tee_cmd(struct tee_session *sess, struct tee_cmd *cmd)
|
||||
{
|
||||
int idx;
|
||||
struct tee_context *ctx;
|
||||
|
||||
BUG_ON(!cmd);
|
||||
BUG_ON(!sess);
|
||||
BUG_ON(!sess->ctx);
|
||||
BUG_ON(!sess->ctx->tee);
|
||||
|
||||
ctx = sess->ctx;
|
||||
|
||||
dev_dbg(_DEV_TEE, "%s: > free the temporary objects...\n", __func__);
|
||||
|
||||
tee_shm_free(cmd->uuid);
|
||||
|
||||
if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
|
||||
TEEC_NONE, TEEC_NONE, TEEC_NONE))
|
||||
goto out;
|
||||
|
||||
for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
|
||||
int type = TEEC_PARAM_TYPE_GET(cmd->param.type_original, idx);
|
||||
struct tee_shm *shm;
|
||||
switch (type) {
|
||||
case TEEC_NONE:
|
||||
case TEEC_VALUE_INPUT:
|
||||
case TEEC_VALUE_OUTPUT:
|
||||
case TEEC_VALUE_INOUT:
|
||||
break;
|
||||
case TEEC_MEMREF_TEMP_INPUT:
|
||||
case TEEC_MEMREF_TEMP_OUTPUT:
|
||||
case TEEC_MEMREF_TEMP_INOUT:
|
||||
case TEEC_MEMREF_WHOLE:
|
||||
case TEEC_MEMREF_PARTIAL_INPUT:
|
||||
case TEEC_MEMREF_PARTIAL_OUTPUT:
|
||||
case TEEC_MEMREF_PARTIAL_INOUT:
|
||||
if (IS_ERR_OR_NULL(cmd->param.params[idx].shm))
|
||||
break;
|
||||
|
||||
shm = cmd->param.params[idx].shm;
|
||||
|
||||
if (is_mapped_temp(shm->flags))
|
||||
tee_shm_free(shm);
|
||||
else
|
||||
tee_shm_put(ctx, shm);
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
memset(cmd, 0, sizeof(struct tee_cmd));
|
||||
dev_dbg(_DEV_TEE, "%s: <\n", __func__);
|
||||
}
|
||||
815
security/optee_linuxdriver/core/tee_shm.c
Normal file
815
security/optee_linuxdriver/core/tee_shm.c
Normal file
@@ -0,0 +1,815 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/hugetlb.h>
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include "tee_core_priv.h"
|
||||
#include "tee_shm.h"
|
||||
|
||||
#define INMSG() dev_dbg(_DEV(tee), "%s: >\n", __func__)
|
||||
#define OUTMSG(val) dev_dbg(_DEV(tee), "%s: < %ld\n", __func__, (long)val)
|
||||
#define OUTMSGX(val) dev_dbg(_DEV(tee), "%s: < %08x\n",\
|
||||
__func__, (unsigned int)(long)val)
|
||||
|
||||
/* TODO
|
||||
#if (sizeof(TEEC_SharedMemory) != sizeof(tee_shm))
|
||||
#error "sizeof(TEEC_SharedMemory) != sizeof(tee_shm))"
|
||||
#endif
|
||||
*/
|
||||
struct tee_shm_attach {
|
||||
struct sg_table sgt;
|
||||
enum dma_data_direction dir;
|
||||
bool is_mapped;
|
||||
};
|
||||
|
||||
struct tee_shm *tee_shm_alloc_from_rpc(struct tee *tee, size_t size)
|
||||
{
|
||||
struct tee_shm *shm;
|
||||
|
||||
INMSG();
|
||||
|
||||
shm = tee_shm_alloc(tee, size, TEE_SHM_TEMP | TEE_SHM_FROM_RPC);
|
||||
if (IS_ERR_OR_NULL(shm)) {
|
||||
dev_err(_DEV(tee), "%s: buffer allocation failed (%ld)\n",
|
||||
__func__, PTR_ERR(shm));
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&tee->lock);
|
||||
tee_inc_stats(&tee->stats[TEE_STATS_SHM_IDX]);
|
||||
list_add_tail(&shm->entry, &tee->list_rpc_shm);
|
||||
mutex_unlock(&tee->lock);
|
||||
shm->ctx = NULL;
|
||||
|
||||
out:
|
||||
OUTMSGX(shm);
|
||||
return shm;
|
||||
}
|
||||
|
||||
void tee_shm_free_from_rpc(struct tee_shm *shm)
|
||||
{
|
||||
if (shm == NULL)
|
||||
return;
|
||||
|
||||
if (shm->ctx == NULL) {
|
||||
mutex_lock(&shm->tee->lock);
|
||||
tee_dec_stats(&shm->tee->stats[TEE_STATS_SHM_IDX]);
|
||||
list_del(&shm->entry);
|
||||
mutex_unlock(&shm->tee->lock);
|
||||
}
|
||||
|
||||
tee_shm_free(shm);
|
||||
}
|
||||
|
||||
struct tee_shm *tee_shm_alloc(struct tee *tee, size_t size, uint32_t flags)
|
||||
{
|
||||
struct tee_shm *shm;
|
||||
unsigned long pfn;
|
||||
unsigned int nr_pages;
|
||||
struct page *page;
|
||||
int ret;
|
||||
|
||||
INMSG();
|
||||
|
||||
shm = tee->ops->alloc(tee, size, flags);
|
||||
if (IS_ERR_OR_NULL(shm)) {
|
||||
dev_err(_DEV(tee),
|
||||
"%s: allocation failed (s=%d,flags=0x%08x) err=%ld\n",
|
||||
__func__, (int)size, flags, PTR_ERR(shm));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
shm->tee = tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: shm=%p, paddr=%p,s=%d/%d app=\"%s\" pid=%d\n",
|
||||
__func__, shm, (void *)shm->paddr, (int)shm->size_req,
|
||||
(int)shm->size_alloc, current->comm, current->pid);
|
||||
|
||||
pfn = shm->paddr >> PAGE_SHIFT;
|
||||
page = pfn_to_page(pfn);
|
||||
if (IS_ERR_OR_NULL(page)) {
|
||||
dev_err(_DEV(tee), "%s: pfn_to_page(%lx) failed\n",
|
||||
__func__, pfn);
|
||||
tee->ops->free(shm);
|
||||
return (struct tee_shm *)page;
|
||||
}
|
||||
|
||||
/* Only one page of contiguous physical memory */
|
||||
nr_pages = 1;
|
||||
|
||||
ret = sg_alloc_table_from_pages(&shm->sgt, &page,
|
||||
nr_pages, 0, nr_pages * PAGE_SIZE, GFP_KERNEL);
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
dev_err(_DEV(tee), "%s: sg_alloc_table_from_pages() failed\n",
|
||||
__func__);
|
||||
tee->ops->free(shm);
|
||||
shm = ERR_PTR(ret);
|
||||
}
|
||||
exit:
|
||||
OUTMSGX(shm);
|
||||
return shm;
|
||||
}
|
||||
|
||||
void tee_shm_free(struct tee_shm *shm)
|
||||
{
|
||||
struct tee *tee;
|
||||
|
||||
if (IS_ERR_OR_NULL(shm))
|
||||
return;
|
||||
tee = shm->tee;
|
||||
if (tee == NULL)
|
||||
pr_warn("invalid call to tee_shm_free(%p): NULL tee\n", shm);
|
||||
else if (shm->tee == NULL)
|
||||
dev_warn(_DEV(tee), "tee_shm_free(%p): NULL tee\n", shm);
|
||||
else {
|
||||
sg_free_table(&shm->sgt);
|
||||
shm->tee->ops->free(shm);
|
||||
}
|
||||
}
|
||||
|
||||
static int _tee_shm_attach_dma_buf(struct dma_buf *dmabuf,
|
||||
struct device *dev,
|
||||
struct dma_buf_attachment *attach)
|
||||
{
|
||||
struct tee_shm_attach *tee_shm_attach;
|
||||
struct tee_shm *shm;
|
||||
struct tee *tee;
|
||||
|
||||
shm = dmabuf->priv;
|
||||
tee = shm->tee;
|
||||
|
||||
INMSG();
|
||||
|
||||
tee_shm_attach = devm_kzalloc(_DEV(tee),
|
||||
sizeof(*tee_shm_attach), GFP_KERNEL);
|
||||
if (!tee_shm_attach) {
|
||||
OUTMSG(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tee_shm_attach->dir = DMA_NONE;
|
||||
attach->priv = tee_shm_attach;
|
||||
|
||||
OUTMSG(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _tee_shm_detach_dma_buf(struct dma_buf *dmabuf,
|
||||
struct dma_buf_attachment *attach)
|
||||
{
|
||||
struct tee_shm_attach *tee_shm_attach = attach->priv;
|
||||
struct sg_table *sgt;
|
||||
struct tee_shm *shm;
|
||||
struct tee *tee;
|
||||
|
||||
shm = dmabuf->priv;
|
||||
tee = shm->tee;
|
||||
|
||||
INMSG();
|
||||
|
||||
if (!tee_shm_attach) {
|
||||
OUTMSG(0);
|
||||
return;
|
||||
}
|
||||
|
||||
sgt = &tee_shm_attach->sgt;
|
||||
|
||||
if (tee_shm_attach->dir != DMA_NONE)
|
||||
dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
|
||||
tee_shm_attach->dir);
|
||||
|
||||
sg_free_table(sgt);
|
||||
devm_kfree(_DEV(tee), tee_shm_attach);
|
||||
attach->priv = NULL;
|
||||
OUTMSG(0);
|
||||
}
|
||||
|
||||
static struct sg_table *_tee_shm_dma_buf_map_dma_buf(
|
||||
struct dma_buf_attachment *attach, enum dma_data_direction dir)
|
||||
{
|
||||
struct tee_shm_attach *tee_shm_attach = attach->priv;
|
||||
struct tee_shm *tee_shm = attach->dmabuf->priv;
|
||||
struct sg_table *sgt = NULL;
|
||||
struct scatterlist *rd, *wr;
|
||||
unsigned int i;
|
||||
int nents, ret;
|
||||
struct tee *tee;
|
||||
|
||||
tee = tee_shm->tee;
|
||||
|
||||
INMSG();
|
||||
|
||||
/* just return current sgt if already requested. */
|
||||
if (tee_shm_attach->dir == dir && tee_shm_attach->is_mapped) {
|
||||
OUTMSGX(&tee_shm_attach->sgt);
|
||||
return &tee_shm_attach->sgt;
|
||||
}
|
||||
|
||||
sgt = &tee_shm_attach->sgt;
|
||||
|
||||
ret = sg_alloc_table(sgt, tee_shm->sgt.orig_nents, GFP_KERNEL);
|
||||
if (ret) {
|
||||
dev_err(_DEV(tee), "failed to alloc sgt.\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
rd = tee_shm->sgt.sgl;
|
||||
wr = sgt->sgl;
|
||||
for (i = 0; i < sgt->orig_nents; ++i) {
|
||||
sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
|
||||
rd = sg_next(rd);
|
||||
wr = sg_next(wr);
|
||||
}
|
||||
|
||||
if (dir != DMA_NONE) {
|
||||
nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
|
||||
if (!nents) {
|
||||
dev_err(_DEV(tee), "failed to map sgl with iommu.\n");
|
||||
sg_free_table(sgt);
|
||||
sgt = ERR_PTR(-EIO);
|
||||
goto err_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
tee_shm_attach->is_mapped = true;
|
||||
tee_shm_attach->dir = dir;
|
||||
attach->priv = tee_shm_attach;
|
||||
|
||||
err_unlock:
|
||||
OUTMSGX(sgt);
|
||||
return sgt;
|
||||
}
|
||||
|
||||
static void _tee_shm_dma_buf_unmap_dma_buf(struct dma_buf_attachment *attach,
|
||||
struct sg_table *table,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void _tee_shm_dma_buf_release(struct dma_buf *dmabuf)
|
||||
{
|
||||
struct tee_shm *shm = dmabuf->priv;
|
||||
struct tee_context *ctx;
|
||||
struct tee *tee;
|
||||
|
||||
tee = shm->ctx->tee;
|
||||
|
||||
INMSG();
|
||||
|
||||
ctx = shm->ctx;
|
||||
dev_dbg(_DEV(ctx->tee), "%s: shm=%p, paddr=%p,s=%d/%d app=\"%s\" pid=%d\n",
|
||||
__func__, shm, (void *)shm->paddr, (int)shm->size_req,
|
||||
(int)shm->size_alloc, current->comm, current->pid);
|
||||
|
||||
tee_shm_free_io(shm);
|
||||
|
||||
OUTMSG(0);
|
||||
}
|
||||
|
||||
static int _tee_shm_dma_buf_mmap(struct dma_buf *dmabuf,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct tee_shm *shm = dmabuf->priv;
|
||||
size_t size = vma->vm_end - vma->vm_start;
|
||||
struct tee *tee;
|
||||
int ret;
|
||||
pgprot_t prot;
|
||||
unsigned long pfn;
|
||||
|
||||
tee = shm->ctx->tee;
|
||||
|
||||
pfn = shm->paddr >> PAGE_SHIFT;
|
||||
|
||||
INMSG();
|
||||
|
||||
if (shm->flags & TEE_SHM_CACHED)
|
||||
prot = vma->vm_page_prot;
|
||||
else
|
||||
prot = pgprot_noncached(vma->vm_page_prot);
|
||||
|
||||
ret =
|
||||
remap_pfn_range(vma, vma->vm_start, pfn, size, prot);
|
||||
if (!ret)
|
||||
vma->vm_private_data = (void *)shm;
|
||||
|
||||
dev_dbg(_DEV(shm->ctx->tee), "%s: map the shm (p@=%p,s=%dKiB) => %x\n",
|
||||
__func__, (void *)shm->paddr, (int)size / 1024,
|
||||
(unsigned int)vma->vm_start);
|
||||
|
||||
OUTMSG(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *_tee_shm_dma_buf_kmap_atomic(struct dma_buf *dmabuf,
|
||||
unsigned long pgnum)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *_tee_shm_dma_buf_kmap(struct dma_buf *db, unsigned long pgnum)
|
||||
{
|
||||
struct tee_shm *shm = db->priv;
|
||||
|
||||
dev_dbg(_DEV(shm->ctx->tee), "%s: kmap the shm (p@=%p, v@=%p, s=%zdKiB)\n",
|
||||
__func__, (void *)shm->paddr, (void *)shm->kaddr,
|
||||
shm->size_alloc / 1024);
|
||||
/*
|
||||
* A this stage, a shm allocated by the tee
|
||||
* must be have a kernel address
|
||||
*/
|
||||
return shm->kaddr;
|
||||
}
|
||||
|
||||
static void _tee_shm_dma_buf_kunmap(
|
||||
struct dma_buf *db, unsigned long pfn, void *kaddr)
|
||||
{
|
||||
/* unmap is done at the de init of the shm pool */
|
||||
}
|
||||
|
||||
struct dma_buf_ops _tee_shm_dma_buf_ops = {
|
||||
.attach = _tee_shm_attach_dma_buf,
|
||||
.detach = _tee_shm_detach_dma_buf,
|
||||
.map_dma_buf = _tee_shm_dma_buf_map_dma_buf,
|
||||
.unmap_dma_buf = _tee_shm_dma_buf_unmap_dma_buf,
|
||||
.release = _tee_shm_dma_buf_release,
|
||||
.kmap_atomic = _tee_shm_dma_buf_kmap_atomic,
|
||||
.kmap = _tee_shm_dma_buf_kmap,
|
||||
.kunmap = _tee_shm_dma_buf_kunmap,
|
||||
.mmap = _tee_shm_dma_buf_mmap,
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int export_buf(struct tee *tee, struct tee_shm *shm, int *export)
|
||||
{
|
||||
struct dma_buf *dmabuf;
|
||||
int ret = 0;
|
||||
/* Temporary fix to support both older and newer kernel versions. */
|
||||
#if defined(DEFINE_DMA_BUF_EXPORT_INFO)
|
||||
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||||
|
||||
exp_info.priv = shm;
|
||||
exp_info.ops = &_tee_shm_dma_buf_ops;
|
||||
exp_info.size = shm->size_alloc;
|
||||
exp_info.flags = O_RDWR;
|
||||
|
||||
dmabuf = dma_buf_export(&exp_info);
|
||||
#else
|
||||
dmabuf = dma_buf_export(shm, &_tee_shm_dma_buf_ops, shm->size_alloc,
|
||||
O_RDWR, 0);
|
||||
#endif
|
||||
if (IS_ERR_OR_NULL(dmabuf)) {
|
||||
dev_err(_DEV(tee), "%s: dmabuf: couldn't export buffer (%ld)\n",
|
||||
__func__, PTR_ERR(dmabuf));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*export = dma_buf_fd(dmabuf, O_CLOEXEC);
|
||||
out:
|
||||
OUTMSG(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tee_shm_alloc_io(struct tee_context *ctx, struct tee_shm_io *shm_io)
|
||||
{
|
||||
struct tee_shm *shm;
|
||||
struct tee *tee = ctx->tee;
|
||||
int ret;
|
||||
|
||||
INMSG();
|
||||
|
||||
if (ctx->usr_client)
|
||||
shm_io->fd_shm = 0;
|
||||
else
|
||||
shm_io->ptr = NULL;
|
||||
|
||||
shm = tee_shm_alloc(tee, shm_io->size, shm_io->flags);
|
||||
if (IS_ERR_OR_NULL(shm)) {
|
||||
dev_err(_DEV(tee), "%s: buffer allocation failed (%ld)\n",
|
||||
__func__, PTR_ERR(shm));
|
||||
return PTR_ERR(shm);
|
||||
}
|
||||
|
||||
if (ctx->usr_client) {
|
||||
ret = export_buf(tee, shm, &shm_io->fd_shm);
|
||||
if (ret) {
|
||||
tee_shm_free(shm);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
shm->flags |= TEEC_MEM_DMABUF;
|
||||
} else
|
||||
shm_io->ptr = shm;
|
||||
|
||||
shm->ctx = ctx;
|
||||
shm->dev = get_device(_DEV(tee));
|
||||
ret = tee_get(tee);
|
||||
BUG_ON(ret); /* tee_core_get must not issue */
|
||||
tee_context_get(ctx);
|
||||
|
||||
mutex_lock(&tee->lock);
|
||||
tee_inc_stats(&tee->stats[TEE_STATS_SHM_IDX]);
|
||||
list_add_tail(&shm->entry, &ctx->list_shm);
|
||||
mutex_unlock(&tee->lock);
|
||||
out:
|
||||
OUTMSG(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tee_shm_free_io(struct tee_shm *shm)
|
||||
{
|
||||
struct tee_context *ctx = shm->ctx;
|
||||
struct tee *tee = ctx->tee;
|
||||
struct device *dev = shm->dev;
|
||||
|
||||
mutex_lock(&ctx->tee->lock);
|
||||
tee_dec_stats(&tee->stats[TEE_STATS_SHM_IDX]);
|
||||
list_del(&shm->entry);
|
||||
mutex_unlock(&ctx->tee->lock);
|
||||
|
||||
tee_shm_free(shm);
|
||||
tee_put(ctx->tee);
|
||||
tee_context_put(ctx);
|
||||
if (dev)
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
/* Buffer allocated by rpc from fw and to be accessed by the user
|
||||
* Not need to be registered as it is not allocated by the user */
|
||||
int tee_shm_fd_for_rpc(struct tee_context *ctx, struct tee_shm_io *shm_io)
|
||||
{
|
||||
struct tee_shm *shm = NULL;
|
||||
struct tee *tee = ctx->tee;
|
||||
int ret;
|
||||
struct list_head *pshm;
|
||||
|
||||
INMSG();
|
||||
|
||||
shm_io->fd_shm = 0;
|
||||
|
||||
if (!list_empty(&tee->list_rpc_shm)) {
|
||||
list_for_each(pshm, &tee->list_rpc_shm) {
|
||||
shm = list_entry(pshm, struct tee_shm, entry);
|
||||
if ((void *)shm->paddr == shm_io->buffer)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(_DEV(tee), "Can't find shm for %p\n", (void *)shm_io->buffer);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
|
||||
found:
|
||||
ret = export_buf(tee, shm, &shm_io->fd_shm);
|
||||
if (ret) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
shm->ctx = ctx;
|
||||
mutex_lock(&tee->lock);
|
||||
list_move(&shm->entry, &ctx->list_shm);
|
||||
mutex_unlock(&tee->lock);
|
||||
|
||||
shm->dev = get_device(_DEV(tee));
|
||||
ret = tee_get(tee);
|
||||
BUG_ON(ret);
|
||||
tee_context_get(ctx);
|
||||
|
||||
BUG_ON(!tee->ops->shm_inc_ref(shm));
|
||||
out:
|
||||
OUTMSG(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static int tee_shm_db_get(struct tee *tee, struct tee_shm *shm, int fd,
|
||||
unsigned int flags, size_t size, int offset)
|
||||
{
|
||||
struct tee_shm_dma_buf *sdb;
|
||||
struct dma_buf *dma_buf;
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > fd=%d flags=%08x\n", __func__, fd, flags);
|
||||
|
||||
dma_buf = dma_buf_get(fd);
|
||||
if (IS_ERR(dma_buf)) {
|
||||
ret = PTR_ERR(dma_buf);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sdb = kzalloc(sizeof(*sdb), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(sdb)) {
|
||||
dev_err(_DEV(tee), "can't alloc tee_shm_dma_buf\n");
|
||||
ret = PTR_ERR(sdb);
|
||||
goto buf_put;
|
||||
}
|
||||
shm->sdb = sdb;
|
||||
|
||||
if (dma_buf->size < size + offset) {
|
||||
dev_err(_DEV(tee), "dma_buf too small %zd < %zd + %d\n",
|
||||
dma_buf->size, size, offset);
|
||||
ret = -EINVAL;
|
||||
goto free_sdb;
|
||||
}
|
||||
|
||||
sdb->attach = dma_buf_attach(dma_buf, _DEV(tee));
|
||||
if (IS_ERR_OR_NULL(sdb->attach)) {
|
||||
ret = PTR_ERR(sdb->attach);
|
||||
goto free_sdb;
|
||||
}
|
||||
|
||||
sdb->sgt = dma_buf_map_attachment(sdb->attach, DMA_NONE);
|
||||
if (IS_ERR_OR_NULL(sdb->sgt)) {
|
||||
ret = PTR_ERR(sdb->sgt);
|
||||
goto buf_detach;
|
||||
}
|
||||
|
||||
if (sg_nents(sdb->sgt->sgl) != 1) {
|
||||
ret = -EINVAL;
|
||||
goto buf_unmap;
|
||||
}
|
||||
|
||||
shm->paddr = sg_phys(sdb->sgt->sgl) + offset;
|
||||
if (dma_buf->ops->attach == _tee_shm_attach_dma_buf)
|
||||
sdb->tee_allocated = true;
|
||||
else
|
||||
sdb->tee_allocated = false;
|
||||
|
||||
shm->flags |= TEEC_MEM_DMABUF;
|
||||
|
||||
dev_dbg(_DEV(tee), "fd=%d @p=%p is_tee=%d db=%p\n", fd,
|
||||
(void *)shm->paddr, sdb->tee_allocated, dma_buf);
|
||||
goto exit;
|
||||
|
||||
buf_unmap:
|
||||
dma_buf_unmap_attachment(sdb->attach, sdb->sgt, DMA_NONE);
|
||||
buf_detach:
|
||||
dma_buf_detach(dma_buf, sdb->attach);
|
||||
free_sdb:
|
||||
kfree(sdb);
|
||||
buf_put:
|
||||
dma_buf_put(dma_buf);
|
||||
exit:
|
||||
OUTMSG(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef VA_GET_ENABLED
|
||||
static unsigned int tee_shm_get_phy_from_kla(
|
||||
struct mm_struct *mm, unsigned int kla)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
pte_t *ptep, pte;
|
||||
unsigned int pa = 0;
|
||||
|
||||
/* stolen from kernel3.10:mm/memory.c:__follow_pte */
|
||||
|
||||
pgd = pgd_offset(mm, kla);
|
||||
if (pgd_none(*pgd) || pgd_bad(*pgd))
|
||||
return 0;
|
||||
|
||||
pud = pud_offset(pgd, kla);
|
||||
if (pud_none(*pud) || pud_bad(*pud))
|
||||
return 0;
|
||||
|
||||
pmd = pmd_offset(pud, kla);
|
||||
VM_BUG_ON(pmd_trans_huge(*pmd));
|
||||
if (pmd_none(*pmd) || pmd_bad(*pmd))
|
||||
return 0;
|
||||
|
||||
/* We cannot handle huge page PFN maps.
|
||||
* Luckily they don't exist. */
|
||||
if (pmd_huge(*pmd))
|
||||
return 0;
|
||||
|
||||
ptep = pte_offset_map(pmd, kla);
|
||||
|
||||
if (!ptep)
|
||||
return 0;
|
||||
|
||||
pte = *ptep;
|
||||
|
||||
if (pte_present(pte))
|
||||
pa = __pa(page_address(pte_page(pte)));
|
||||
|
||||
if (!pa)
|
||||
return 0;
|
||||
|
||||
return pa;
|
||||
|
||||
}
|
||||
|
||||
static int tee_shm_va_get(struct tee_context *ctx, struct tee_shm *shm,
|
||||
void *buffer, unsigned int flags, size_t size, int offset)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mm_struct *mm = current->mm;
|
||||
unsigned long va = (unsigned long)buffer;
|
||||
unsigned int virt_base = (va / PAGE_SIZE) * PAGE_SIZE;
|
||||
unsigned int offset_in_page = va - virt_base;
|
||||
unsigned int offset_total = offset_in_page + offset;
|
||||
struct vm_area_struct *vma;
|
||||
struct tee *tee = ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > %p\n", __func__, buffer);
|
||||
/* if the caller is the kernel api, active_mm is mm */
|
||||
if (!mm)
|
||||
mm = current->active_mm;
|
||||
|
||||
BUG_ON(!mm);
|
||||
|
||||
vma = find_vma(mm, virt_base);
|
||||
|
||||
if (vma) {
|
||||
unsigned long pfn;
|
||||
/* It's a VMA => consider it a a user address */
|
||||
|
||||
if (follow_pfn(vma, virt_base, &pfn)) {
|
||||
dev_err(_DEV(tee), "%s can't get pfn for %p\n",
|
||||
__func__, buffer);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
shm->paddr = PFN_PHYS(pfn) + offset_total;
|
||||
|
||||
if (vma->vm_end - vma->vm_start - offset_total < size) {
|
||||
dev_err(_DEV(tee), "%s %p:%x not big enough: %lx - %d < %x\n",
|
||||
__func__, buffer, shm->paddr,
|
||||
vma->vm_end - vma->vm_start,
|
||||
offset_total, size);
|
||||
shm->paddr = 0;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else if (!ctx->usr_client) {
|
||||
/* It's not a VMA => consider it as a kernel address
|
||||
* And look if it's an internal known phys addr
|
||||
* Note: virt_to_phys is not usable since it can be a direct
|
||||
* map or a vremap address
|
||||
*/
|
||||
unsigned int phys_base;
|
||||
int nb_page = (PAGE_SIZE - 1 + size + offset_total) / PAGE_SIZE;
|
||||
int i;
|
||||
|
||||
spin_lock(&mm->page_table_lock);
|
||||
phys_base = tee_shm_get_phy_from_kla(mm, virt_base);
|
||||
|
||||
if (!phys_base) {
|
||||
spin_unlock(&mm->page_table_lock);
|
||||
dev_err(_DEV(tee), "%s can't get physical address for %p\n",
|
||||
__func__, buffer);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Check continuity on size */
|
||||
for (i = 1; i < nb_page; i++) {
|
||||
unsigned int pa = tee_shm_get_phy_from_kla(mm,
|
||||
virt_base + i*PAGE_SIZE);
|
||||
if (pa != phys_base + i*PAGE_SIZE) {
|
||||
spin_unlock(&mm->page_table_lock);
|
||||
dev_err(_DEV(tee), "%s %p:%x not big enough: %lx - %d < %x\n",
|
||||
__func__, buffer, phys_base,
|
||||
i*PAGE_SIZE,
|
||||
offset_total, size);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
spin_unlock(&mm->page_table_lock);
|
||||
|
||||
shm->paddr = phys_base + offset_total;
|
||||
goto out;
|
||||
err:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
dev_dbg(_DEV(tee), "%s: < %d shm=%p vaddr=%p paddr=%x\n",
|
||||
__func__, ret, (void *)shm, buffer, shm->paddr);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct tee_shm *tee_shm_get(struct tee_context *ctx, TEEC_SharedMemory *c_shm,
|
||||
size_t size, int offset)
|
||||
{
|
||||
struct tee_shm *shm;
|
||||
struct tee *tee = ctx->tee;
|
||||
int ret;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > fd=%d flags=%08x\n",
|
||||
__func__, c_shm->d.fd, c_shm->flags);
|
||||
|
||||
shm = kzalloc(sizeof(*shm), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(shm)) {
|
||||
dev_err(_DEV(tee), "can't alloc tee_shm\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
shm->ctx = ctx;
|
||||
shm->tee = tee;
|
||||
shm->dev = _DEV(tee);
|
||||
shm->flags = c_shm->flags | TEE_SHM_MEMREF;
|
||||
shm->size_req = size;
|
||||
shm->size_alloc = 0;
|
||||
|
||||
if (c_shm->flags & TEEC_MEM_KAPI) {
|
||||
struct tee_shm *kc_shm = (struct tee_shm *)c_shm->d.ptr;
|
||||
|
||||
if (!kc_shm) {
|
||||
dev_err(_DEV(tee), "kapi fd null\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
shm->paddr = kc_shm->paddr;
|
||||
|
||||
if (kc_shm->size_alloc < size + offset) {
|
||||
dev_err(_DEV(tee), "kapi buff too small %zd < %zd + %d\n",
|
||||
kc_shm->size_alloc, size, offset);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev_dbg(_DEV(tee), "fd=%d @p=%p\n",
|
||||
c_shm->d.fd, (void *)shm->paddr);
|
||||
} else if (c_shm->d.fd) {
|
||||
ret = tee_shm_db_get(tee, shm,
|
||||
c_shm->d.fd, c_shm->flags, size, offset);
|
||||
if (ret)
|
||||
goto err;
|
||||
} else if (!c_shm->buffer) {
|
||||
dev_dbg(_DEV(tee), "null buffer, pass 'as is'\n");
|
||||
} else {
|
||||
#ifdef VA_GET_ENABLED
|
||||
ret = tee_shm_va_get(ctx, shm,
|
||||
c_shm->buffer, c_shm->flags, size, offset);
|
||||
if (ret)
|
||||
goto err;
|
||||
#else
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
#endif
|
||||
}
|
||||
|
||||
OUTMSGX(shm);
|
||||
return shm;
|
||||
|
||||
err:
|
||||
kfree(shm);
|
||||
OUTMSGX(ERR_PTR(ret));
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void tee_shm_put(struct tee_context *ctx, struct tee_shm *shm)
|
||||
{
|
||||
struct tee *tee = ctx->tee;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: > shm=%p flags=%08x paddr=%p\n",
|
||||
__func__, (void *)shm, shm->flags, (void *)shm->paddr);
|
||||
|
||||
BUG_ON(!shm);
|
||||
BUG_ON(!(shm->flags & TEE_SHM_MEMREF));
|
||||
|
||||
if (shm->flags & TEEC_MEM_DMABUF) {
|
||||
struct tee_shm_dma_buf *sdb;
|
||||
struct dma_buf *dma_buf;
|
||||
|
||||
sdb = shm->sdb;
|
||||
dma_buf = sdb->attach->dmabuf;
|
||||
|
||||
dev_dbg(_DEV(tee), "%s: db=%p\n", __func__, (void *)dma_buf);
|
||||
|
||||
dma_buf_unmap_attachment(sdb->attach, sdb->sgt, DMA_NONE);
|
||||
dma_buf_detach(dma_buf, sdb->attach);
|
||||
dma_buf_put(dma_buf);
|
||||
|
||||
kfree(sdb);
|
||||
sdb = 0;
|
||||
}
|
||||
|
||||
kfree(shm);
|
||||
OUTMSG(0);
|
||||
}
|
||||
|
||||
34
security/optee_linuxdriver/core/tee_shm.h
Normal file
34
security/optee_linuxdriver/core/tee_shm.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_SHM_H__
|
||||
#define __TEE_SHM_H__
|
||||
|
||||
#include <linux/tee_client_api.h>
|
||||
struct tee_context;
|
||||
struct tee_shm;
|
||||
struct tee_shm_io;
|
||||
struct tee;
|
||||
|
||||
int tee_shm_alloc_io(struct tee_context *ctx, struct tee_shm_io *shm_io);
|
||||
void tee_shm_free_io(struct tee_shm *shm);
|
||||
|
||||
int tee_shm_fd_for_rpc(struct tee_context *ctx, struct tee_shm_io *shm_io);
|
||||
|
||||
struct tee_shm *tee_shm_alloc(struct tee *tee, size_t size, uint32_t flags);
|
||||
void tee_shm_free(struct tee_shm *shm);
|
||||
|
||||
struct tee_shm *tee_shm_get(struct tee_context *ctx, TEEC_SharedMemory *c_shm,
|
||||
size_t size, int offset);
|
||||
void tee_shm_put(struct tee_context *ctx, struct tee_shm *shm);
|
||||
|
||||
#endif /* __TEE_SHM_H__ */
|
||||
272
security/optee_linuxdriver/core/tee_supp_com.c
Normal file
272
security/optee_linuxdriver/core/tee_supp_com.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "tee_shm.h"
|
||||
#include "tee_core.h"
|
||||
#include "tee_supp_com.h"
|
||||
|
||||
#define TEE_RPC_BUFFER 0x00000001
|
||||
#define TEE_RPC_VALUE 0x00000002
|
||||
|
||||
enum teec_rpc_result tee_supp_cmd(struct tee *tee,
|
||||
uint32_t id, void *data, size_t datalen)
|
||||
{
|
||||
struct tee_rpc *rpc = tee->rpc;
|
||||
enum teec_rpc_result res = TEEC_RPC_FAIL;
|
||||
size_t size;
|
||||
struct task_struct *task = current;
|
||||
|
||||
dev_dbg(tee->dev, "> tgid:[%d] id:[0x%08x]\n", task->tgid, id);
|
||||
|
||||
if (atomic_read(&rpc->used) == 0) {
|
||||
dev_err(tee->dev, "%s: ERROR Supplicant application NOT ready\n"
|
||||
, __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case TEE_RPC_ICMD_ALLOCATE:
|
||||
{
|
||||
struct tee_rpc_alloc *alloc;
|
||||
struct tee_shm *shmint;
|
||||
|
||||
alloc = (struct tee_rpc_alloc *)data;
|
||||
size = alloc->size;
|
||||
memset(alloc, 0, sizeof(struct tee_rpc_alloc));
|
||||
shmint = tee_shm_alloc_from_rpc(tee, size);
|
||||
if (IS_ERR_OR_NULL(shmint))
|
||||
break;
|
||||
|
||||
alloc->size = size;
|
||||
alloc->data = (void *)shmint->paddr;
|
||||
alloc->shm = shmint;
|
||||
res = TEEC_RPC_OK;
|
||||
|
||||
break;
|
||||
}
|
||||
case TEE_RPC_ICMD_FREE:
|
||||
{
|
||||
struct tee_rpc_free *free;
|
||||
|
||||
free = (struct tee_rpc_free *)data;
|
||||
tee_shm_free_from_rpc(free->shm);
|
||||
res = TEEC_RPC_OK;
|
||||
break;
|
||||
}
|
||||
case TEE_RPC_ICMD_INVOKE:
|
||||
{
|
||||
if (sizeof(rpc->commToUser) < datalen)
|
||||
break;
|
||||
|
||||
mutex_lock(&rpc->outsync);
|
||||
|
||||
memcpy(&rpc->commToUser, data, datalen);
|
||||
|
||||
mutex_unlock(&rpc->outsync);
|
||||
|
||||
dev_dbg(tee->dev,
|
||||
"Supplicant Cmd: %x. Give hand to supplicant\n",
|
||||
rpc->commToUser.cmd);
|
||||
|
||||
up(&rpc->datatouser);
|
||||
|
||||
down(&rpc->datafromuser);
|
||||
|
||||
dev_dbg(tee->dev,
|
||||
"Supplicant Cmd: %x. Give hand to fw\n",
|
||||
rpc->commToUser.cmd);
|
||||
|
||||
mutex_lock(&rpc->insync);
|
||||
|
||||
memcpy(data, &rpc->commFromUser, datalen);
|
||||
|
||||
mutex_unlock(&rpc->insync);
|
||||
|
||||
res = TEEC_RPC_OK;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* not supported */
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
dev_dbg(tee->dev, "< res: [%d]\n", res);
|
||||
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(tee_supp_cmd);
|
||||
|
||||
ssize_t tee_supp_read(struct file *filp, char __user *buffer,
|
||||
size_t length, loff_t *offset)
|
||||
{
|
||||
struct tee_context *ctx = (struct tee_context *)(filp->private_data);
|
||||
struct tee *tee;
|
||||
struct tee_rpc *rpc;
|
||||
struct task_struct *task = current;
|
||||
int ret;
|
||||
|
||||
BUG_ON(!ctx);
|
||||
tee = ctx->tee;
|
||||
BUG_ON(!tee);
|
||||
BUG_ON(!tee->dev);
|
||||
BUG_ON(!tee->rpc);
|
||||
|
||||
dev_dbg(tee->dev, "> ctx %p\n", ctx);
|
||||
|
||||
rpc = tee->rpc;
|
||||
|
||||
if (atomic_read(&rpc->used) == 0) {
|
||||
dev_err(tee->dev, "%s: ERROR Supplicant application NOT ready\n"
|
||||
, __func__);
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (down_interruptible(&rpc->datatouser))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
dev_dbg(tee->dev, "> tgid:[%d]\n", task->tgid);
|
||||
|
||||
mutex_lock(&rpc->outsync);
|
||||
|
||||
ret =
|
||||
sizeof(rpc->commToUser) - sizeof(rpc->commToUser.cmds) +
|
||||
sizeof(rpc->commToUser.cmds[0]) * rpc->commToUser.nbr_bf;
|
||||
if (length < ret) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
if (copy_to_user(buffer, &rpc->commToUser, ret)) {
|
||||
dev_err(tee->dev,
|
||||
"[%s] error, copy_to_user failed!\n", __func__);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&rpc->outsync);
|
||||
|
||||
out:
|
||||
dev_dbg(tee->dev, "< [%d]\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t tee_supp_write(struct file *filp, const char __user *buffer,
|
||||
size_t length, loff_t *offset)
|
||||
{
|
||||
struct tee_context *ctx = (struct tee_context *)(filp->private_data);
|
||||
struct tee *tee;
|
||||
struct tee_rpc *rpc;
|
||||
struct task_struct *task = current;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(!ctx);
|
||||
BUG_ON(!ctx->tee);
|
||||
BUG_ON(!ctx->tee->rpc);
|
||||
tee = ctx->tee;
|
||||
rpc = tee->rpc;
|
||||
dev_dbg(tee->dev, "> tgid:[%d]\n", task->tgid);
|
||||
|
||||
if (atomic_read(&rpc->used) == 0) {
|
||||
dev_err(tee->dev, "%s: ERROR Supplicant application NOT ready\n"
|
||||
, __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (length > 0 && length < sizeof(rpc->commFromUser)) {
|
||||
uint32_t i;
|
||||
|
||||
mutex_lock(&rpc->insync);
|
||||
|
||||
if (copy_from_user(&rpc->commFromUser, buffer, length)) {
|
||||
dev_err(tee->dev,
|
||||
"%s: ERROR, tee_session copy_from_user failed\n",
|
||||
__func__);
|
||||
mutex_unlock(&rpc->insync);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Translate virtual address of caller into physical address */
|
||||
for (i = 0; i < rpc->commFromUser.nbr_bf; i++) {
|
||||
if (rpc->commFromUser.cmds[i].type == TEE_RPC_BUFFER
|
||||
&& rpc->commFromUser.cmds[i].buffer) {
|
||||
struct vm_area_struct *vma =
|
||||
find_vma(current->mm,
|
||||
(unsigned long)rpc->
|
||||
commFromUser.cmds[i].buffer);
|
||||
if (vma != NULL) {
|
||||
struct tee_shm *shm =
|
||||
vma->vm_private_data;
|
||||
BUG_ON(!shm);
|
||||
dev_dbg(tee->dev,
|
||||
"%d gid2pa(0x%p => %x)\n", i,
|
||||
rpc->commFromUser.cmds[i].
|
||||
buffer,
|
||||
(unsigned int)shm->paddr);
|
||||
rpc->commFromUser.cmds[i].buffer =
|
||||
(void *)shm->paddr;
|
||||
} else
|
||||
dev_dbg(tee->dev,
|
||||
" gid2pa(0x%p => NULL\n)",
|
||||
rpc->commFromUser.cmds[i].
|
||||
buffer);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&rpc->insync);
|
||||
up(&rpc->datafromuser);
|
||||
ret = length;
|
||||
}
|
||||
|
||||
out:
|
||||
dev_dbg(tee->dev, "< [%d]\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tee_supp_init(struct tee *tee)
|
||||
{
|
||||
struct tee_rpc *rpc =
|
||||
devm_kzalloc(tee->dev, sizeof(struct tee_rpc), GFP_KERNEL);
|
||||
if (!rpc) {
|
||||
dev_err(tee->dev, "%s: can't allocate tee_rpc structure\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rpc->datafromuser = (struct semaphore)
|
||||
__SEMAPHORE_INITIALIZER(rpc->datafromuser, 0);
|
||||
rpc->datatouser = (struct semaphore)
|
||||
__SEMAPHORE_INITIALIZER(rpc->datatouser, 0);
|
||||
mutex_init(&rpc->outsync);
|
||||
mutex_init(&rpc->insync);
|
||||
atomic_set(&rpc->used, 0);
|
||||
tee->rpc = rpc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tee_supp_deinit(struct tee *tee)
|
||||
{
|
||||
devm_kfree(tee->dev, tee->rpc);
|
||||
tee->rpc = NULL;
|
||||
}
|
||||
111
security/optee_linuxdriver/core/tee_supp_com.h
Normal file
111
security/optee_linuxdriver/core/tee_supp_com.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_SUPP_COMM_H
|
||||
#define TEE_SUPP_COMM_H
|
||||
|
||||
#define TEE_RPC_ICMD_ALLOCATE 0x1001
|
||||
#define TEE_RPC_ICMD_FREE 0x1002
|
||||
#define TEE_RPC_ICMD_INVOKE 0x1003
|
||||
|
||||
#define TEE_RPC_NBR_BUFF 1
|
||||
#define TEE_RPC_DATA_SIZE 64
|
||||
#define TEE_RPC_BUFFER_NUMBER 5
|
||||
|
||||
#define TEE_RPC_STATE_IDLE 0x00
|
||||
#define TEE_RPC_STATE_ACTIVE 0x01
|
||||
|
||||
/* Keep aligned with optee_client (user space) */
|
||||
#define TEE_RPC_BUFFER 0x00000001
|
||||
#define TEE_RPC_VALUE 0x00000002
|
||||
#define TEE_RPC_LOAD_TA 0x10000001
|
||||
/*
|
||||
* Handled within the driver only
|
||||
* Keep aligned with optee_os (secure space)
|
||||
*/
|
||||
#define TEE_RPC_MUTEX_WAIT 0x20000000
|
||||
#define TEE_RPC_WAIT_QUEUE_SLEEP 0x20000001
|
||||
#define TEE_RPC_WAIT_QUEUE_WAKEUP 0x20000002
|
||||
#define TEE_RPC_WAIT 0x30000000
|
||||
|
||||
/* Parameters for TEE_RPC_WAIT_MUTEX above */
|
||||
#define TEE_MUTEX_WAIT_SLEEP 0
|
||||
#define TEE_MUTEX_WAIT_WAKEUP 1
|
||||
#define TEE_MUTEX_WAIT_DELETE 2
|
||||
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
/**
|
||||
* struct tee_rpc_bf - Contains definition of the tee com buffer
|
||||
* @state: Buffer state
|
||||
* @data: Command data
|
||||
*/
|
||||
struct tee_rpc_bf {
|
||||
uint32_t state;
|
||||
uint8_t data[TEE_RPC_DATA_SIZE];
|
||||
};
|
||||
|
||||
struct tee_rpc_alloc {
|
||||
uint32_t size; /* size of block */
|
||||
void *data; /* pointer to data */
|
||||
void *shm; /* pointer to an opaque data, being shm structure */
|
||||
};
|
||||
|
||||
struct tee_rpc_free {
|
||||
void *shm; /* pointer to an opaque data, being shm structure */
|
||||
};
|
||||
|
||||
struct tee_rpc_cmd {
|
||||
void *buffer;
|
||||
uint32_t size;
|
||||
uint32_t type;
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct tee_rpc_invoke {
|
||||
uint32_t cmd;
|
||||
uint32_t res;
|
||||
uint32_t nbr_bf;
|
||||
struct tee_rpc_cmd cmds[TEE_RPC_BUFFER_NUMBER];
|
||||
};
|
||||
|
||||
struct tee_rpc {
|
||||
struct tee_rpc_invoke commToUser;
|
||||
struct tee_rpc_invoke commFromUser;
|
||||
struct semaphore datatouser;
|
||||
struct semaphore datafromuser;
|
||||
struct mutex outsync; /* Out sync mutex */
|
||||
struct mutex insync; /* In sync mutex */
|
||||
struct mutex reqsync; /* Request sync mutex */
|
||||
atomic_t used;
|
||||
};
|
||||
|
||||
enum teec_rpc_result {
|
||||
TEEC_RPC_OK,
|
||||
TEEC_RPC_FAIL
|
||||
};
|
||||
|
||||
struct tee;
|
||||
|
||||
int tee_supp_init(struct tee *tee);
|
||||
void tee_supp_deinit(struct tee *tee);
|
||||
|
||||
enum teec_rpc_result tee_supp_cmd(struct tee *tee,
|
||||
uint32_t id, void *data, size_t datalen);
|
||||
|
||||
ssize_t tee_supp_read(struct file *filp, char __user *buffer,
|
||||
size_t length, loff_t *offset);
|
||||
|
||||
ssize_t tee_supp_write(struct file *filp, const char __user *buffer,
|
||||
size_t length, loff_t *offset);
|
||||
|
||||
#endif
|
||||
204
security/optee_linuxdriver/core/tee_sysfs.c
Normal file
204
security/optee_linuxdriver/core/tee_sysfs.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include "tee_core_priv.h"
|
||||
|
||||
static ssize_t dump_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
int len;
|
||||
char *tmp_buf;
|
||||
|
||||
tmp_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!tmp_buf) {
|
||||
printk(KERN_ALERT "%s : Unable to get buf memory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
len = tee_context_dump(tee, tmp_buf, PAGE_SIZE - 128);
|
||||
|
||||
if (len > 0)
|
||||
len = snprintf(buf, PAGE_SIZE, "%s", tmp_buf);
|
||||
kfree(tmp_buf);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t stat_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d/%d %d/%d %d/%d %d/%d\n",
|
||||
atomic_read(&tee->refcount),
|
||||
tee->max_refcount,
|
||||
tee->stats[TEE_STATS_CONTEXT_IDX].count,
|
||||
tee->stats[TEE_STATS_CONTEXT_IDX].max,
|
||||
tee->stats[TEE_STATS_SESSION_IDX].count,
|
||||
tee->stats[TEE_STATS_SESSION_IDX].max,
|
||||
tee->stats[TEE_STATS_SHM_IDX].count,
|
||||
tee->stats[TEE_STATS_SHM_IDX].max);
|
||||
}
|
||||
|
||||
static ssize_t info_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s iminor=%d dev=\"%s\" state=%d\n",
|
||||
dev_name(tee->dev), tee->miscdev.minor,
|
||||
dev_name(tee->miscdev.this_device), tee->state);
|
||||
}
|
||||
|
||||
static ssize_t name_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", tee->name);
|
||||
}
|
||||
|
||||
static ssize_t type_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", tee->ops->type);
|
||||
}
|
||||
|
||||
static ssize_t refcount_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&tee->refcount));
|
||||
}
|
||||
|
||||
static ssize_t conf_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "0x%08x\n", tee->conf);
|
||||
}
|
||||
|
||||
static ssize_t test_show(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%08X\n", tee->test);
|
||||
}
|
||||
|
||||
static ssize_t test_store(struct device *device,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
unsigned long val;
|
||||
int status;
|
||||
|
||||
status = kstrtoul(buf, 0, &val);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if ((tee->conf & TEE_CONF_TEST_MODE) == TEE_CONF_TEST_MODE)
|
||||
tee->test = val;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* A state-to-string lookup table, for exposing a human readable state
|
||||
* via sysfs. Always keep in sync with enum tee_state
|
||||
*/
|
||||
static const char *const tee_state_string[] = {
|
||||
"offline",
|
||||
"online",
|
||||
"suspended",
|
||||
"running",
|
||||
"crashed",
|
||||
"invalid",
|
||||
};
|
||||
|
||||
static ssize_t tee_show_state(struct device *device,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tee *tee = dev_get_drvdata(device);
|
||||
|
||||
int state = tee->state > TEE_LAST ? TEE_LAST : tee->state;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s (%d)\n", tee_state_string[state],
|
||||
tee->state);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the following, 0660 is (S_IWUGO | S_IRUGO)
|
||||
*/
|
||||
static struct device_attribute device_attrs[] = {
|
||||
__ATTR_RO(dump),
|
||||
__ATTR_RO(stat),
|
||||
__ATTR_RO(info),
|
||||
__ATTR(test, (0660), test_show, test_store),
|
||||
__ATTR(state, S_IRUGO, tee_show_state, NULL),
|
||||
__ATTR(name, S_IRUGO, name_show, NULL),
|
||||
__ATTR(refcount, S_IRUGO, refcount_show, NULL),
|
||||
__ATTR(type, S_IRUGO, type_show, NULL),
|
||||
__ATTR(conf, S_IRUGO, conf_show, NULL),
|
||||
};
|
||||
|
||||
void tee_init_sysfs(struct tee *tee)
|
||||
{
|
||||
int i, error = 0;
|
||||
|
||||
if (!tee)
|
||||
return;
|
||||
|
||||
if (dev_get_drvdata(tee->miscdev.this_device) != tee) {
|
||||
dev_err(_DEV(tee), "drvdata is not valid\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
|
||||
error =
|
||||
device_create_file(tee->miscdev.this_device,
|
||||
&device_attrs[i]);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
while (--i >= 0)
|
||||
device_remove_file(tee->miscdev.this_device,
|
||||
&device_attrs[i]);
|
||||
}
|
||||
/* location /sys/class/<class name>/<dev_name()>/<name> ->
|
||||
* /sys/class/misc/teelx00/info */
|
||||
}
|
||||
|
||||
void tee_cleanup_sysfs(struct tee *tee)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!tee)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
|
||||
device_remove_file(tee->miscdev.this_device, &device_attrs[i]);
|
||||
}
|
||||
21
security/optee_linuxdriver/core/tee_sysfs.h
Normal file
21
security/optee_linuxdriver/core/tee_sysfs.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_SYSFS_H__
|
||||
#define __TEE_SYSFS_H__
|
||||
|
||||
struct tee;
|
||||
|
||||
void tee_init_sysfs(struct tee *tee);
|
||||
void tee_cleanup_sysfs(struct tee *tee);
|
||||
|
||||
#endif
|
||||
86
security/optee_linuxdriver/core/tee_wait_queue.c
Normal file
86
security/optee_linuxdriver/core/tee_wait_queue.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/slab.h>
|
||||
#include "tee_wait_queue.h"
|
||||
|
||||
struct tee_wait_queue {
|
||||
struct list_head link;
|
||||
struct completion comp;
|
||||
u32 key;
|
||||
};
|
||||
|
||||
void tee_wait_queue_init(struct tee_wait_queue_private *priv)
|
||||
{
|
||||
mutex_init(&priv->mu);
|
||||
INIT_LIST_HEAD(&priv->db);
|
||||
}
|
||||
EXPORT_SYMBOL(tee_wait_queue_init);
|
||||
|
||||
void tee_wait_queue_exit(struct tee_wait_queue_private *priv)
|
||||
{
|
||||
mutex_destroy(&priv->mu);
|
||||
}
|
||||
EXPORT_SYMBOL(tee_wait_queue_exit);
|
||||
|
||||
static struct tee_wait_queue *tee_wait_queue_get(struct device *dev,
|
||||
struct tee_wait_queue_private *priv, u32 key)
|
||||
{
|
||||
struct tee_wait_queue *w;
|
||||
|
||||
mutex_lock(&priv->mu);
|
||||
|
||||
list_for_each_entry(w, &priv->db, link)
|
||||
if (w->key == key)
|
||||
goto out;
|
||||
|
||||
w = kmalloc(sizeof(struct tee_wait_queue), GFP_KERNEL);
|
||||
if (!w)
|
||||
goto out;
|
||||
|
||||
init_completion(&w->comp);
|
||||
w->key = key;
|
||||
list_add_tail(&w->link, &priv->db);
|
||||
out:
|
||||
mutex_unlock(&priv->mu);
|
||||
return w;
|
||||
}
|
||||
|
||||
void tee_wait_queue_sleep(struct device *dev,
|
||||
struct tee_wait_queue_private *priv, u32 key)
|
||||
{
|
||||
struct tee_wait_queue *w = tee_wait_queue_get(dev, priv, key);
|
||||
|
||||
if (!w)
|
||||
return;
|
||||
|
||||
wait_for_completion(&w->comp);
|
||||
mutex_lock(&priv->mu);
|
||||
list_del(&w->link);
|
||||
mutex_unlock(&priv->mu);
|
||||
kfree(w);
|
||||
}
|
||||
EXPORT_SYMBOL(tee_wait_queue_sleep);
|
||||
|
||||
void tee_wait_queue_wakeup(struct device *dev,
|
||||
struct tee_wait_queue_private *priv, u32 key)
|
||||
{
|
||||
struct tee_wait_queue *w = tee_wait_queue_get(dev, priv, key);
|
||||
|
||||
if (!w)
|
||||
return;
|
||||
|
||||
complete(&w->comp);
|
||||
}
|
||||
EXPORT_SYMBOL(tee_wait_queue_wakeup);
|
||||
32
security/optee_linuxdriver/core/tee_wait_queue.h
Normal file
32
security/optee_linuxdriver/core/tee_wait_queue.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_WAIT_QUEUE_H
|
||||
#define TEE_WAIT_QUEUE_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
struct tee_wait_queue_private {
|
||||
struct mutex mu;
|
||||
struct list_head db;
|
||||
};
|
||||
|
||||
void tee_wait_queue_init(struct tee_wait_queue_private *priv);
|
||||
void tee_wait_queue_exit(struct tee_wait_queue_private *priv);
|
||||
void tee_wait_queue_sleep(struct device *dev,
|
||||
struct tee_wait_queue_private *priv, u32 key);
|
||||
void tee_wait_queue_wakeup(struct device *dev,
|
||||
struct tee_wait_queue_private *priv, u32 key);
|
||||
|
||||
#endif /*TEE_WAIT_QUEUE_H*/
|
||||
202
security/optee_linuxdriver/fdts/fvp-foundation-gicv2-psci.dts
Normal file
202
security/optee_linuxdriver/fdts/fvp-foundation-gicv2-psci.dts
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the ARM nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/memreserve/ 0x81000000 0x00100000;
|
||||
/memreserve/ 0x80000000 0x00010000;
|
||||
|
||||
/ {
|
||||
};
|
||||
|
||||
/ {
|
||||
model = "FVP Foundation";
|
||||
compatible = "arm,fvp-base", "arm,vexpress";
|
||||
interrupt-parent = <&gic>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
chosen { };
|
||||
|
||||
aliases {
|
||||
serial0 = &v2m_serial0;
|
||||
serial1 = &v2m_serial1;
|
||||
serial2 = &v2m_serial2;
|
||||
serial3 = &v2m_serial3;
|
||||
};
|
||||
|
||||
psci {
|
||||
compatible = "arm,psci";
|
||||
method = "smc";
|
||||
cpu_suspend = <0xc4000001>;
|
||||
cpu_off = <0x84000002>;
|
||||
cpu_on = <0xc4000003>;
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu@0 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,armv8";
|
||||
reg = <0x0 0x0>;
|
||||
enable-method = "psci";
|
||||
};
|
||||
cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,armv8";
|
||||
reg = <0x0 0x1>;
|
||||
enable-method = "psci";
|
||||
};
|
||||
cpu@2 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,armv8";
|
||||
reg = <0x0 0x2>;
|
||||
enable-method = "psci";
|
||||
};
|
||||
cpu@3 {
|
||||
device_type = "cpu";
|
||||
compatible = "arm,armv8";
|
||||
reg = <0x0 0x3>;
|
||||
enable-method = "psci";
|
||||
};
|
||||
};
|
||||
|
||||
memory@80000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x00000000 0x80000000 0 0x7F000000>,
|
||||
<0x00000008 0x80000000 0 0x80000000>;
|
||||
};
|
||||
|
||||
gic: interrupt-controller@2f000000 {
|
||||
compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
|
||||
#interrupt-cells = <3>;
|
||||
#address-cells = <0>;
|
||||
interrupt-controller;
|
||||
reg = <0x0 0x2f000000 0 0x10000>,
|
||||
<0x0 0x2c000000 0 0x2000>,
|
||||
<0x0 0x2c010000 0 0x2000>,
|
||||
<0x0 0x2c02F000 0 0x2000>;
|
||||
interrupts = <1 9 0xf04>;
|
||||
};
|
||||
|
||||
timer {
|
||||
compatible = "arm,armv8-timer";
|
||||
interrupts = <1 13 0xff01>,
|
||||
<1 14 0xff01>,
|
||||
<1 11 0xff01>,
|
||||
<1 10 0xff01>;
|
||||
clock-frequency = <100000000>;
|
||||
};
|
||||
|
||||
timer@2a810000 {
|
||||
compatible = "arm,armv7-timer-mem";
|
||||
reg = <0x0 0x2a810000 0x0 0x10000>;
|
||||
clock-frequency = <100000000>;
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
frame@2a830000 {
|
||||
frame-number = <1>;
|
||||
interrupts = <0 26 4>;
|
||||
reg = <0x0 0x2a830000 0x0 0x10000>;
|
||||
};
|
||||
};
|
||||
|
||||
pmu {
|
||||
compatible = "arm,armv8-pmuv3";
|
||||
interrupts = <0 60 4>,
|
||||
<0 61 4>,
|
||||
<0 62 4>,
|
||||
<0 63 4>;
|
||||
};
|
||||
|
||||
smb {
|
||||
compatible = "simple-bus";
|
||||
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 0 0 0x08000000 0x04000000>,
|
||||
<1 0 0 0x14000000 0x04000000>,
|
||||
<2 0 0 0x18000000 0x04000000>,
|
||||
<3 0 0 0x1c000000 0x04000000>,
|
||||
<4 0 0 0x0c000000 0x04000000>,
|
||||
<5 0 0 0x10000000 0x04000000>;
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 63>;
|
||||
interrupt-map = <0 0 0 &gic 0 0 4>,
|
||||
<0 0 1 &gic 0 1 4>,
|
||||
<0 0 2 &gic 0 2 4>,
|
||||
<0 0 3 &gic 0 3 4>,
|
||||
<0 0 4 &gic 0 4 4>,
|
||||
<0 0 5 &gic 0 5 4>,
|
||||
<0 0 6 &gic 0 6 4>,
|
||||
<0 0 7 &gic 0 7 4>,
|
||||
<0 0 8 &gic 0 8 4>,
|
||||
<0 0 9 &gic 0 9 4>,
|
||||
<0 0 10 &gic 0 10 4>,
|
||||
<0 0 11 &gic 0 11 4>,
|
||||
<0 0 12 &gic 0 12 4>,
|
||||
<0 0 13 &gic 0 13 4>,
|
||||
<0 0 14 &gic 0 14 4>,
|
||||
<0 0 15 &gic 0 15 4>,
|
||||
<0 0 16 &gic 0 16 4>,
|
||||
<0 0 17 &gic 0 17 4>,
|
||||
<0 0 18 &gic 0 18 4>,
|
||||
<0 0 19 &gic 0 19 4>,
|
||||
<0 0 20 &gic 0 20 4>,
|
||||
<0 0 21 &gic 0 21 4>,
|
||||
<0 0 22 &gic 0 22 4>,
|
||||
<0 0 23 &gic 0 23 4>,
|
||||
<0 0 24 &gic 0 24 4>,
|
||||
<0 0 25 &gic 0 25 4>,
|
||||
<0 0 26 &gic 0 26 4>,
|
||||
<0 0 27 &gic 0 27 4>,
|
||||
<0 0 28 &gic 0 28 4>,
|
||||
<0 0 29 &gic 0 29 4>,
|
||||
<0 0 30 &gic 0 30 4>,
|
||||
<0 0 31 &gic 0 31 4>,
|
||||
<0 0 32 &gic 0 32 4>,
|
||||
<0 0 33 &gic 0 33 4>,
|
||||
<0 0 34 &gic 0 34 4>,
|
||||
<0 0 35 &gic 0 35 4>,
|
||||
<0 0 36 &gic 0 36 4>,
|
||||
<0 0 37 &gic 0 37 4>,
|
||||
<0 0 38 &gic 0 38 4>,
|
||||
<0 0 39 &gic 0 39 4>,
|
||||
<0 0 40 &gic 0 40 4>,
|
||||
<0 0 41 &gic 0 41 4>,
|
||||
<0 0 42 &gic 0 42 4>;
|
||||
|
||||
/include/ "fvp-foundation-motherboard.dtsi"
|
||||
};
|
||||
};
|
||||
197
security/optee_linuxdriver/fdts/fvp-foundation-motherboard.dtsi
Normal file
197
security/optee_linuxdriver/fdts/fvp-foundation-motherboard.dtsi
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the ARM nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
motherboard {
|
||||
arm,v2m-memory-map = "rs1";
|
||||
compatible = "arm,vexpress,v2m-p1", "simple-bus";
|
||||
#address-cells = <2>; /* SMB chipselect number and offset */
|
||||
#size-cells = <1>;
|
||||
#interrupt-cells = <1>;
|
||||
ranges;
|
||||
|
||||
ethernet@2,02000000 {
|
||||
compatible = "smsc,lan91c111";
|
||||
reg = <2 0x02000000 0x10000>;
|
||||
interrupts = <15>;
|
||||
};
|
||||
|
||||
v2m_clk24mhz: clk24mhz {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <24000000>;
|
||||
clock-output-names = "v2m:clk24mhz";
|
||||
};
|
||||
|
||||
v2m_refclk1mhz: refclk1mhz {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <1000000>;
|
||||
clock-output-names = "v2m:refclk1mhz";
|
||||
};
|
||||
|
||||
v2m_refclk32khz: refclk32khz {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
clock-output-names = "v2m:refclk32khz";
|
||||
};
|
||||
|
||||
iofpga@3,00000000 {
|
||||
compatible = "arm,amba-bus", "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0 3 0 0x200000>;
|
||||
|
||||
v2m_sysreg: sysreg@010000 {
|
||||
compatible = "arm,vexpress-sysreg";
|
||||
reg = <0x010000 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
v2m_sysctl: sysctl@020000 {
|
||||
compatible = "arm,sp810", "arm,primecell";
|
||||
reg = <0x020000 0x1000>;
|
||||
clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>;
|
||||
clock-names = "refclk", "timclk", "apb_pclk";
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
|
||||
};
|
||||
|
||||
v2m_serial0: uart@090000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x090000 0x1000>;
|
||||
interrupts = <5>;
|
||||
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial1: uart@0a0000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x0a0000 0x1000>;
|
||||
interrupts = <6>;
|
||||
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial2: uart@0b0000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x0b0000 0x1000>;
|
||||
interrupts = <7>;
|
||||
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_serial3: uart@0c0000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x0c0000 0x1000>;
|
||||
interrupts = <8>;
|
||||
clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
};
|
||||
|
||||
wdt@0f0000 {
|
||||
compatible = "arm,sp805", "arm,primecell";
|
||||
reg = <0x0f0000 0x1000>;
|
||||
interrupts = <0>;
|
||||
clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>;
|
||||
clock-names = "wdogclk", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_timer01: timer@110000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
reg = <0x110000 0x1000>;
|
||||
interrupts = <2>;
|
||||
clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>;
|
||||
clock-names = "timclken1", "timclken2", "apb_pclk";
|
||||
};
|
||||
|
||||
v2m_timer23: timer@120000 {
|
||||
compatible = "arm,sp804", "arm,primecell";
|
||||
reg = <0x120000 0x1000>;
|
||||
interrupts = <3>;
|
||||
clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>;
|
||||
clock-names = "timclken1", "timclken2", "apb_pclk";
|
||||
};
|
||||
|
||||
rtc@170000 {
|
||||
compatible = "arm,pl031", "arm,primecell";
|
||||
reg = <0x170000 0x1000>;
|
||||
interrupts = <4>;
|
||||
clocks = <&v2m_clk24mhz>;
|
||||
clock-names = "apb_pclk";
|
||||
};
|
||||
|
||||
virtio_block@0130000 {
|
||||
compatible = "virtio,mmio";
|
||||
reg = <0x130000 0x1000>;
|
||||
interrupts = <0x2a>;
|
||||
};
|
||||
};
|
||||
|
||||
v2m_fixed_3v3: fixedregulator@0 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "3V3";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
|
||||
mcc {
|
||||
compatible = "arm,vexpress,config-bus", "simple-bus";
|
||||
arm,vexpress,config-bridge = <&v2m_sysreg>;
|
||||
|
||||
reset@0 {
|
||||
compatible = "arm,vexpress-reset";
|
||||
arm,vexpress-sysreg,func = <5 0>;
|
||||
};
|
||||
|
||||
muxfpga@0 {
|
||||
compatible = "arm,vexpress-muxfpga";
|
||||
arm,vexpress-sysreg,func = <7 0>;
|
||||
};
|
||||
|
||||
shutdown@0 {
|
||||
compatible = "arm,vexpress-shutdown";
|
||||
arm,vexpress-sysreg,func = <8 0>;
|
||||
};
|
||||
|
||||
reboot@0 {
|
||||
compatible = "arm,vexpress-reboot";
|
||||
arm,vexpress-sysreg,func = <9 0>;
|
||||
};
|
||||
|
||||
dvimode@0 {
|
||||
compatible = "arm,vexpress-dvimode";
|
||||
arm,vexpress-sysreg,func = <11 0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
2
security/optee_linuxdriver/fdts/readme.txt
Normal file
2
security/optee_linuxdriver/fdts/readme.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
These files is a temporary workaround until the driver has switched
|
||||
to use CMA to allocate shared memory.
|
||||
700
security/optee_linuxdriver/include/arm_common/teesmc.h
Normal file
700
security/optee_linuxdriver/include/arm_common/teesmc.h
Normal file
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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 TEESMC_H
|
||||
#define TEESMC_H
|
||||
|
||||
#ifndef ASM
|
||||
/*
|
||||
* This section depends on uint64_t, uint32_t uint8_t already being
|
||||
* defined. Since this file is used in several different environments
|
||||
* (secure world OS and normal world Linux kernel to start with) where
|
||||
* stdint.h may not be available it's the responsibility of the one
|
||||
* including this file to provide those types.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Trusted OS SMC interface.
|
||||
*
|
||||
* The SMC interface follows SMC Calling Convention
|
||||
* (ARM_DEN0028A_SMC_Calling_Convention).
|
||||
*
|
||||
* The primary objective of this API is to provide a transport layer on
|
||||
* which a Global Platform compliant TEE interfaces can be deployed. But the
|
||||
* interface can also be used for other implementations.
|
||||
*
|
||||
* This file is divided in two parts.
|
||||
* Part 1 deals with passing parameters to Trusted Applications running in
|
||||
* a trusted OS in secure world.
|
||||
* Part 2 deals with the lower level handling of the SMC.
|
||||
*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Part 1 - passing parameters to Trusted Applications
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* Same values as TEE_PARAM_* from TEE Internal API
|
||||
*/
|
||||
#define TEESMC_ATTR_TYPE_NONE 0
|
||||
#define TEESMC_ATTR_TYPE_VALUE_INPUT 1
|
||||
#define TEESMC_ATTR_TYPE_VALUE_OUTPUT 2
|
||||
#define TEESMC_ATTR_TYPE_VALUE_INOUT 3
|
||||
#define TEESMC_ATTR_TYPE_MEMREF_INPUT 5
|
||||
#define TEESMC_ATTR_TYPE_MEMREF_OUTPUT 6
|
||||
#define TEESMC_ATTR_TYPE_MEMREF_INOUT 7
|
||||
|
||||
#define TEESMC_ATTR_TYPE_MASK 0x7
|
||||
|
||||
/*
|
||||
* Meta parameter to be absorbed by the Secure OS and not passed
|
||||
* to the Trusted Application.
|
||||
*
|
||||
* One example of this is a struct teesmc_meta_open_session which
|
||||
* is added to TEESMC{32,64}_CMD_OPEN_SESSION.
|
||||
*/
|
||||
#define TEESMC_ATTR_META 0x8
|
||||
|
||||
/*
|
||||
* Used as an indication from normal world of compatible cache usage.
|
||||
* 'I' stands for inner cache and 'O' for outer cache.
|
||||
*/
|
||||
#define TEESMC_ATTR_CACHE_I_NONCACHE 0x0
|
||||
#define TEESMC_ATTR_CACHE_I_WRITE_THR 0x1
|
||||
#define TEESMC_ATTR_CACHE_I_WRITE_BACK 0x2
|
||||
#define TEESMC_ATTR_CACHE_O_NONCACHE 0x0
|
||||
#define TEESMC_ATTR_CACHE_O_WRITE_THR 0x4
|
||||
#define TEESMC_ATTR_CACHE_O_WRITE_BACK 0x8
|
||||
|
||||
#define TEESMC_ATTR_CACHE_NONCACHE (TEESMC_ATTR_CACHE_I_NONCACHE | \
|
||||
TEESMC_ATTR_CACHE_O_NONCACHE)
|
||||
#define TEESMC_ATTR_CACHE_DEFAULT (TEESMC_ATTR_CACHE_I_WRITE_BACK | \
|
||||
TEESMC_ATTR_CACHE_O_WRITE_BACK)
|
||||
|
||||
#define TEESMC_ATTR_CACHE_SHIFT 4
|
||||
#define TEESMC_ATTR_CACHE_MASK 0xf
|
||||
|
||||
#define TEESMC_CMD_OPEN_SESSION 0
|
||||
#define TEESMC_CMD_INVOKE_COMMAND 1
|
||||
#define TEESMC_CMD_CLOSE_SESSION 2
|
||||
#define TEESMC_CMD_CANCEL 3
|
||||
|
||||
/**
|
||||
* struct teesmc32_param_memref - memory reference
|
||||
* @buf_ptr: Address of the buffer
|
||||
* @size: Size of the buffer
|
||||
*
|
||||
* Secure and normal world communicates pointer via physical address instead of
|
||||
* the virtual address with is usually used for pointers. This is because
|
||||
* Secure and normal world has completely independant memory mapping. Normal
|
||||
* world can even have a hypervisor which need to translate the guest
|
||||
* physical address (AKA IPA in ARM lingo) to a real physical address
|
||||
* before passing the structure to secure world.
|
||||
*/
|
||||
struct teesmc32_param_memref {
|
||||
uint32_t buf_ptr;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct teesmc32_param_memref - memory reference
|
||||
* @buf_ptr: Address of the buffer
|
||||
* @size: Size of the buffer
|
||||
*
|
||||
* See description of struct teesmc32_param_memref.
|
||||
*/
|
||||
struct teesmc64_param_memref {
|
||||
uint64_t buf_ptr;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct teesmc32_param_value - values
|
||||
* @a: first value
|
||||
* @b: second value
|
||||
*/
|
||||
struct teesmc32_param_value {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct teesmc64_param_value - values
|
||||
* @a: first value
|
||||
* @b: second value
|
||||
*/
|
||||
struct teesmc64_param_value {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct teesmc32_param - parameter
|
||||
* @attr: attributes
|
||||
* @memref: a memory reference
|
||||
* @value: a value
|
||||
*
|
||||
* attr & TEESMC_ATTR_TYPE_MASK indicates if memref or value is used in the
|
||||
* union. TEESMC_ATTR_TYPE_VALUE_* indicates value and
|
||||
* TEESMC_ATTR_TYPE_MEMREF_* indicates memref. TEESMC_ATTR_TYPE_NONE
|
||||
* indicates that none of the members are used.
|
||||
*/
|
||||
struct teesmc32_param {
|
||||
uint32_t attr;
|
||||
union {
|
||||
struct teesmc32_param_memref memref;
|
||||
struct teesmc32_param_value value;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct teesmc64_param - parameter
|
||||
* @attr: attributes
|
||||
* @memref: a memory reference
|
||||
* @value: a value
|
||||
*
|
||||
* See description of union teesmc32_param.
|
||||
*/
|
||||
struct teesmc64_param {
|
||||
uint64_t attr;
|
||||
union {
|
||||
struct teesmc64_param_memref memref;
|
||||
struct teesmc64_param_value value;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct teesmc32_arg - SMC argument for Trusted OS
|
||||
* @cmd: Command, one of TEESMC_CMD_*
|
||||
* @ta_func: Trusted Application function, specific to the Trusted Application,
|
||||
* used if cmd == TEESMC_CMD_INVOKE_COMMAND
|
||||
* @session: In parameter for all TEESMC_CMD_* except
|
||||
* TEESMC_CMD_OPEN_SESSION where it's an output paramter instead
|
||||
* @ret: return value
|
||||
* @ret_origin: origin of the return value
|
||||
* @num_params: number of parameters supplied to the OS Command
|
||||
* @params: the parameters supplied to the OS Command
|
||||
*
|
||||
* All normal SMC calls to Trusted OS uses this struct. If cmd requires
|
||||
* further information than what these field holds it can be passed as a
|
||||
* parameter tagged as meta (setting the TEESMC_ATTR_META bit in
|
||||
* corresponding param_attrs). This is used for TEESMC_CMD_OPEN_SESSION
|
||||
* to pass a struct teesmc32_meta_open_session which is needed find the
|
||||
* Trusted Application and to indicate the credentials of the client.
|
||||
*/
|
||||
struct teesmc32_arg {
|
||||
uint32_t cmd;
|
||||
uint32_t ta_func;
|
||||
uint32_t session;
|
||||
uint32_t ret;
|
||||
uint32_t ret_origin;
|
||||
uint32_t num_params;
|
||||
/*
|
||||
* Commented out elements used to visualize the layout dynamic part
|
||||
* of the struct. Note that these fields are not available at all
|
||||
* if num_params == 0.
|
||||
*
|
||||
* params is accessed through the macro TEESMC32_GET_PARAMS
|
||||
*/
|
||||
|
||||
/* struct teesmc32_param params[num_params]; */
|
||||
};
|
||||
|
||||
/**
|
||||
* TEESMC32_GET_PARAMS - return pointer to union teesmc32_param *
|
||||
*
|
||||
* @x: Pointer to a struct teesmc32_arg
|
||||
*
|
||||
* Returns a pointer to the params[] inside a struct teesmc32_arg.
|
||||
*/
|
||||
#define TEESMC32_GET_PARAMS(x) \
|
||||
(struct teesmc32_param *)(((struct teesmc32_arg *)(x)) + 1)
|
||||
|
||||
/**
|
||||
* TEESMC32_GET_ARG_SIZE - return size of struct teesmc32_arg
|
||||
*
|
||||
* @num_params: Number of parameters embedded in the struct teesmc32_arg
|
||||
*
|
||||
* Returns the size of the struct teesmc32_arg together with the number
|
||||
* of embedded paramters.
|
||||
*/
|
||||
#define TEESMC32_GET_ARG_SIZE(num_params) \
|
||||
(sizeof(struct teesmc32_arg) + \
|
||||
sizeof(struct teesmc32_param) * (num_params))
|
||||
|
||||
/**
|
||||
* struct teesmc64_arg - SMC argument for Trusted OS
|
||||
* @cmd: OS Command, one of TEESMC_CMD_*
|
||||
* @ta_func: Trusted Application function, specific to the Trusted Application
|
||||
* @session: In parameter for all TEESMC_CMD_* but
|
||||
* TEESMC_CMD_OPEN_SESSION
|
||||
* @ret: return value
|
||||
* @ret_origin: origin of the return value
|
||||
* @num_params: number of parameters supplied to the OS Command
|
||||
* @params: the parameters supplied to the OS Command
|
||||
*
|
||||
* See description of struct teesmc32_arg.
|
||||
*/
|
||||
struct teesmc64_arg {
|
||||
uint64_t cmd;
|
||||
uint64_t ta_func;
|
||||
uint64_t session;
|
||||
uint64_t ret;
|
||||
uint64_t ret_origin;
|
||||
uint64_t num_params;
|
||||
/*
|
||||
* Commented out elements used to visualize the layout dynamic part
|
||||
* of the struct. Note that these fields are not available at all
|
||||
* if num_params == 0.
|
||||
*
|
||||
* params is accessed through the macro TEESMC64_GET_PARAMS
|
||||
*/
|
||||
|
||||
/* struct teesmc64_param params[num_params]; */
|
||||
};
|
||||
|
||||
/**
|
||||
* TEESMC64_GET_PARAMS - return pointer to union teesmc64_param *
|
||||
*
|
||||
* @x: Pointer to a struct teesmc64_arg
|
||||
*
|
||||
* Returns a pointer to the params[] inside a struct teesmc64_arg.
|
||||
*/
|
||||
#define TEESMC64_GET_PARAMS(x) \
|
||||
(struct teesmc64_param *)(((struct teesmc64_arg *)(x)) + 1)
|
||||
|
||||
/**
|
||||
* TEESMC64_GET_ARG_SIZE - return size of struct teesmc64_arg
|
||||
*
|
||||
* @num_params: Number of parameters embedded in the struct teesmc64_arg
|
||||
*
|
||||
* Returns the size of the struct teesmc64_arg together with the number
|
||||
* of embedded paramters.
|
||||
*/
|
||||
#define TEESMC64_GET_ARG_SIZE(num_params) \
|
||||
(sizeof(struct teesmc64_arg) + \
|
||||
sizeof(union teesmc64_param) * (num_params))
|
||||
|
||||
#define TEESMC_UUID_LEN 16
|
||||
|
||||
/**
|
||||
* struct teesmc_meta_open_session - additional parameters for
|
||||
* TEESMC32_CMD_OPEN_SESSION and
|
||||
* TEESMC64_CMD_OPEN_SESSION
|
||||
* @uuid: UUID of the Trusted Application
|
||||
* @clnt_uuid: UUID of client
|
||||
* @clnt_login: Login class of client, TEE_LOGIN_* if being Global Platform
|
||||
* compliant
|
||||
*
|
||||
* This struct is passed in the first parameter as an input memref tagged
|
||||
* as meta on an TEESMC{32,64}_CMD_OPEN_SESSION cmd. It's important
|
||||
* that it really is the first parameter to make it easy for an eventual
|
||||
* hypervisor to inspect and possibly update clnt_* values.
|
||||
*/
|
||||
struct teesmc_meta_open_session {
|
||||
uint8_t uuid[TEESMC_UUID_LEN];
|
||||
uint8_t clnt_uuid[TEESMC_UUID_LEN];
|
||||
uint32_t clnt_login;
|
||||
};
|
||||
|
||||
|
||||
#endif /*!ASM*/
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Part 2 - low level SMC interaction
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
#define TEESMC_32 0
|
||||
#define TEESMC_64 0x40000000
|
||||
#define TEESMC_FAST_CALL 0x80000000
|
||||
#define TEESMC_STD_CALL 0
|
||||
|
||||
#define TEESMC_OWNER_MASK 0x3F
|
||||
#define TEESMC_OWNER_SHIFT 24
|
||||
|
||||
#define TEESMC_FUNC_MASK 0xFFFF
|
||||
|
||||
#define TEESMC_IS_FAST_CALL(smc_val) ((smc_val) & TEESMC_FAST_CALL)
|
||||
#define TEESMC_IS_64(smc_val) ((smc_val) & TEESMC_64)
|
||||
#define TEESMC_FUNC_NUM(smc_val) ((smc_val) & TEESMC_FUNC_MASK)
|
||||
#define TEESMC_OWNER_NUM(smc_val) (((smc_val) >> TEESMC_OWNER_SHIFT) & \
|
||||
TEESMC_OWNER_MASK)
|
||||
|
||||
#define TEESMC_CALL_VAL(type, calling_convention, owner, func_num) \
|
||||
((type) | (calling_convention) | \
|
||||
(((owner) & TEESMC_OWNER_MASK) << TEESMC_OWNER_SHIFT) |\
|
||||
((func_num) & TEESMC_FUNC_MASK))
|
||||
|
||||
#define TEESMC_OWNER_ARCH 0
|
||||
#define TEESMC_OWNER_CPU 1
|
||||
#define TEESMC_OWNER_SIP 2
|
||||
#define TEESMC_OWNER_OEM 3
|
||||
#define TEESMC_OWNER_STANDARD 4
|
||||
#define TEESMC_OWNER_TRUSTED_APP 48
|
||||
#define TEESMC_OWNER_TRUSTED_OS 50
|
||||
|
||||
#define TEESMC_OWNER_TRUSTED_OS_API 63
|
||||
|
||||
/*
|
||||
* Function specified by SMC Calling convention.
|
||||
*/
|
||||
#define TEESMC32_FUNCID_CALLS_COUNT 0xFF00
|
||||
#define TEESMC32_CALLS_COUNT \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, \
|
||||
TEESMC_OWNER_TRUSTED_OS_API, \
|
||||
TEESMC32_FUNCID_CALLS_COUNT)
|
||||
|
||||
/*
|
||||
* Function specified by SMC Calling convention
|
||||
*
|
||||
* Return one of the following UIDs if using API specified in this file
|
||||
* without further extentions:
|
||||
* 65cb6b93-af0c-4617-8ed6-644a8d1140f8 : Only 32 bit calls are supported
|
||||
* 65cb6b93-af0c-4617-8ed6-644a8d1140f9 : Both 32 and 64 bit calls are supported
|
||||
*/
|
||||
#define TEESMC_UID_R0 0x65cb6b93
|
||||
#define TEESMC_UID_R1 0xaf0c4617
|
||||
#define TEESMC_UID_R2 0x8ed6644a
|
||||
#define TEESMC_UID32_R3 0x8d1140f8
|
||||
#define TEESMC_UID64_R3 0x8d1140f9
|
||||
#define TEESMC32_FUNCID_CALLS_UID 0xFF01
|
||||
#define TEESMC32_CALLS_UID \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, \
|
||||
TEESMC_OWNER_TRUSTED_OS_API, \
|
||||
TEESMC32_FUNCID_CALLS_UID)
|
||||
|
||||
/*
|
||||
* Function specified by SMC Calling convention
|
||||
*
|
||||
* Returns 1.0 if using API specified in this file without further extentions.
|
||||
*/
|
||||
#define TEESMC_REVISION_MAJOR 1
|
||||
#define TEESMC_REVISION_MINOR 0
|
||||
#define TEESMC32_FUNCID_CALLS_REVISION 0xFF03
|
||||
#define TEESMC32_CALLS_REVISION \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, \
|
||||
TEESMC_OWNER_TRUSTED_OS_API, \
|
||||
TEESMC32_FUNCID_CALLS_REVISION)
|
||||
|
||||
/*
|
||||
* Get UUID of Trusted OS.
|
||||
*
|
||||
* Used by non-secure world to figure out which Trusted OS is installed.
|
||||
* Note that returned UUID is the UUID of the Trusted OS, not of the API.
|
||||
*
|
||||
* Returns UUID in r0-4/w0-4 in the same way as TEESMC32_CALLS_UID
|
||||
* described above.
|
||||
*/
|
||||
#define TEESMC_FUNCID_GET_OS_UUID 0
|
||||
#define TEESMC32_CALL_GET_OS_UUID \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_GET_OS_UUID)
|
||||
|
||||
/*
|
||||
* Get revision of Trusted OS.
|
||||
*
|
||||
* Used by non-secure world to figure out which version of the Trusted OS
|
||||
* is installed. Note that the returned revision is the revision of the
|
||||
* Trusted OS, not of the API.
|
||||
*
|
||||
* Returns revision in r0-1/w0-1 in the same way as TEESMC32_CALLS_REVISION
|
||||
* described above.
|
||||
*/
|
||||
#define TEESMC_FUNCID_GET_OS_REVISION 1
|
||||
#define TEESMC32_CALL_GET_OS_REVISION \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_GET_OS_REVISION)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Call with struct teesmc32_arg as argument
|
||||
*
|
||||
* Call register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_WITH_ARG
|
||||
* r1/x1 Physical pointer to a struct teesmc32_arg
|
||||
* r2-6/x2-6 Not used
|
||||
* r7/x7 Hypervisor Client ID register
|
||||
*
|
||||
* Normal return register usage:
|
||||
* r0/x0 Return value, TEESMC_RETURN_*
|
||||
* r1-3/x1-3 Not used
|
||||
* r4-7/x4-7 Preserved
|
||||
*
|
||||
* Ebusy return register usage:
|
||||
* r0/x0 Return value, TEESMC_RETURN_EBUSY
|
||||
* r1-3/x1-3 Preserved
|
||||
* r4-7/x4-7 Preserved
|
||||
*
|
||||
* RPC return register usage:
|
||||
* r0/x0 Return value, TEESMC_RETURN_IS_RPC(val)
|
||||
* r1-2/x1-2 RPC parameters
|
||||
* r3-7/x3-7 Resume information, must be preserved
|
||||
*
|
||||
* Possible return values:
|
||||
* TEESMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this
|
||||
* function.
|
||||
* TEESMC_RETURN_OK Call completed, result updated in
|
||||
* the previously supplied struct
|
||||
* teesmc32_arg.
|
||||
* TEESMC_RETURN_EBUSY Trusted OS busy, try again later.
|
||||
* TEESMC_RETURN_EBADADDR Bad physcial pointer to struct
|
||||
* teesmc32_arg.
|
||||
* TEESMC_RETURN_EBADCMD Bad/unknown cmd in struct teesmc32_arg
|
||||
* TEESMC_RETURN_IS_RPC() Call suspended by RPC call to normal
|
||||
* world.
|
||||
*/
|
||||
#define TEESMC_FUNCID_CALL_WITH_ARG 2
|
||||
#define TEESMC32_CALL_WITH_ARG \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_STD_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_CALL_WITH_ARG)
|
||||
/* Same as TEESMC32_CALL_WITH_ARG but a "fast call". */
|
||||
#define TEESMC32_FASTCALL_WITH_ARG \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_CALL_WITH_ARG)
|
||||
|
||||
/*
|
||||
* Call with struct teesmc64_arg as argument
|
||||
*
|
||||
* See description of TEESMC32_CALL_WITH_ARG above, uses struct
|
||||
* teesmc64_arg in x1 instead.
|
||||
*/
|
||||
#define TEESMC64_CALL_WITH_ARG \
|
||||
TEESMC_CALL_VAL(TEESMC_64, TEESMC_STD_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_CALL_WITH_ARG)
|
||||
/* Same as TEESMC64_CALL_WITH_ARG but a "fast call". */
|
||||
#define TEESMC64_FASTCALL_WITH_ARG \
|
||||
TEESMC_CALL_VAL(TEESMC_64, TEESMC_FAST_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_CALL_WITH_ARG)
|
||||
|
||||
/*
|
||||
* Resume from RPC (for example after processing an IRQ)
|
||||
*
|
||||
* Call register usage:
|
||||
* r0/x0 SMC Function ID,
|
||||
* TEESMC32_CALL_RETURN_FROM_RPC or
|
||||
* TEESMC32_FASTCALL_RETURN_FROM_RPC
|
||||
* r1-3/x1-3 Value of r1-3/x1-3 when TEESMC32_CALL_WITH_ARG returned
|
||||
* TEESMC_RETURN_RPC in r0/x0
|
||||
*
|
||||
* Return register usage is the same as for TEESMC32_CALL_WITH_ARG above.
|
||||
*
|
||||
* Possible return values
|
||||
* TEESMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this
|
||||
* function.
|
||||
* TEESMC_RETURN_OK Original call completed, result
|
||||
* updated in the previously supplied.
|
||||
* struct teesmc32_arg
|
||||
* TEESMC_RETURN_RPC Call suspended by RPC call to normal
|
||||
* world.
|
||||
* TEESMC_RETURN_EBUSY Trusted OS busy, try again later.
|
||||
* TEESMC_RETURN_ERESUME Resume failed, the opaque resume
|
||||
* information was corrupt.
|
||||
*/
|
||||
#define TEESMC_FUNCID_RETURN_FROM_RPC 3
|
||||
#define TEESMC32_CALL_RETURN_FROM_RPC \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_STD_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_RETURN_FROM_RPC)
|
||||
/* Same as TEESMC32_CALL_RETURN_FROM_RPC but a "fast call". */
|
||||
#define TEESMC32_FASTCALL_RETURN_FROM_RPC \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_RETURN_FROM_RPC)
|
||||
|
||||
/*
|
||||
* Resume from RPC (for example after processing an IRQ)
|
||||
*
|
||||
* See description of TEESMC32_CALL_RETURN_FROM_RPC above, used when
|
||||
* it's a 64bit call that has returned.
|
||||
*/
|
||||
#define TEESMC64_CALL_RETURN_FROM_RPC \
|
||||
TEESMC_CALL_VAL(TEESMC_64, TEESMC_STD_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_RETURN_FROM_RPC)
|
||||
/* Same as TEESMC64_CALL_RETURN_FROM_RPC but a "fast call". */
|
||||
#define TEESMC64_FASTCALL_RETURN_FROM_RPC \
|
||||
TEESMC_CALL_VAL(TEESMC_64, TEESMC_FAST_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_RETURN_FROM_RPC)
|
||||
|
||||
/*
|
||||
* From secure monitor to Trusted OS, handle FIQ
|
||||
*
|
||||
* A virtual call which is injected by the Secure Monitor when an FIQ is
|
||||
* raised while in normal world (SCR_NS is set). The monitor restores
|
||||
* secure architecture registers and secure EL_SP1 and jumps to previous
|
||||
* secure EL3_ELR. Trusted OS should preserve all general purpose
|
||||
* registers.
|
||||
*
|
||||
* Call register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_HANDLE_FIQ
|
||||
* r1-7/x1-7 Not used, but must be preserved
|
||||
*
|
||||
* Return register usage:
|
||||
* Note used
|
||||
*/
|
||||
#define TEESMC_FUNCID_CALL_HANDLE_FIQ 0xf000
|
||||
#define TEESMC32_CALL_HANDLE_FIQ \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_FUNCID_CALL_HANDLE_FIQ)
|
||||
|
||||
#define TEESMC_RETURN_RPC_PREFIX_MASK 0xFFFF0000
|
||||
#define TEESMC_RETURN_RPC_PREFIX 0xFFFF0000
|
||||
#define TEESMC_RETURN_RPC_FUNC_MASK 0x0000FFFF
|
||||
|
||||
#define TEESMC_RETURN_GET_RPC_FUNC(ret) ((ret) & TEESMC_RETURN_RPC_FUNC_MASK)
|
||||
|
||||
#define TEESMC_RPC_VAL(func) ((func) | TEESMC_RETURN_RPC_PREFIX)
|
||||
|
||||
/*
|
||||
* Allocate argument memory for RPC parameter passing.
|
||||
* Argument memory is used to hold a struct teesmc32_arg.
|
||||
*
|
||||
* "Call" register usage:
|
||||
* r0/x0 This value, TEESMC_RETURN_RPC_ALLOC
|
||||
* r1/x1 Size in bytes of required argument memory
|
||||
* r2-7/x2-7 Resume information, must be preserved
|
||||
*
|
||||
* "Return" register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_RETURN_FROM_RPC if it was an
|
||||
* AArch32 SMC return or TEESMC64_CALL_RETURN_FROM_RPC for
|
||||
* AArch64 SMC return
|
||||
* r1/x1 Physical pointer to allocated argument memory, 0 if size
|
||||
* was 0 or if memory can't be allocated
|
||||
* r2-7/x2-7 Preserved
|
||||
*/
|
||||
#define TEESMC_RPC_FUNC_ALLOC_ARG 0
|
||||
#define TEESMC_RETURN_RPC_ALLOC_ARG \
|
||||
TEESMC_RPC_VAL(TEESMC_RPC_FUNC_ALLOC_ARG)
|
||||
|
||||
/*
|
||||
* Allocate payload memory for RPC parameter passing.
|
||||
* Payload memory is used to hold the memory referred to by struct
|
||||
* teesmc32_param_memref.
|
||||
*
|
||||
* "Call" register usage:
|
||||
* r0/x0 This value, TEESMC_RETURN_RPC_ALLOC
|
||||
* r1/x1 Size in bytes of required payload memory
|
||||
* r2-7/x2-7 Resume information, must be preserved
|
||||
*
|
||||
* "Return" register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_RETURN_FROM_RPC if it was an
|
||||
* AArch32 SMC return or TEESMC64_CALL_RETURN_FROM_RPC for
|
||||
* AArch64 SMC return
|
||||
* r1/x1 Physical pointer to allocated payload memory, 0 if size
|
||||
* was 0 or if memory can't be allocated
|
||||
* r2-7/x2-7 Preserved
|
||||
*/
|
||||
#define TEESMC_RPC_FUNC_ALLOC_PAYLOAD 1
|
||||
#define TEESMC_RETURN_RPC_ALLOC_PAYLOAD \
|
||||
TEESMC_RPC_VAL(TEESMC_RPC_FUNC_ALLOC_PAYLOAD)
|
||||
|
||||
/*
|
||||
* Free memory previously allocated by TEESMC_RETURN_RPC_ALLOC_ARG.
|
||||
*
|
||||
* "Call" register usage:
|
||||
* r0/x0 This value, TEESMC_RETURN_RPC_FREE
|
||||
* r1/x1 Physical pointer to previously allocated argument memory
|
||||
* r2-7/x2-7 Resume information, must be preserved
|
||||
*
|
||||
* "Return" register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_RETURN_FROM_RPC if it was an
|
||||
* AArch32 SMC return or TEESMC64_CALL_RETURN_FROM_RPC for
|
||||
* AArch64 SMC return
|
||||
* r1/x1 Not used
|
||||
* r2-7/x2-7 Preserved
|
||||
*/
|
||||
#define TEESMC_RPC_FUNC_FREE_ARG 2
|
||||
#define TEESMC_RETURN_RPC_FREE_ARG TEESMC_RPC_VAL(TEESMC_RPC_FUNC_FREE_ARG)
|
||||
|
||||
/*
|
||||
* Free memory previously allocated by TEESMC_RETURN_RPC_ALLOC_PAYLOAD.
|
||||
*
|
||||
* "Call" register usage:
|
||||
* r0/x0 This value, TEESMC_RETURN_RPC_FREE
|
||||
* r1/x1 Physical pointer to previously allocated payload memory
|
||||
* r3-7/x3-7 Resume information, must be preserved
|
||||
*
|
||||
* "Return" register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_RETURN_FROM_RPC if it was an
|
||||
* AArch32 SMC return or TEESMC64_CALL_RETURN_FROM_RPC for
|
||||
* AArch64 SMC return
|
||||
* r1-2/x1-2 Not used
|
||||
* r3-7/x3-7 Preserved
|
||||
*/
|
||||
#define TEESMC_RPC_FUNC_FREE_PAYLOAD 3
|
||||
#define TEESMC_RETURN_RPC_FREE_PAYLOAD \
|
||||
TEESMC_RPC_VAL(TEESMC_RPC_FUNC_FREE_PAYLOAD)
|
||||
|
||||
/*
|
||||
* Deliver an IRQ in normal world.
|
||||
*
|
||||
* "Call" register usage:
|
||||
* r0/x0 TEESMC_RETURN_RPC_IRQ
|
||||
* r1-7/x1-7 Resume information, must be preserved
|
||||
*
|
||||
* "Return" register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_RETURN_FROM_RPC if it was an
|
||||
* AArch32 SMC return or TEESMC64_CALL_RETURN_FROM_RPC for
|
||||
* AArch64 SMC return
|
||||
* r1-7/x1-7 Preserved
|
||||
*/
|
||||
#define TEESMC_RPC_FUNC_IRQ 4
|
||||
#define TEESMC_RETURN_RPC_IRQ TEESMC_RPC_VAL(TEESMC_RPC_FUNC_IRQ)
|
||||
|
||||
/*
|
||||
* Do an RPC request. The supplied struct teesmc{32,64}_arg tells which
|
||||
* request to do and the paramters for the request. The following fields
|
||||
* are used (the rest are unused):
|
||||
* - cmd the Request ID
|
||||
* - ret return value of the request, filled in by normal world
|
||||
* - num_params number of parameters for the request
|
||||
* - params the parameters
|
||||
* - param_attrs attributes of the parameters
|
||||
*
|
||||
* "Call" register usage:
|
||||
* r0/x0 TEESMC_RETURN_RPC_CMD
|
||||
* r1/x1 Physical pointer to a struct teesmc32_arg if returning from
|
||||
* a AArch32 SMC or a struct teesmc64_arg if returning from a
|
||||
* AArch64 SMC, must be preserved, only the data should
|
||||
* be updated
|
||||
* r2-7/x2-7 Resume information, must be preserved
|
||||
*
|
||||
* "Return" register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_RETURN_FROM_RPC if it was an
|
||||
* AArch32 SMC return or TEESMC64_CALL_RETURN_FROM_RPC for
|
||||
* AArch64 SMC return
|
||||
* r1-7/x1-7 Preserved
|
||||
*/
|
||||
#define TEESMC_RPC_FUNC_CMD 5
|
||||
#define TEESMC_RETURN_RPC_CMD TEESMC_RPC_VAL(TEESMC_RPC_FUNC_CMD)
|
||||
|
||||
|
||||
/* Returned in r0 */
|
||||
#define TEESMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF
|
||||
|
||||
/* Returned in r0 only from Trusted OS functions */
|
||||
#define TEESMC_RETURN_OK 0x0
|
||||
#define TEESMC_RETURN_EBUSY 0x1
|
||||
#define TEESMC_RETURN_ERESUME 0x2
|
||||
#define TEESMC_RETURN_EBADADDR 0x3
|
||||
#define TEESMC_RETURN_EBADCMD 0x4
|
||||
#define TEESMC_RETURN_IS_RPC(ret) \
|
||||
(((ret) & TEESMC_RETURN_RPC_PREFIX_MASK) == TEESMC_RETURN_RPC_PREFIX)
|
||||
|
||||
/*
|
||||
* Returned in r1 by Trusted OS functions if r0 = TEESMC_RETURN_RPC
|
||||
*/
|
||||
#define TEESMC_RPC_REQUEST_IRQ 0x0
|
||||
|
||||
#endif /* TEESMC_H */
|
||||
147
security/optee_linuxdriver/include/arm_common/teesmc_st.h
Normal file
147
security/optee_linuxdriver/include/arm_common/teesmc_st.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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 TEESMC_ST_H
|
||||
#define TEESMC_ST_H
|
||||
|
||||
#define TEESMC_ST_RETURN_NOTAVAIL 0x5700
|
||||
|
||||
/*
|
||||
* Get Shared Memory Config
|
||||
*
|
||||
* Returns the Secure/Non-secure shared memory config.
|
||||
*
|
||||
* Call register usage:
|
||||
* r0 SMC Function ID, TEESMC32_ST_FASTCALL_GET_SHM_CONFIG
|
||||
* r1-6 Not used
|
||||
* r7 Hypervisor Client ID register
|
||||
*
|
||||
* Have config return register usage:
|
||||
* r0 TEESMC_RETURN_OK
|
||||
* r1 Physical address of start of SHM
|
||||
* r2 Size of of SHM
|
||||
* r3 1 if SHM is cached, 0 if uncached.
|
||||
* r4-7 Preserved
|
||||
*
|
||||
* Not available register usage:
|
||||
* r0 TEESMC_ST_RETURN_NOTAVAIL
|
||||
* r1-3 Not used
|
||||
* r4-7 Preserved
|
||||
*/
|
||||
#define TEESMC_ST_FUNCID_GET_SHM_CONFIG 0x5700
|
||||
#define TEESMC32_ST_FASTCALL_GET_SHM_CONFIG \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_ST_FUNCID_GET_SHM_CONFIG)
|
||||
|
||||
/*
|
||||
* Configures TZ/NS shared mutex for outer cache maintenance
|
||||
*
|
||||
* Disables, enables usage of outercache mutex.
|
||||
* Returns or sets physical address of outercache mutex.
|
||||
*
|
||||
* Call register usage:
|
||||
* r0 SMC Function ID, TEESMC32_ST_FASTCALL_L2CC_MUTEX
|
||||
* r1 TEESMC_ST_L2CC_MUTEX_GET_ADDR Get physical address of mutex
|
||||
* TEESMC_ST_L2CC_MUTEX_SET_ADDR Set physical address of mutex
|
||||
* TEESMC_ST_L2CC_MUTEX_ENABLE Enable usage of mutex
|
||||
* TEESMC_ST_L2CC_MUTEX_DISABLE Disable usage of mutex
|
||||
* r2 if r1 == TEESMC_ST_L2CC_MUTEX_SET_ADDR, physical address of mutex
|
||||
* r3-6 Not used
|
||||
* r7 Hypervisor Client ID register
|
||||
*
|
||||
* Have config return register usage:
|
||||
* r0 TEESMC_RETURN_OK
|
||||
* r1 Preserved
|
||||
* r2 if r1 == 0, physical address of L2CC mutex
|
||||
* r3-7 Preserved
|
||||
*
|
||||
* Error return register usage:
|
||||
* r0 TEESMC_ST_RETURN_NOTAVAIL Physical address not available
|
||||
* TEESMC_RETURN_EBADADDR Bad supplied physical address
|
||||
* TEESMC_RETURN_EBADCMD Unsupported value in r1
|
||||
* r1-7 Preserved
|
||||
*/
|
||||
#define TEESMC_ST_L2CC_MUTEX_GET_ADDR 0
|
||||
#define TEESMC_ST_L2CC_MUTEX_SET_ADDR 1
|
||||
#define TEESMC_ST_L2CC_MUTEX_ENABLE 2
|
||||
#define TEESMC_ST_L2CC_MUTEX_DISABLE 3
|
||||
#define TEESMC_ST_FUNCID_L2CC_MUTEX 0x5701
|
||||
#define TEESMC32_ST_FASTCALL_L2CC_MUTEX \
|
||||
TEESMC_CALL_VAL(TEESMC_32, TEESMC_FAST_CALL, TEESMC_OWNER_TRUSTED_OS, \
|
||||
TEESMC_ST_FUNCID_L2CC_MUTEX)
|
||||
|
||||
/*
|
||||
* Allocate payload memory for RPC parameter passing.
|
||||
*
|
||||
* "Call" register usage:
|
||||
* r0/x0 This value, TEESMC_RETURN_ST_RPC_ALLOC_PAYLOAD
|
||||
* r1/x1 Size in bytes of required payload memory
|
||||
* r2/x2 Not used
|
||||
* r3-7/x3-7 Resume information, must be preserved
|
||||
*
|
||||
* "Return" register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_RETURN_FROM_RPC if it was an
|
||||
* AArch32 SMC return or TEESMC64_CALL_RETURN_FROM_RPC for
|
||||
* AArch64 SMC return
|
||||
* r1/x1 Physical pointer to allocated payload memory, 0 if size
|
||||
* was 0 or if memory can't be allocated
|
||||
* r2/x2 Shared memory cookie used when freeing the memory
|
||||
* r3-7/x3-7 Preserved
|
||||
*/
|
||||
#define TEESMC_ST_RPC_FUNC_ALLOC_PAYLOAD 0x5700
|
||||
#define TEESMC_RETURN_ST_RPC_ALLOC_PAYLOAD \
|
||||
TEESMC_RPC_VAL(TEESMC_ST_RPC_FUNC_ALLOC_PAYLOAD)
|
||||
|
||||
|
||||
/*
|
||||
* Free memory previously allocated by TEESMC_RETURN_ST_RPC_ALLOC_PAYLOAD
|
||||
*
|
||||
* "Call" register usage:
|
||||
* r0/x0 This value, TEESMC_RETURN_ST_RPC_FREE_PAYLOAD
|
||||
* r1/x1 Shared memory cookie belonging to this payload memory
|
||||
* r2-7/x2-7 Resume information, must be preserved
|
||||
*
|
||||
* "Return" register usage:
|
||||
* r0/x0 SMC Function ID, TEESMC32_CALL_RETURN_FROM_RPC if it was an
|
||||
* AArch32 SMC return or TEESMC64_CALL_RETURN_FROM_RPC for
|
||||
* AArch64 SMC return
|
||||
* r2-7/x2-7 Preserved
|
||||
*/
|
||||
#define TEESMC_ST_RPC_FUNC_FREE_PAYLOAD 0x5701
|
||||
#define TEESMC_RETURN_ST_RPC_FREE_PAYLOAD \
|
||||
TEESMC_RPC_VAL(TEESMC_ST_RPC_FUNC_FREE_PAYLOAD)
|
||||
|
||||
/* Overriding default UID since the interface is extended
|
||||
* 384fb3e0-e7f8-11e3-af63-0002a5d5c51b
|
||||
*/
|
||||
#define TEESMC_ST_UID_R0 0x384fb3e0
|
||||
#define TEESMC_ST_UID_R1 0xe7f811e3
|
||||
#define TEESMC_ST_UID_R2 0xaf630002
|
||||
#define TEESMC_ST_UID32_R3 0xa5d5c51b
|
||||
#define TEESMC_ST_UID64_R3 0xa5d5c51c
|
||||
|
||||
#define TEESMC_ST_REVISION_MAJOR 1
|
||||
#define TEESMC_ST_REVISION_MINOR 0
|
||||
|
||||
/*
|
||||
* UUID for OP-TEE
|
||||
* 486178e0-e7f8-11e3-bc5e-0002a5d5c51b
|
||||
*/
|
||||
#define TEESMC_OS_OPTEE_UUID_R0 0x486178e0
|
||||
#define TEESMC_OS_OPTEE_UUID_R1 0xe7f811e3
|
||||
#define TEESMC_OS_OPTEE_UUID_R2 0xbc5e0002
|
||||
#define TEESMC_OS_OPTEE_UUID_R3 0xa5d5c51b
|
||||
|
||||
#define TEESMC_OS_OPTEE_REVISION_MAJOR 1
|
||||
#define TEESMC_OS_OPTEE_REVISION_MINOR 0
|
||||
|
||||
#endif /*TEESMC_ST_H*/
|
||||
566
security/optee_linuxdriver/include/linux/tee_client_api.h
Normal file
566
security/optee_linuxdriver/include/linux/tee_client_api.h
Normal file
@@ -0,0 +1,566 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef TEE_CLIENT_API_H
|
||||
#define TEE_CLIENT_API_H
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/*
|
||||
* Defines the number of available memory references in an open session or
|
||||
* invoke command operation payload.
|
||||
*/
|
||||
#define TEEC_CONFIG_PAYLOAD_REF_COUNT 4
|
||||
|
||||
/**
|
||||
* Defines the maximum size of a single shared memory block, in bytes, of both
|
||||
* API allocated and API registered memory. The size is currently set to
|
||||
* 512 * kB (512 * 1024).
|
||||
*/
|
||||
#define TEEC_CONFIG_SHAREDMEM_MAX_SIZE 0x8000
|
||||
|
||||
/**
|
||||
* Flag constants indicating the type of parameters encoded inside the
|
||||
* operation payload (TEEC_Operation), Type is uint32_t.
|
||||
*
|
||||
* TEEC_NONE The Parameter is not used
|
||||
*
|
||||
* TEEC_VALUE_INPUT The Parameter is a TEEC_Value tagged as input.
|
||||
*
|
||||
* TEEC_VALUE_OUTPUT The Parameter is a TEEC_Value tagged as output.
|
||||
*
|
||||
* TEEC_VALUE_INOUT The Parameter is a TEEC_Value tagged as both as
|
||||
* input and output, i.e., for which both the
|
||||
* behaviors of TEEC_VALUE_INPUT and
|
||||
* TEEC_VALUE_OUTPUT apply.
|
||||
*
|
||||
* TEEC_MEMREF_TEMP_INPUT The Parameter is a TEEC_TempMemoryReference
|
||||
* describing a region of memory which needs to be
|
||||
* temporarily registered for the duration of the
|
||||
* Operation and is tagged as input.
|
||||
*
|
||||
* TEEC_MEMREF_TEMP_OUTPUT Same as TEEC_MEMREF_TEMP_INPUT, but the Memory
|
||||
* Reference is tagged as output. The
|
||||
* Implementation may update the size field to
|
||||
* reflect the required output size in some use
|
||||
* cases.
|
||||
*
|
||||
* TEEC_MEMREF_TEMP_INOUT A Temporary Memory Reference tagged as both
|
||||
* input and output, i.e., for which both the
|
||||
* behaviors of TEEC_MEMREF_TEMP_INPUT and
|
||||
* TEEC_MEMREF_TEMP_OUTPUT apply.
|
||||
*
|
||||
* TEEC_MEMREF_WHOLE The Parameter is a Registered Memory Reference
|
||||
* that refers to the entirety of its parent Shared
|
||||
* Memory block. The parameter structure is a
|
||||
* TEEC_MemoryReference. In this structure, the
|
||||
* Implementation MUST read only the parent field
|
||||
* and MAY update the size field when the operation
|
||||
* completes.
|
||||
*
|
||||
* TEEC_MEMREF_PARTIAL_INPUT A Registered Memory Reference structure that
|
||||
* refers to a partial region of its parent Shared
|
||||
* Memory block and is tagged as input.
|
||||
*
|
||||
* TEEC_MEMREF_PARTIAL_OUTPUT Registered Memory Reference structure that
|
||||
* refers to a partial region of its parent Shared
|
||||
* Memory block and is tagged as output.
|
||||
*
|
||||
* TEEC_MEMREF_PARTIAL_INOUT The Registered Memory Reference structure that
|
||||
* refers to a partial region of its parent Shared
|
||||
* Memory block and is tagged as both input and
|
||||
* output, i.e., for which both the behaviors of
|
||||
* TEEC_MEMREF_PARTIAL_INPUT and
|
||||
* TEEC_MEMREF_PARTIAL_OUTPUT apply.
|
||||
*/
|
||||
#define TEEC_NONE 0x00000000
|
||||
#define TEEC_VALUE_INPUT 0x00000001
|
||||
#define TEEC_VALUE_OUTPUT 0x00000002
|
||||
#define TEEC_VALUE_INOUT 0x00000003
|
||||
#define TEEC_MEMREF_TEMP_INPUT 0x00000005
|
||||
#define TEEC_MEMREF_TEMP_OUTPUT 0x00000006
|
||||
#define TEEC_MEMREF_TEMP_INOUT 0x00000007
|
||||
#define TEEC_MEMREF_WHOLE 0x0000000C
|
||||
#define TEEC_MEMREF_PARTIAL_INPUT 0x0000000D
|
||||
#define TEEC_MEMREF_PARTIAL_OUTPUT 0x0000000E
|
||||
#define TEEC_MEMREF_PARTIAL_INOUT 0x0000000F
|
||||
|
||||
/**
|
||||
* Flag constants indicating the data transfer direction of memory in
|
||||
* TEEC_Parameter. TEEC_MEM_INPUT signifies data transfer direction from the
|
||||
* client application to the TEE. TEEC_MEM_OUTPUT signifies data transfer
|
||||
* direction from the TEE to the client application. Type is uint32_t.
|
||||
*
|
||||
* TEEC_MEM_INPUT The Shared Memory can carry data from the client
|
||||
* application to the Trusted Application.
|
||||
* TEEC_MEM_OUTPUT The Shared Memory can carry data from the Trusted
|
||||
* Application to the client application.
|
||||
* TEEC_MEM_DMABUF The Shared Memory is allocated with the dma buf api and
|
||||
* not necessarly user mapped.
|
||||
* Handle of the memory pass to drivers is the implementation
|
||||
* fd field instead of the buffer field.
|
||||
* TEEC_MEM_KAPI Shared memory is required from another linux module.
|
||||
* Dma buf file descriptor is not created.
|
||||
*/
|
||||
#define TEEC_MEM_INPUT 0x00000001
|
||||
#define TEEC_MEM_OUTPUT 0x00000002
|
||||
#define TEEC_MEM_DMABUF 0x00010000
|
||||
#define TEEC_MEM_KAPI 0x00020000
|
||||
|
||||
/**
|
||||
* Return values. Type is TEEC_Result
|
||||
*
|
||||
* TEEC_SUCCESS The operation was successful.
|
||||
* TEEC_ERROR_GENERIC Non-specific cause.
|
||||
* TEEC_ERROR_ACCESS_DENIED Access privileges are not sufficient.
|
||||
* TEEC_ERROR_CANCEL The operation was canceled.
|
||||
* TEEC_ERROR_ACCESS_CONFLICT Concurrent accesses caused conflict.
|
||||
* TEEC_ERROR_EXCESS_DATA Too much data for the requested operation was
|
||||
* passed.
|
||||
* TEEC_ERROR_BAD_FORMAT Input data was of invalid format.
|
||||
* TEEC_ERROR_BAD_PARAMETERS Input parameters were invalid.
|
||||
* TEEC_ERROR_BAD_STATE Operation is not valid in the current state.
|
||||
* TEEC_ERROR_ITEM_NOT_FOUND The requested data item is not found.
|
||||
* TEEC_ERROR_NOT_IMPLEMENTED The requested operation should exist but is not
|
||||
* yet implemented.
|
||||
* TEEC_ERROR_NOT_SUPPORTED The requested operation is valid but is not
|
||||
* supported in this implementation.
|
||||
* TEEC_ERROR_NO_DATA Expected data was missing.
|
||||
* TEEC_ERROR_OUT_OF_MEMORY System ran out of resources.
|
||||
* TEEC_ERROR_BUSY The system is busy working on something else.
|
||||
* TEEC_ERROR_COMMUNICATION Communication with a remote party failed.
|
||||
* TEEC_ERROR_SECURITY A security fault was detected.
|
||||
* TEEC_ERROR_SHORT_BUFFER The supplied buffer is too short for the
|
||||
* generated output.
|
||||
* TEEC_ERROR_TARGET_DEAD Trusted Application has panicked
|
||||
* during the operation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Standard defined error codes.
|
||||
*/
|
||||
#define TEEC_SUCCESS 0x00000000
|
||||
#define TEEC_ERROR_GENERIC 0xFFFF0000
|
||||
#define TEEC_ERROR_ACCESS_DENIED 0xFFFF0001
|
||||
#define TEEC_ERROR_CANCEL 0xFFFF0002
|
||||
#define TEEC_ERROR_ACCESS_CONFLICT 0xFFFF0003
|
||||
#define TEEC_ERROR_EXCESS_DATA 0xFFFF0004
|
||||
#define TEEC_ERROR_BAD_FORMAT 0xFFFF0005
|
||||
#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
|
||||
#define TEEC_ERROR_BAD_STATE 0xFFFF0007
|
||||
#define TEEC_ERROR_ITEM_NOT_FOUND 0xFFFF0008
|
||||
#define TEEC_ERROR_NOT_IMPLEMENTED 0xFFFF0009
|
||||
#define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A
|
||||
#define TEEC_ERROR_NO_DATA 0xFFFF000B
|
||||
#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
|
||||
#define TEEC_ERROR_BUSY 0xFFFF000D
|
||||
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
|
||||
#define TEEC_ERROR_SECURITY 0xFFFF000F
|
||||
#define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010
|
||||
#define TEEC_ERROR_TARGET_DEAD 0xFFFF3024
|
||||
|
||||
/**
|
||||
* Function error origins, of type TEEC_ErrorOrigin. These indicate where in
|
||||
* the software stack a particular return value originates from.
|
||||
*
|
||||
* TEEC_ORIGIN_API The error originated within the TEE Client API
|
||||
* implementation.
|
||||
* TEEC_ORIGIN_COMMS The error originated within the underlying
|
||||
* communications stack linking the rich OS with
|
||||
* the TEE.
|
||||
* TEEC_ORIGIN_TEE The error originated within the common TEE code.
|
||||
* TEEC_ORIGIN_TRUSTED_APP The error originated within the Trusted Application
|
||||
* code.
|
||||
*/
|
||||
#define TEEC_ORIGIN_API 0x00000001
|
||||
#define TEEC_ORIGIN_COMMS 0x00000002
|
||||
#define TEEC_ORIGIN_TEE 0x00000003
|
||||
#define TEEC_ORIGIN_TRUSTED_APP 0x00000004
|
||||
|
||||
/**
|
||||
* Session login methods, for use in TEEC_OpenSession() as parameter
|
||||
* connectionMethod. Type is uint32_t.
|
||||
*
|
||||
* TEEC_LOGIN_PUBLIC No login data is provided.
|
||||
* TEEC_LOGIN_USER Login data about the user running the Client
|
||||
* Application process is provided.
|
||||
* TEEC_LOGIN_GROUP Login data about the group running the Client
|
||||
* Application process is provided.
|
||||
* TEEC_LOGIN_APPLICATION Login data about the running Client Application
|
||||
* itself is provided.
|
||||
*/
|
||||
#define TEEC_LOGIN_PUBLIC 0x00000000
|
||||
#define TEEC_LOGIN_USER 0x00000001
|
||||
#define TEEC_LOGIN_GROUP 0x00000002
|
||||
#define TEEC_LOGIN_APPLICATION 0x00000004
|
||||
|
||||
/**
|
||||
* Encode the paramTypes according to the supplied types.
|
||||
*
|
||||
* @param p0 The first param type.
|
||||
* @param p1 The second param type.
|
||||
* @param p2 The third param type.
|
||||
* @param p3 The fourth param type.
|
||||
*/
|
||||
#define TEEC_PARAM_TYPES(p0, p1, p2, p3) \
|
||||
((p0) | ((p1) << 4) | ((p2) << 8) | ((p3) << 12))
|
||||
|
||||
/**
|
||||
* Get the i_th param type from the paramType.
|
||||
*
|
||||
* @param p The paramType.
|
||||
* @param i The i-th parameter to get the type for.
|
||||
*/
|
||||
#define TEEC_PARAM_TYPE_GET(p, i) (((p) >> (i * 4)) & 0xF)
|
||||
|
||||
typedef uint32_t TEEC_Result;
|
||||
|
||||
/**
|
||||
* struct TEEC_Context - Represents a connection between a client application
|
||||
* and a TEE.
|
||||
*
|
||||
* Context identifier can be a handle (when opened from user land)
|
||||
* or a structure pointer (when opened from kernel land).
|
||||
* Identifier is defined as an union to match type sizes on all architectures.
|
||||
*/
|
||||
typedef struct {
|
||||
char devname[256];
|
||||
union {
|
||||
struct tee_context *ctx;
|
||||
int fd;
|
||||
};
|
||||
} TEEC_Context;
|
||||
|
||||
/**
|
||||
* This type contains a Universally Unique Resource Identifier (UUID) type as
|
||||
* defined in RFC4122. These UUID values are used to identify Trusted
|
||||
* Applications.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t timeLow;
|
||||
uint16_t timeMid;
|
||||
uint16_t timeHiAndVersion;
|
||||
uint8_t clockSeqAndNode[8];
|
||||
} TEEC_UUID;
|
||||
|
||||
/**
|
||||
* struct TEEC_SharedMemory - Memory to transfer data between a client
|
||||
* application and trusted code.
|
||||
*
|
||||
* @param buffer The memory buffer which is to be, or has been, shared
|
||||
* with the TEE.
|
||||
* @param size The size, in bytes, of the memory buffer.
|
||||
* @param flags Bit-vector which holds properties of buffer.
|
||||
* The bit-vector can contain either or both of the
|
||||
* TEEC_MEM_INPUT and TEEC_MEM_OUTPUT flags.
|
||||
*
|
||||
* A shared memory block is a region of memory allocated in the context of the
|
||||
* client application memory space that can be used to transfer data between
|
||||
* that client application and a trusted application. The user of this struct
|
||||
* is responsible to populate the buffer pointer.
|
||||
*/
|
||||
typedef struct {
|
||||
void *buffer;
|
||||
size_t size;
|
||||
uint32_t flags;
|
||||
/*
|
||||
* identifier can store a handle (int) or a structure pointer (void *).
|
||||
* define this union to match case where sizeof(int)!=sizeof(void *).
|
||||
*/
|
||||
union {
|
||||
int fd;
|
||||
void *ptr;
|
||||
} d;
|
||||
uint8_t registered;
|
||||
} TEEC_SharedMemory;
|
||||
|
||||
/**
|
||||
* struct TEEC_TempMemoryReference - Temporary memory to transfer data between
|
||||
* a client application and trusted code, only used for the duration of the
|
||||
* operation.
|
||||
*
|
||||
* @param buffer The memory buffer which is to be, or has been shared with
|
||||
* the TEE.
|
||||
* @param size The size, in bytes, of the memory buffer.
|
||||
*
|
||||
* A memory buffer that is registered temporarily for the duration of the
|
||||
* operation to be called.
|
||||
*/
|
||||
typedef struct {
|
||||
void *buffer;
|
||||
size_t size;
|
||||
} TEEC_TempMemoryReference;
|
||||
|
||||
/**
|
||||
* struct TEEC_RegisteredMemoryReference - use a pre-registered or
|
||||
* pre-allocated shared memory block of memory to transfer data between
|
||||
* a client application and trusted code.
|
||||
*
|
||||
* @param parent Points to a shared memory structure. The memory reference
|
||||
* may utilize the whole shared memory or only a part of it.
|
||||
* Must not be NULL
|
||||
*
|
||||
* @param size The size, in bytes, of the memory buffer.
|
||||
*
|
||||
* @param offset The offset, in bytes, of the referenced memory region from
|
||||
* the start of the shared memory block.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
TEEC_SharedMemory *parent;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
} TEEC_RegisteredMemoryReference;
|
||||
|
||||
/**
|
||||
* struct TEEC_Value - Small raw data container
|
||||
*
|
||||
* Instead of allocating a shared memory buffer this structure can be used
|
||||
* to pass small raw data between a client application and trusted code.
|
||||
*
|
||||
* @param a The first integer value.
|
||||
*
|
||||
* @param b The second second value.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
} TEEC_Value;
|
||||
|
||||
/**
|
||||
* union TEEC_Parameter - Memory container to be used when passing data between
|
||||
* client application and trusted code.
|
||||
*
|
||||
* Either the client uses a shared memory reference, parts of it or a small raw
|
||||
* data container.
|
||||
*
|
||||
* @param tmpref A temporary memory reference only valid for the duration
|
||||
* of the operation.
|
||||
*
|
||||
* @param memref The entire shared memory or parts of it.
|
||||
*
|
||||
* @param value The small raw data container to use
|
||||
*/
|
||||
typedef union {
|
||||
TEEC_TempMemoryReference tmpref;
|
||||
TEEC_RegisteredMemoryReference memref;
|
||||
TEEC_Value value;
|
||||
} TEEC_Parameter;
|
||||
|
||||
/**
|
||||
* struct TEEC_Session - Represents a connection between a client application
|
||||
* and a trusted application.
|
||||
*/
|
||||
typedef struct {
|
||||
int fd;
|
||||
} TEEC_Session;
|
||||
|
||||
/**
|
||||
* struct TEEC_Operation - Holds information and memory references used in
|
||||
* TEEC_InvokeCommand().
|
||||
*
|
||||
* @param started Client must initialize to zero if it needs to cancel
|
||||
* an operation about to be performed.
|
||||
* @param paramTypes Type of data passed. Use TEEC_PARAMS_TYPE macro to
|
||||
* create the correct flags.
|
||||
* 0 means TEEC_NONE is passed for all params.
|
||||
* @param params Array of parameters of type TEEC_Parameter.
|
||||
* @param session Internal pointer to the last session used by
|
||||
* TEEC_InvokeCommand with this operation.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t started;
|
||||
uint32_t paramTypes;
|
||||
TEEC_Parameter params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
/* Implementation-Defined */
|
||||
TEEC_Session *session;
|
||||
TEEC_SharedMemory memRefs[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
uint32_t flags;
|
||||
} TEEC_Operation;
|
||||
|
||||
/**
|
||||
* TEEC_InitializeContext() - Initializes a context holding connection
|
||||
* information on the specific TEE, designated by the name string.
|
||||
|
||||
* @param name A zero-terminated string identifying the TEE to connect to.
|
||||
* If name is set to NULL, the default TEE is connected to. NULL
|
||||
* is the only supported value in this version of the API
|
||||
* implementation.
|
||||
*
|
||||
* @param context The context structure which is to be initialized.
|
||||
*
|
||||
* @return TEEC_SUCCESS The initialization was successful.
|
||||
* @return TEEC_Result Something failed.
|
||||
*/
|
||||
TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context);
|
||||
|
||||
/**
|
||||
* TEEC_FinalizeContext() - Destroys a context holding connection information
|
||||
* on the specific TEE.
|
||||
*
|
||||
* This function destroys an initialized TEE context, closing the connection
|
||||
* between the client application and the TEE. This function must only be
|
||||
* called when all sessions related to this TEE context have been closed and
|
||||
* all shared memory blocks have been released.
|
||||
*
|
||||
* @param context The context to be destroyed.
|
||||
*/
|
||||
void TEEC_FinalizeContext(TEEC_Context *context);
|
||||
|
||||
/**
|
||||
* TEEC_OpenSession() - Opens a new session with the specified trusted
|
||||
* application.
|
||||
*
|
||||
* @param context The initialized TEE context structure in which
|
||||
* scope to open the session.
|
||||
* @param session The session to initialize.
|
||||
* @param destination A structure identifying the trusted application
|
||||
* with which to open a session.
|
||||
*
|
||||
* @param connectionMethod The connection method to use.
|
||||
* @param connectionData Any data necessary to connect with the chosen
|
||||
* connection method. Not supported, should be set to
|
||||
* NULL.
|
||||
* @param operation An operation structure to use in the session. May
|
||||
* be set to NULL to signify no operation structure
|
||||
* needed.
|
||||
*
|
||||
* @param returnOrigin A parameter which will hold the error origin if
|
||||
* this function returns any value other than
|
||||
* TEEC_SUCCESS.
|
||||
*
|
||||
* @return TEEC_SUCCESS OpenSession successfully opened a new session.
|
||||
* @return TEEC_Result Something failed.
|
||||
*
|
||||
*/
|
||||
TEEC_Result TEEC_OpenSession(TEEC_Context *context,
|
||||
TEEC_Session *session,
|
||||
const TEEC_UUID *destination,
|
||||
uint32_t connectionMethod,
|
||||
const void *connectionData,
|
||||
TEEC_Operation *operation,
|
||||
uint32_t *returnOrigin);
|
||||
|
||||
/**
|
||||
* TEEC_CloseSession() - Closes the session which has been opened with the
|
||||
* specific trusted application.
|
||||
*
|
||||
* @param session The opened session to close.
|
||||
*/
|
||||
void TEEC_CloseSession(TEEC_Session *session);
|
||||
|
||||
/**
|
||||
* TEEC_InvokeCommand() - Executes a command in the specified trusted
|
||||
* application.
|
||||
*
|
||||
* @param session A handle to an open connection to the trusted
|
||||
* application.
|
||||
* @param commandID Identifier of the command in the trusted application
|
||||
* to invoke.
|
||||
* @param operation An operation structure to use in the invoke command.
|
||||
* May be set to NULL to signify no operation structure
|
||||
* needed.
|
||||
* @param returnOrigin A parameter which will hold the error origin if this
|
||||
* function returns any value other than TEEC_SUCCESS.
|
||||
*
|
||||
* @return TEEC_SUCCESS OpenSession successfully opened a new session.
|
||||
* @return TEEC_Result Something failed.
|
||||
*/
|
||||
TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
|
||||
uint32_t commandID,
|
||||
TEEC_Operation *operation,
|
||||
uint32_t *returnOrigin);
|
||||
|
||||
/**
|
||||
* TEEC_RegisterSharedMemory() - Register a block of existing memory as a
|
||||
* shared block within the scope of the specified context.
|
||||
*
|
||||
* @param context The initialized TEE context structure in which scope to
|
||||
* open the session.
|
||||
* @param sharedMem pointer to the shared memory structure to register.
|
||||
*
|
||||
* @return TEEC_SUCCESS The registration was successful.
|
||||
* @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion.
|
||||
* @return TEEC_Result Something failed.
|
||||
*/
|
||||
TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
|
||||
TEEC_SharedMemory *sharedMem);
|
||||
|
||||
/**
|
||||
* TEEC_AllocateSharedMemory() - Allocate shared memory for TEE.
|
||||
*
|
||||
* @param context The initialized TEE context structure in which scope to
|
||||
* open the session.
|
||||
* @param sharedMem Pointer to the allocated shared memory.
|
||||
*
|
||||
* @return TEEC_SUCCESS The registration was successful.
|
||||
* @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion.
|
||||
* @return TEEC_Result Something failed.
|
||||
*/
|
||||
TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
|
||||
TEEC_SharedMemory *sharedMem);
|
||||
|
||||
/**
|
||||
* TEEC_ReleaseSharedMemory() - Free or deregister the shared memory.
|
||||
*
|
||||
* @param sharedMem Pointer to the shared memory to be freed.
|
||||
*/
|
||||
void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory);
|
||||
|
||||
/**
|
||||
* TEEC_RequestCancellation() - Request the cancellation of a pending open
|
||||
* session or command invocation.
|
||||
*
|
||||
* @param operation Pointer to an operation previously passed to open session
|
||||
* or invoke.
|
||||
*/
|
||||
void TEEC_RequestCancellation(TEEC_Operation *operation);
|
||||
|
||||
/**
|
||||
* Register a pre-allocated Trusted Application This is mainly intended for
|
||||
* OS-FREE contexts or when a filesystem is not available.
|
||||
*
|
||||
* @param ta Pointer to the trusted application binary
|
||||
* @param size The size of the TA binary
|
||||
*
|
||||
* @return TEEC_SUCCESS if successful.
|
||||
* @return TEEC_Result something failed.
|
||||
*/
|
||||
TEEC_Result TEEC_RegisterTA(const void *ta, const size_t size);
|
||||
|
||||
/**
|
||||
* Unregister a pre-allocated Trusted Application This is mainly intended for
|
||||
* OS-FREE contexts or when a filesystem is not available.
|
||||
*
|
||||
* @param ta Pointer to the trusted application binary
|
||||
*/
|
||||
void TEEC_UnregisterTA(const void *ta);
|
||||
|
||||
#endif
|
||||
205
security/optee_linuxdriver/include/linux/tee_core.h
Normal file
205
security/optee_linuxdriver/include/linux/tee_core.h
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_CORE_DRV_H__
|
||||
#define __TEE_CORE_DRV_H__
|
||||
|
||||
#include <linux/klist.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/tee_client_api.h>
|
||||
|
||||
struct tee_cmd_io;
|
||||
struct tee_shm_io;
|
||||
struct tee_rpc;
|
||||
|
||||
enum tee_state {
|
||||
TEE_OFFLINE = 0,
|
||||
TEE_ONLINE = 1,
|
||||
TEE_SUSPENDED = 2,
|
||||
TEE_RUNNING = 3,
|
||||
TEE_CRASHED = 4,
|
||||
TEE_LAST = 5,
|
||||
};
|
||||
|
||||
#define TEE_CONF_TEST_MODE 0x01000000
|
||||
#define TEE_CONF_FW_NOT_CAPABLE 0x00000001
|
||||
|
||||
struct tee_stats_entry {
|
||||
int count;
|
||||
int max;
|
||||
};
|
||||
|
||||
#define TEE_STATS_CONTEXT_IDX 0
|
||||
#define TEE_STATS_SESSION_IDX 1
|
||||
#define TEE_STATS_SHM_IDX 2
|
||||
|
||||
#define TEE_MAX_TEE_DEV_NAME (64)
|
||||
struct tee {
|
||||
struct klist_node node;
|
||||
char name[TEE_MAX_TEE_DEV_NAME];
|
||||
int id;
|
||||
void *priv;
|
||||
const struct tee_ops *ops;
|
||||
struct device *dev;
|
||||
struct miscdevice miscdev;
|
||||
struct tee_rpc *rpc;
|
||||
struct dentry *dbg_dir;
|
||||
atomic_t refcount;
|
||||
int max_refcount;
|
||||
struct tee_stats_entry stats[3];
|
||||
struct list_head list_ctx;
|
||||
struct list_head list_rpc_shm;
|
||||
struct mutex lock;
|
||||
unsigned int state;
|
||||
uint32_t shm_flags; /* supported flags for shm allocation */
|
||||
uint32_t conf;
|
||||
uint32_t test;
|
||||
};
|
||||
|
||||
#define _DEV(tee) (tee->miscdev.this_device)
|
||||
|
||||
#define TEE_MAX_CLIENT_NAME (128)
|
||||
|
||||
/**
|
||||
* struct tee_context - internal structure to store a TEE context.
|
||||
*
|
||||
* @tee: tee attached to the tee_context
|
||||
* @usr_client: flag to known if the client is user side client
|
||||
* @entry: list of tee_context
|
||||
* @list_sess: list of tee_session that denotes all tee_session attached
|
||||
* @list_shm: list of tee_shm that denotes all tee_shm attached
|
||||
* @refcount: number of objects which reference it (including itself)
|
||||
*/
|
||||
struct tee_context {
|
||||
struct tee *tee;
|
||||
char name[TEE_MAX_CLIENT_NAME];
|
||||
int tgid;
|
||||
int usr_client;
|
||||
struct list_head entry;
|
||||
struct list_head list_sess;
|
||||
struct list_head list_shm;
|
||||
struct kref refcount;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_session - internal structure to store a TEE session.
|
||||
*
|
||||
* @entry: list of tee_context
|
||||
* @ctx: tee_context attached to the tee_session
|
||||
* @sessid: session ID returned by the secure world
|
||||
* @priv: exporter specific private data for this buffer object
|
||||
*/
|
||||
struct tee_session {
|
||||
struct list_head entry;
|
||||
struct tee_context *ctx;
|
||||
uint32_t sessid;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct tee_shm_dma_buf {
|
||||
struct dma_buf_attachment *attach;
|
||||
struct sg_table *sgt;
|
||||
bool tee_allocated;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_shm - internal structure to store a shm object.
|
||||
*
|
||||
* @ctx: tee_context attached to the buffer.
|
||||
* @tee: tee attached to the buffer.
|
||||
* @dev: device attached to the buffer.
|
||||
* @size_req: requested size for the buffer
|
||||
* @size_alloc: effective size of the buffer
|
||||
* @kaddr: kernel address if mapped kernel side
|
||||
* @paddr: physical address
|
||||
* @flags: flags which denote the type of the buffer
|
||||
* @entry: list of tee_shm
|
||||
*/
|
||||
struct tee_shm {
|
||||
struct list_head entry;
|
||||
struct tee_context *ctx;
|
||||
struct tee *tee;
|
||||
struct device *dev;
|
||||
size_t size_req;
|
||||
size_t size_alloc;
|
||||
uint32_t flags;
|
||||
void *kaddr;
|
||||
dma_addr_t paddr;
|
||||
struct sg_table sgt;
|
||||
struct tee_shm_dma_buf *sdb;
|
||||
};
|
||||
|
||||
#define TEE_SHM_MAPPED 0x01000000
|
||||
#define TEE_SHM_TEMP 0x02000000
|
||||
#define TEE_SHM_FROM_RPC 0x04000000
|
||||
#define TEE_SHM_REGISTERED 0x08000000
|
||||
#define TEE_SHM_MEMREF 0x10000000
|
||||
#define TEE_SHM_CACHED 0x20000000
|
||||
|
||||
#define TEE_SHM_DRV_PRIV_MASK 0xFF000000
|
||||
|
||||
struct tee_data {
|
||||
uint32_t type;
|
||||
uint32_t type_original;
|
||||
TEEC_SharedMemory c_shm[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
union {
|
||||
struct tee_shm *shm;
|
||||
TEEC_Value value;
|
||||
} params[TEEC_CONFIG_PAYLOAD_REF_COUNT];
|
||||
};
|
||||
|
||||
struct tee_cmd {
|
||||
TEEC_Result err;
|
||||
uint32_t origin;
|
||||
uint32_t cmd;
|
||||
struct tee_shm *uuid;
|
||||
struct tee_shm *ta;
|
||||
struct tee_data param;
|
||||
};
|
||||
|
||||
struct tee_shm *tee_shm_alloc_from_rpc(struct tee *tee, size_t size);
|
||||
void tee_shm_free_from_rpc(struct tee_shm *);
|
||||
|
||||
int tee_core_add(struct tee *tee);
|
||||
int tee_core_del(struct tee *tee);
|
||||
|
||||
struct tee *tee_core_alloc(struct device *dev, char *name, int id,
|
||||
const struct tee_ops *ops, size_t len);
|
||||
int tee_core_free(struct tee *tee);
|
||||
|
||||
struct tee_ops {
|
||||
struct module *owner;
|
||||
const char *type;
|
||||
|
||||
int (*start)(struct tee *tee);
|
||||
int (*stop)(struct tee *tee);
|
||||
int (*open)(struct tee_session *sess, struct tee_cmd *cmd);
|
||||
int (*close)(struct tee_session *sess);
|
||||
int (*invoke)(struct tee_session *sess, struct tee_cmd *cmd);
|
||||
int (*cancel)(struct tee_session *sess, struct tee_cmd *cmd);
|
||||
struct tee_shm *(*alloc)(struct tee *tee, size_t size,
|
||||
uint32_t flags);
|
||||
void (*free)(struct tee_shm *shm);
|
||||
int (*shm_inc_ref)(struct tee_shm *shm);
|
||||
};
|
||||
|
||||
#endif /* __TEE_CORE_DRV_H__ */
|
||||
63
security/optee_linuxdriver/include/linux/tee_ioc.h
Normal file
63
security/optee_linuxdriver/include/linux/tee_ioc.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_IOC_H
|
||||
#define _TEE_IOC_H
|
||||
|
||||
#include <linux/tee_client_api.h>
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#define __user
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct tee_cmd_io - The command sent to an open tee device.
|
||||
* @err: Error code (as in Global Platform TEE Client API spec)
|
||||
* @origin: Origin for the error code (also from spec).
|
||||
* @cmd: The command to be executed in the trusted application.
|
||||
* @uuid: The uuid for the trusted application.
|
||||
* @data: The trusted application or memory block.
|
||||
* @data_size: The size of the trusted application or memory block.
|
||||
* @op: The cmd payload operation for the trusted application.
|
||||
*
|
||||
* This structure is mainly used in the Linux kernel for communication
|
||||
* with the user space.
|
||||
*/
|
||||
struct tee_cmd_io {
|
||||
TEEC_Result err;
|
||||
uint32_t origin;
|
||||
uint32_t cmd;
|
||||
TEEC_UUID __user *uuid;
|
||||
void __user *data;
|
||||
uint32_t data_size;
|
||||
TEEC_Operation __user *op;
|
||||
int fd_sess;
|
||||
};
|
||||
|
||||
struct tee_shm_io {
|
||||
void __user *buffer;
|
||||
size_t size;
|
||||
uint32_t flags;
|
||||
union {
|
||||
int fd_shm;
|
||||
void *ptr;
|
||||
};
|
||||
uint8_t registered;
|
||||
};
|
||||
|
||||
#define TEE_OPEN_SESSION_IOC _IOWR('t', 161, struct tee_cmd_io)
|
||||
#define TEE_INVOKE_COMMAND_IOC _IOWR('t', 163, struct tee_cmd_io)
|
||||
#define TEE_REQUEST_CANCELLATION_IOC _IOWR('t', 164, struct tee_cmd_io)
|
||||
#define TEE_ALLOC_SHM_IOC _IOWR('t', 165, struct tee_shm_io)
|
||||
#define TEE_GET_FD_FOR_RPC_SHM_IOC _IOWR('t', 167, struct tee_shm_io)
|
||||
|
||||
#endif /* _TEE_IOC_H */
|
||||
174
security/optee_linuxdriver/include/linux/tee_kernel_api.h
Normal file
174
security/optee_linuxdriver/include/linux/tee_kernel_api.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2014, STMicroelectronics International N.V.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License Version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT 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_KERNEL_API_H
|
||||
#define _TEE_KERNEL_API_H
|
||||
|
||||
#include <linux/tee_client_api.h>
|
||||
|
||||
/**
|
||||
* struct TEEC_Context - Represents a connection between a client application
|
||||
* and a TEE.
|
||||
*/
|
||||
/*typedef struct {
|
||||
char devname[256];
|
||||
} TEEC_Context;*/
|
||||
|
||||
/**
|
||||
* struct TEEC_Session - Represents a connection between a client application
|
||||
* and a trusted application.
|
||||
*/
|
||||
/*typedef struct {
|
||||
void *session;
|
||||
} TEEC_Session;*/
|
||||
|
||||
/**
|
||||
* TEEC_InitializeContext() - Initializes a context holding connection
|
||||
* information on the specific TEE, designated by the name string.
|
||||
|
||||
* @param name A zero-terminated string identifying the TEE to connect to.
|
||||
* If name is set to NULL, the default TEE is connected to. NULL
|
||||
* is the only supported value in this version of the API
|
||||
* implementation.
|
||||
*
|
||||
* @param context The context structure which is to be initialized.
|
||||
*
|
||||
* @return TEEC_SUCCESS The initialization was successful.
|
||||
* @return TEEC_Result Something failed.
|
||||
*/
|
||||
TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *context);
|
||||
|
||||
/**
|
||||
* TEEC_FinalizeContext() - Destroys a context holding connection information
|
||||
* on the specific TEE.
|
||||
*
|
||||
* This function destroys an initialized TEE context, closing the connection
|
||||
* between the client application and the TEE. This function must only be
|
||||
* called when all sessions related to this TEE context have been closed and
|
||||
* all shared memory blocks have been released.
|
||||
*
|
||||
* @param context The context to be destroyed.
|
||||
*/
|
||||
void TEEC_FinalizeContext(TEEC_Context *context);
|
||||
|
||||
/**
|
||||
* TEEC_OpenSession() - Opens a new session with the specified trusted
|
||||
* application.
|
||||
*
|
||||
* @param context The initialized TEE context structure in which
|
||||
* scope to open the session.
|
||||
* @param session The session to initialize.
|
||||
* @param destination A structure identifying the trusted application
|
||||
* with which to open a session.
|
||||
*
|
||||
* @param connectionMethod The connection method to use.
|
||||
* @param connectionData Any data necessary to connect with the chosen
|
||||
* connection method. Not supported, should be set to
|
||||
* NULL.
|
||||
* @param operation An operation structure to use in the session. May
|
||||
* be set to NULL to signify no operation structure
|
||||
* needed.
|
||||
*
|
||||
* @param returnOrigin A parameter which will hold the error origin if
|
||||
* this function returns any value other than
|
||||
* TEEC_SUCCESS.
|
||||
*
|
||||
* @return TEEC_SUCCESS OpenSession successfully opened a new session.
|
||||
* @return TEEC_Result Something failed.
|
||||
*
|
||||
*/
|
||||
TEEC_Result TEEC_OpenSession(TEEC_Context *context,
|
||||
TEEC_Session *session,
|
||||
const TEEC_UUID *destination,
|
||||
uint32_t connectionMethod,
|
||||
const void *connectionData,
|
||||
TEEC_Operation *operation,
|
||||
uint32_t *returnOrigin);
|
||||
|
||||
/**
|
||||
* TEEC_CloseSession() - Closes the session which has been opened with the
|
||||
* specific trusted application.
|
||||
*
|
||||
* @param session The opened session to close.
|
||||
*/
|
||||
void TEEC_CloseSession(TEEC_Session *session);
|
||||
|
||||
/**
|
||||
* TEEC_InvokeCommand() - Executes a command in the specified trusted
|
||||
* application.
|
||||
*
|
||||
* @param session A handle to an open connection to the trusted
|
||||
* application.
|
||||
* @param commandID Identifier of the command in the trusted application
|
||||
* to invoke.
|
||||
* @param operation An operation structure to use in the invoke command.
|
||||
* May be set to NULL to signify no operation structure
|
||||
* needed.
|
||||
* @param returnOrigin A parameter which will hold the error origin if this
|
||||
* function returns any value other than TEEC_SUCCESS.
|
||||
*
|
||||
* @return TEEC_SUCCESS OpenSession successfully opened a new session.
|
||||
* @return TEEC_Result Something failed.
|
||||
*/
|
||||
TEEC_Result TEEC_InvokeCommand(TEEC_Session *session,
|
||||
uint32_t commandID,
|
||||
TEEC_Operation *operation,
|
||||
uint32_t *returnOrigin);
|
||||
|
||||
/**
|
||||
* TEEC_RegisterSharedMemory() - Register a block of existing memory as a
|
||||
* shared block within the scope of the specified context.
|
||||
*
|
||||
* @param context The initialized TEE context structure in which scope to
|
||||
* open the session.
|
||||
* @param sharedMem pointer to the shared memory structure to register.
|
||||
*
|
||||
* @return TEEC_SUCCESS The registration was successful.
|
||||
* @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion.
|
||||
* @return TEEC_Result Something failed.
|
||||
*/
|
||||
TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *context,
|
||||
TEEC_SharedMemory *sharedMem);
|
||||
|
||||
/**
|
||||
* TEEC_AllocateSharedMemory() - Allocate shared memory for TEE.
|
||||
*
|
||||
* @param context The initialized TEE context structure in which scope to
|
||||
* open the session.
|
||||
* @param sharedMem Pointer to the allocated shared memory.
|
||||
*
|
||||
* @return TEEC_SUCCESS The registration was successful.
|
||||
* @return TEEC_ERROR_OUT_OF_MEMORY Memory exhaustion.
|
||||
* @return TEEC_Result Something failed.
|
||||
*/
|
||||
TEEC_Result TEEC_AllocateSharedMemory(TEEC_Context *context,
|
||||
TEEC_SharedMemory *sharedMem);
|
||||
|
||||
/**
|
||||
* TEEC_ReleaseSharedMemory() - Free or deregister the shared memory.
|
||||
*
|
||||
* @param sharedMem Pointer to the shared memory to be freed.
|
||||
*/
|
||||
void TEEC_ReleaseSharedMemory(TEEC_SharedMemory *sharedMemory);
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* TEEC_RequestCancellation() - Request the cancellation of a pending open
|
||||
* session or command invocation.
|
||||
*
|
||||
* @param operation Pointer to an operation previously passed to open session
|
||||
* or invoke.
|
||||
*/
|
||||
void TEEC_RequestCancellation(TEEC_Operation *operation);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user