mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-27 07:15:20 +00:00
debugfs: add SMC channel
Provide an SMC interface to the 9p filesystem. This permits accessing firmware drivers through a common interface, using standardized read/write/control operations. Signed-off-by: Ambroise Vincent <ambroise.vincent@arm.com> Signed-off-by: Olivier Deprez <olivier.deprez@arm.com> Change-Id: I9314662314bb060f6bc02714476574da158b2a7d
This commit is contained in:
parent
d310239d77
commit
992f091b5d
12 changed files with 759 additions and 5 deletions
|
@ -17,6 +17,7 @@ The Arm SiP implementation offers the following services:
|
||||||
|
|
||||||
- Performance Measurement Framework (PMF)
|
- Performance Measurement Framework (PMF)
|
||||||
- Execution State Switching service
|
- Execution State Switching service
|
||||||
|
- DebugFS interface
|
||||||
|
|
||||||
Source definitions for Arm SiP service are located in the ``arm_sip_svc.h`` header
|
Source definitions for Arm SiP service are located in the ``arm_sip_svc.h`` header
|
||||||
file.
|
file.
|
||||||
|
@ -87,6 +88,346 @@ Instead, execution starts at the supplied entry point, with the CPU registers 0
|
||||||
and 1 populated with the supplied *Cookie hi* and *Cookie lo* values,
|
and 1 populated with the supplied *Cookie hi* and *Cookie lo* values,
|
||||||
respectively.
|
respectively.
|
||||||
|
|
||||||
|
DebugFS interface
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The optional DebugFS interface is accessed through an SMC SiP service. Refer
|
||||||
|
to the component documentation for details.
|
||||||
|
|
||||||
|
String parameters are passed through a shared buffer using a specific union:
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
union debugfs_parms {
|
||||||
|
struct {
|
||||||
|
char fname[MAX_PATH_LEN];
|
||||||
|
} open;
|
||||||
|
|
||||||
|
struct mount {
|
||||||
|
char srv[MAX_PATH_LEN];
|
||||||
|
char where[MAX_PATH_LEN];
|
||||||
|
char spec[MAX_PATH_LEN];
|
||||||
|
} mount;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char path[MAX_PATH_LEN];
|
||||||
|
dir_t dir;
|
||||||
|
} stat;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char oldpath[MAX_PATH_LEN];
|
||||||
|
char newpath[MAX_PATH_LEN];
|
||||||
|
} bind;
|
||||||
|
};
|
||||||
|
|
||||||
|
Format of the dir_t structure as such:
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[NAMELEN];
|
||||||
|
long length;
|
||||||
|
unsigned char mode;
|
||||||
|
unsigned char index;
|
||||||
|
unsigned char dev;
|
||||||
|
qid_t qid;
|
||||||
|
} dir_t;
|
||||||
|
|
||||||
|
|
||||||
|
* Identifiers
|
||||||
|
|
||||||
|
======================== =============================================
|
||||||
|
SMC_OK 0
|
||||||
|
SMC_UNK -1
|
||||||
|
DEBUGFS_E_INVALID_PARAMS -2
|
||||||
|
======================== =============================================
|
||||||
|
|
||||||
|
======================== =============================================
|
||||||
|
MOUNT 0
|
||||||
|
CREATE 1
|
||||||
|
OPEN 2
|
||||||
|
CLOSE 3
|
||||||
|
READ 4
|
||||||
|
WRITE 5
|
||||||
|
SEEK 6
|
||||||
|
BIND 7
|
||||||
|
STAT 8
|
||||||
|
INIT 10
|
||||||
|
VERSION 11
|
||||||
|
======================== =============================================
|
||||||
|
|
||||||
|
MOUNT
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
This operation mounts a blob of data pointed to by path stored in `src`, at
|
||||||
|
filesystem location pointed to by path stored in `where`, using driver pointed
|
||||||
|
to by path in `spec`.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
^^^^^^^^^^
|
||||||
|
======== ============================================================
|
||||||
|
uint32_t FunctionID (0x82000030 / 0xC2000030)
|
||||||
|
uint32_t ``MOUNT``
|
||||||
|
======== ============================================================
|
||||||
|
|
||||||
|
Return values
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
=============== ==========================================================
|
||||||
|
int32_t w0 == SMC_OK on success
|
||||||
|
|
||||||
|
w0 == DEBUGFS_E_INVALID_PARAMS if mount operation failed
|
||||||
|
=============== ==========================================================
|
||||||
|
|
||||||
|
OPEN
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
This operation opens the file path pointed to by `fname`.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
======== ============================================================
|
||||||
|
uint32_t FunctionID (0x82000030 / 0xC2000030)
|
||||||
|
uint32_t ``OPEN``
|
||||||
|
uint32_t mode
|
||||||
|
======== ============================================================
|
||||||
|
|
||||||
|
mode can be one of:
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
enum mode {
|
||||||
|
O_READ = 1 << 0,
|
||||||
|
O_WRITE = 1 << 1,
|
||||||
|
O_RDWR = 1 << 2,
|
||||||
|
O_BIND = 1 << 3,
|
||||||
|
O_DIR = 1 << 4,
|
||||||
|
O_STAT = 1 << 5
|
||||||
|
};
|
||||||
|
|
||||||
|
Return values
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
=============== ==========================================================
|
||||||
|
int32_t w0 == SMC_OK on success
|
||||||
|
|
||||||
|
w0 == DEBUGFS_E_INVALID_PARAMS if open operation failed
|
||||||
|
|
||||||
|
uint32_t w1: file descriptor id on success.
|
||||||
|
=============== ==========================================================
|
||||||
|
|
||||||
|
CLOSE
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
This operation closes a file described by a file descriptor obtained by a
|
||||||
|
previous call to OPEN.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
======== ============================================================
|
||||||
|
uint32_t FunctionID (0x82000030 / 0xC2000030)
|
||||||
|
uint32_t ``CLOSE``
|
||||||
|
uint32_t File descriptor id returned by OPEN
|
||||||
|
======== ============================================================
|
||||||
|
|
||||||
|
Return values
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
=============== ==========================================================
|
||||||
|
int32_t w0 == SMC_OK on success
|
||||||
|
|
||||||
|
w0 == DEBUGFS_E_INVALID_PARAMS if close operation failed
|
||||||
|
=============== ==========================================================
|
||||||
|
|
||||||
|
READ
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
This operation reads a number of bytes from a file descriptor obtained by
|
||||||
|
a previous call to OPEN.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
======== ============================================================
|
||||||
|
uint32_t FunctionID (0x82000030 / 0xC2000030)
|
||||||
|
uint32_t ``READ``
|
||||||
|
uint32_t File descriptor id returned by OPEN
|
||||||
|
uint32_t Number of bytes to read
|
||||||
|
======== ============================================================
|
||||||
|
|
||||||
|
Return values
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
On success, the read data is retrieved from the shared buffer after the
|
||||||
|
operation.
|
||||||
|
|
||||||
|
=============== ==========================================================
|
||||||
|
int32_t w0 == SMC_OK on success
|
||||||
|
|
||||||
|
w0 == DEBUGFS_E_INVALID_PARAMS if read operation failed
|
||||||
|
|
||||||
|
uint32_t w1: number of bytes read on success.
|
||||||
|
=============== ==========================================================
|
||||||
|
|
||||||
|
SEEK
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
Move file pointer for file described by given `file descriptor` of given
|
||||||
|
`offset` related to `whence`.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
======== ============================================================
|
||||||
|
uint32_t FunctionID (0x82000030 / 0xC2000030)
|
||||||
|
uint32_t ``SEEK``
|
||||||
|
uint32_t File descriptor id returned by OPEN
|
||||||
|
sint32_t offset in the file relative to whence
|
||||||
|
uint32_t whence
|
||||||
|
======== ============================================================
|
||||||
|
|
||||||
|
whence can be one of:
|
||||||
|
|
||||||
|
========= ============================================================
|
||||||
|
KSEEK_SET 0
|
||||||
|
KSEEK_CUR 1
|
||||||
|
KSEEK_END 2
|
||||||
|
========= ============================================================
|
||||||
|
|
||||||
|
Return values
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
=============== ==========================================================
|
||||||
|
int32_t w0 == SMC_OK on success
|
||||||
|
|
||||||
|
w0 == DEBUGFS_E_INVALID_PARAMS if seek operation failed
|
||||||
|
=============== ==========================================================
|
||||||
|
|
||||||
|
BIND
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
Create a link from `oldpath` to `newpath`.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
======== ============================================================
|
||||||
|
uint32_t FunctionID (0x82000030 / 0xC2000030)
|
||||||
|
uint32_t ``BIND``
|
||||||
|
======== ============================================================
|
||||||
|
|
||||||
|
Return values
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
=============== ==========================================================
|
||||||
|
int32_t w0 == SMC_OK on success
|
||||||
|
|
||||||
|
w0 == DEBUGFS_E_INVALID_PARAMS if bind operation failed
|
||||||
|
=============== ==========================================================
|
||||||
|
|
||||||
|
STAT
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
Perform a stat operation on provided file `name` and returns the directory
|
||||||
|
entry statistics into `dir`.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
======== ============================================================
|
||||||
|
uint32_t FunctionID (0x82000030 / 0xC2000030)
|
||||||
|
uint32_t ``STAT``
|
||||||
|
======== ============================================================
|
||||||
|
|
||||||
|
Return values
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
=============== ==========================================================
|
||||||
|
int32_t w0 == SMC_OK on success
|
||||||
|
|
||||||
|
w0 == DEBUGFS_E_INVALID_PARAMS if stat operation failed
|
||||||
|
=============== ==========================================================
|
||||||
|
|
||||||
|
INIT
|
||||||
|
~~~~
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
Initial call to setup the shared exchange buffer. Notice if successful once,
|
||||||
|
subsequent calls fail after a first initialization. The caller maps the same
|
||||||
|
page frame in its virtual space and uses this buffer to exchange string
|
||||||
|
parameters with filesystem primitives.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
======== ============================================================
|
||||||
|
uint32_t FunctionID (0x82000030 / 0xC2000030)
|
||||||
|
uint32_t ``INIT``
|
||||||
|
uint64_t Physical address of the shared buffer.
|
||||||
|
======== ============================================================
|
||||||
|
|
||||||
|
Return values
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
=============== ======================================================
|
||||||
|
int32_t w0 == SMC_OK on success
|
||||||
|
|
||||||
|
w0 == DEBUGFS_E_INVALID_PARAMS if already initialized,
|
||||||
|
or internal error occurred.
|
||||||
|
=============== ======================================================
|
||||||
|
|
||||||
|
VERSION
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
Description
|
||||||
|
^^^^^^^^^^^
|
||||||
|
Returns the debugfs interface version if implemented in TF-A.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
======== ============================================================
|
||||||
|
uint32_t FunctionID (0x82000030 / 0xC2000030)
|
||||||
|
uint32_t ``VERSION``
|
||||||
|
======== ============================================================
|
||||||
|
|
||||||
|
Return values
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
=============== ======================================================
|
||||||
|
int32_t w0 == SMC_OK on success
|
||||||
|
|
||||||
|
w0 == SMC_UNK if interface is not implemented
|
||||||
|
|
||||||
|
uint32_t w1: On success, debugfs interface version, 32 bits
|
||||||
|
value with major version number in upper 16 bits and
|
||||||
|
minor version in lower 16 bits.
|
||||||
|
=============== ======================================================
|
||||||
|
|
||||||
|
* CREATE(1) and WRITE (5) command identifiers are unimplemented and
|
||||||
|
return `SMC_UNK`.
|
||||||
|
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
*Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.*
|
*Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.*
|
||||||
|
|
132
docs/components/debugfs-design.rst
Normal file
132
docs/components/debugfs-design.rst
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
========
|
||||||
|
Debug FS
|
||||||
|
========
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
The *DebugFS* feature is primarily aimed at exposing firmware debug data to
|
||||||
|
higher SW layers such as a non-secure component. Such component can be the
|
||||||
|
TFTF test payload or a Linux kernel module.
|
||||||
|
|
||||||
|
Virtual filesystem
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The core functionality lies in a virtual file system based on a 9p file server
|
||||||
|
interface (`Notes on the Plan 9 Kernel Source`_). The implementation permits
|
||||||
|
exposing virtual files, firmware drivers, and file blobs.
|
||||||
|
|
||||||
|
Namespace
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
Two namespaces are exposed:
|
||||||
|
|
||||||
|
- # is used as root for drivers (e.g. #t0 is the first uart)
|
||||||
|
- / is used as root for virtual "files" (e.g. /fip, or /dev/uart)
|
||||||
|
|
||||||
|
9p interface
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The associated primitives are:
|
||||||
|
|
||||||
|
- Unix-like:
|
||||||
|
|
||||||
|
- open(): create a file descriptor that acts as a handle to the file passed as
|
||||||
|
an argument.
|
||||||
|
- close(): close the file descriptor created by open().
|
||||||
|
- read(): read from a file to a buffer.
|
||||||
|
- write(): write from a buffer to a file.
|
||||||
|
- seek(): set the file position indicator of a file descriptor either to a
|
||||||
|
relative or an absolute offset.
|
||||||
|
- stat(): get information about a file (type, mode, size, ...).
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
int open(const char *name, int flags);
|
||||||
|
int close(int fd);
|
||||||
|
int read(int fd, void *buf, int n);
|
||||||
|
int write(int fd, void *buf, int n);
|
||||||
|
int seek(int fd, long off, int whence);
|
||||||
|
int stat(char *path, dir_t *dir);
|
||||||
|
|
||||||
|
- Specific primitives :
|
||||||
|
|
||||||
|
- mount(): create a link between a driver and spec.
|
||||||
|
- create(): create a file in a specific location.
|
||||||
|
- bind(): expose the content of a directory to another directory.
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
int mount(char *srv, char *mnt, char *spec);
|
||||||
|
int create(const char *name, int flags);
|
||||||
|
int bind(char *path, char *where);
|
||||||
|
|
||||||
|
This interface is embedded into the BL31 run-time payload when selected by build
|
||||||
|
options. The interface multiplexes drivers or emulated "files":
|
||||||
|
|
||||||
|
- Debug data can be partitioned into different virtual files e.g. expose PMF
|
||||||
|
measurements through a file, and internal firmware state counters through
|
||||||
|
another file.
|
||||||
|
- This permits direct access to a firmware driver, mainly for test purposes
|
||||||
|
(e.g. a hardware device that may not be accessible to non-privileged/
|
||||||
|
non-secure layers, or for which no support exists in the NS side).
|
||||||
|
|
||||||
|
SMC interface
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The communication with the 9p layer in BL31 is made through an SMC conduit
|
||||||
|
(`SMC Calling Convention PDD`_), using a specific SiP Function Id. An NS shared
|
||||||
|
buffer is used to pass path string parameters, or e.g. to exchange data on a
|
||||||
|
read operation. Refer to `ARM SiP Services`_ for a description of the SMC
|
||||||
|
interface.
|
||||||
|
|
||||||
|
Security considerations
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
- Due to the nature of the exposed data, the feature is considered experimental
|
||||||
|
and importantly **shall only be used in debug builds**.
|
||||||
|
- Several primitive imply string manipulations and usage of string formats.
|
||||||
|
- Special care is taken with the shared buffer to avoid TOCTOU attacks.
|
||||||
|
|
||||||
|
Limitations
|
||||||
|
-----------
|
||||||
|
|
||||||
|
- In order to setup the shared buffer, the component consuming the interface
|
||||||
|
needs to allocate a physical page frame and transmit its address.
|
||||||
|
- In order to map the shared buffer, BL31 requires enabling the dynamic xlat
|
||||||
|
table option.
|
||||||
|
- Data exchange is limited by the shared buffer length. A large read operation
|
||||||
|
might be split into multiple read operations of smaller chunks.
|
||||||
|
- On concurrent access, a spinlock is implemented in the BL31 service to protect
|
||||||
|
the internal work buffer, and re-entrancy into the filesystem layers.
|
||||||
|
- Notice, a physical device driver if exposed by the firmware may conflict with
|
||||||
|
the higher level OS if the latter implements its own driver for the same
|
||||||
|
physical device.
|
||||||
|
|
||||||
|
Applications
|
||||||
|
------------
|
||||||
|
|
||||||
|
The SMC interface is accessible from an NS environment, that is:
|
||||||
|
|
||||||
|
- a test payload, bootloader or hypervisor running at NS-EL2
|
||||||
|
- a Linux kernel driver running at NS-EL1
|
||||||
|
- a Linux userspace application through the kernel driver
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. [#] `SMC Calling Convention PDD`_
|
||||||
|
.. [#] `Notes on the Plan 9 Kernel Source`_
|
||||||
|
.. [#] `Linux 9p remote filesystem protocol`_
|
||||||
|
.. [#] `ARM SiP Services`_
|
||||||
|
|
||||||
|
--------------
|
||||||
|
|
||||||
|
*Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.*
|
||||||
|
|
||||||
|
.. _SMC Calling Convention PDD: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/
|
||||||
|
.. _Notes on the Plan 9 Kernel Source: http://lsub.org/who/nemo/9.pdf
|
||||||
|
.. _Linux 9p remote filesystem protocol: https://www.kernel.org/doc/Documentation/filesystems/9p.txt
|
||||||
|
.. _ARM SiP Services: arm-sip-service.rst
|
|
@ -544,6 +544,10 @@ Common build options
|
||||||
(Coherent memory region is included) or 0 (Coherent memory region is
|
(Coherent memory region is included) or 0 (Coherent memory region is
|
||||||
excluded). Default is 1.
|
excluded). Default is 1.
|
||||||
|
|
||||||
|
- ``USE_DEBUGFS``: When set to 1 this option activates an EXPERIMENTAL feature
|
||||||
|
exposing a virtual filesystem interface through BL31 as a SiP SMC function.
|
||||||
|
Default is 0.
|
||||||
|
|
||||||
- ``USE_ROMLIB``: This flag determines whether library at ROM will be used.
|
- ``USE_ROMLIB``: This flag determines whether library at ROM will be used.
|
||||||
This feature creates a library of functions to be placed in ROM and thus
|
This feature creates a library of functions to be placed in ROM and thus
|
||||||
reduces SRAM usage. Refer to :ref:`Library at ROM` for further details. Default
|
reduces SRAM usage. Refer to :ref:`Library at ROM` for further details. Default
|
||||||
|
|
|
@ -56,5 +56,28 @@ int stat(const char *path, dir_t *dir);
|
||||||
|
|
||||||
/* DebugFS initialization */
|
/* DebugFS initialization */
|
||||||
void debugfs_init(void);
|
void debugfs_init(void);
|
||||||
|
int debugfs_smc_setup(void);
|
||||||
|
|
||||||
|
/* Debugfs version returned through SMC interface */
|
||||||
|
#define DEBUGFS_VERSION (0x000000001U)
|
||||||
|
|
||||||
|
/* Function ID for accessing the debugfs interface */
|
||||||
|
#define DEBUGFS_FID_VALUE (0x30U)
|
||||||
|
|
||||||
|
#define is_debugfs_fid(_fid) \
|
||||||
|
(((_fid) & FUNCID_NUM_MASK) == DEBUGFS_FID_VALUE)
|
||||||
|
|
||||||
|
/* Error code for debugfs SMC interface failures */
|
||||||
|
#define DEBUGFS_E_INVALID_PARAMS (-2)
|
||||||
|
#define DEBUGFS_E_DENIED (-3)
|
||||||
|
|
||||||
|
uintptr_t debugfs_smc_handler(unsigned int smc_fid,
|
||||||
|
u_register_t cmd,
|
||||||
|
u_register_t arg2,
|
||||||
|
u_register_t arg3,
|
||||||
|
u_register_t arg4,
|
||||||
|
void *cookie,
|
||||||
|
void *handle,
|
||||||
|
uintptr_t flags);
|
||||||
|
|
||||||
#endif /* DEBUGFS_H */
|
#endif /* DEBUGFS_H */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -16,9 +16,15 @@
|
||||||
/* U(0x8200ff02) is reserved */
|
/* U(0x8200ff02) is reserved */
|
||||||
#define ARM_SIP_SVC_VERSION U(0x8200ff03)
|
#define ARM_SIP_SVC_VERSION U(0x8200ff03)
|
||||||
|
|
||||||
|
/* PMF_SMC_GET_TIMESTAMP_32 0x82000010 */
|
||||||
|
/* PMF_SMC_GET_TIMESTAMP_64 0xC2000010 */
|
||||||
|
|
||||||
/* Function ID for requesting state switch of lower EL */
|
/* Function ID for requesting state switch of lower EL */
|
||||||
#define ARM_SIP_SVC_EXE_STATE_SWITCH U(0x82000020)
|
#define ARM_SIP_SVC_EXE_STATE_SWITCH U(0x82000020)
|
||||||
|
|
||||||
|
/* DEBUGFS_SMC_32 0x82000030U */
|
||||||
|
/* DEBUGFS_SMC_64 0xC2000030U */
|
||||||
|
|
||||||
/* ARM SiP Service Calls version numbers */
|
/* ARM SiP Service Calls version numbers */
|
||||||
#define ARM_SIP_SVC_VERSION_MAJOR U(0x0)
|
#define ARM_SIP_SVC_VERSION_MAJOR U(0x0)
|
||||||
#define ARM_SIP_SVC_VERSION_MINOR U(0x2)
|
#define ARM_SIP_SVC_VERSION_MINOR U(0x2)
|
||||||
|
|
|
@ -9,3 +9,5 @@ DEBUGFS_SRCS := $(addprefix lib/debugfs/, \
|
||||||
devc.c \
|
devc.c \
|
||||||
devroot.c \
|
devroot.c \
|
||||||
devfip.c)
|
devfip.c)
|
||||||
|
|
||||||
|
DEBUGFS_SRCS += lib/debugfs/debugfs_smc.c
|
||||||
|
|
209
lib/debugfs/debugfs_smc.c
Normal file
209
lib/debugfs/debugfs_smc.c
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <lib/debugfs.h>
|
||||||
|
#include <lib/smccc.h>
|
||||||
|
#include <lib/spinlock.h>
|
||||||
|
#include <lib/xlat_tables/xlat_tables_v2.h>
|
||||||
|
#include <smccc_helpers.h>
|
||||||
|
|
||||||
|
#define MAX_PATH_LEN 256
|
||||||
|
|
||||||
|
#define MOUNT 0
|
||||||
|
#define CREATE 1
|
||||||
|
#define OPEN 2
|
||||||
|
#define CLOSE 3
|
||||||
|
#define READ 4
|
||||||
|
#define WRITE 5
|
||||||
|
#define SEEK 6
|
||||||
|
#define BIND 7
|
||||||
|
#define STAT 8
|
||||||
|
#define INIT 10
|
||||||
|
#define VERSION 11
|
||||||
|
|
||||||
|
/* This is the virtual address to which we map the NS shared buffer */
|
||||||
|
#define DEBUGFS_SHARED_BUF_VIRT ((void *)0x81000000U)
|
||||||
|
|
||||||
|
static union debugfs_parms {
|
||||||
|
struct {
|
||||||
|
char fname[MAX_PATH_LEN];
|
||||||
|
} open;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char srv[MAX_PATH_LEN];
|
||||||
|
char where[MAX_PATH_LEN];
|
||||||
|
char spec[MAX_PATH_LEN];
|
||||||
|
} mount;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char path[MAX_PATH_LEN];
|
||||||
|
dir_t dir;
|
||||||
|
} stat;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char oldpath[MAX_PATH_LEN];
|
||||||
|
char newpath[MAX_PATH_LEN];
|
||||||
|
} bind;
|
||||||
|
} parms;
|
||||||
|
|
||||||
|
/* debugfs_access_lock protects shared buffer and internal */
|
||||||
|
/* FS functions from concurrent acccesses. */
|
||||||
|
static spinlock_t debugfs_access_lock;
|
||||||
|
|
||||||
|
static bool debugfs_initialized;
|
||||||
|
|
||||||
|
uintptr_t debugfs_smc_handler(unsigned int smc_fid,
|
||||||
|
u_register_t cmd,
|
||||||
|
u_register_t arg2,
|
||||||
|
u_register_t arg3,
|
||||||
|
u_register_t arg4,
|
||||||
|
void *cookie,
|
||||||
|
void *handle,
|
||||||
|
u_register_t flags)
|
||||||
|
{
|
||||||
|
int64_t smc_ret = DEBUGFS_E_INVALID_PARAMS, smc_resp = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Allow calls from non-secure only */
|
||||||
|
if (is_caller_secure(flags)) {
|
||||||
|
SMC_RET1(handle, DEBUGFS_E_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expect a SiP service fast call */
|
||||||
|
if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
|
||||||
|
(GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
|
||||||
|
SMC_RET1(handle, SMC_UNK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Truncate parameters if 32b SMC convention call */
|
||||||
|
if (GET_SMC_CC(smc_fid) == SMC_32) {
|
||||||
|
arg2 &= 0xffffffff;
|
||||||
|
arg3 &= 0xffffffff;
|
||||||
|
arg4 &= 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock(&debugfs_access_lock);
|
||||||
|
|
||||||
|
if (debugfs_initialized == true) {
|
||||||
|
/* Copy NS shared buffer to internal secure location */
|
||||||
|
memcpy(&parms, (void *)DEBUGFS_SHARED_BUF_VIRT,
|
||||||
|
sizeof(union debugfs_parms));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case INIT:
|
||||||
|
if (debugfs_initialized == false) {
|
||||||
|
/* TODO: check PA validity e.g. whether */
|
||||||
|
/* it is an NS region. */
|
||||||
|
ret = mmap_add_dynamic_region(arg2,
|
||||||
|
(uintptr_t)DEBUGFS_SHARED_BUF_VIRT,
|
||||||
|
PAGE_SIZE_4KB,
|
||||||
|
MT_MEMORY | MT_RW | MT_NS);
|
||||||
|
if (ret == 0) {
|
||||||
|
debugfs_initialized = true;
|
||||||
|
smc_ret = SMC_OK;
|
||||||
|
smc_resp = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VERSION:
|
||||||
|
smc_ret = SMC_OK;
|
||||||
|
smc_resp = DEBUGFS_VERSION;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOUNT:
|
||||||
|
ret = mount(parms.mount.srv,
|
||||||
|
parms.mount.where,
|
||||||
|
parms.mount.spec);
|
||||||
|
if (ret == 0) {
|
||||||
|
smc_ret = SMC_OK;
|
||||||
|
smc_resp = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPEN:
|
||||||
|
ret = open(parms.open.fname, arg2);
|
||||||
|
if (ret >= 0) {
|
||||||
|
smc_ret = SMC_OK;
|
||||||
|
smc_resp = ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CLOSE:
|
||||||
|
ret = close(arg2);
|
||||||
|
if (ret == 0) {
|
||||||
|
smc_ret = SMC_OK;
|
||||||
|
smc_resp = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case READ:
|
||||||
|
ret = read(arg2, DEBUGFS_SHARED_BUF_VIRT, arg3);
|
||||||
|
if (ret >= 0) {
|
||||||
|
smc_ret = SMC_OK;
|
||||||
|
smc_resp = ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK:
|
||||||
|
ret = seek(arg2, arg3, arg4);
|
||||||
|
if (ret == 0) {
|
||||||
|
smc_ret = SMC_OK;
|
||||||
|
smc_resp = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BIND:
|
||||||
|
ret = bind(parms.bind.oldpath, parms.bind.newpath);
|
||||||
|
if (ret == 0) {
|
||||||
|
smc_ret = SMC_OK;
|
||||||
|
smc_resp = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STAT:
|
||||||
|
ret = stat(parms.stat.path, &parms.stat.dir);
|
||||||
|
if (ret == 0) {
|
||||||
|
memcpy((void *)DEBUGFS_SHARED_BUF_VIRT, &parms,
|
||||||
|
sizeof(union debugfs_parms));
|
||||||
|
smc_ret = SMC_OK;
|
||||||
|
smc_resp = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Not implemented */
|
||||||
|
case CREATE:
|
||||||
|
/* Intentional fall-through */
|
||||||
|
|
||||||
|
/* Not implemented */
|
||||||
|
case WRITE:
|
||||||
|
/* Intentional fall-through */
|
||||||
|
|
||||||
|
default:
|
||||||
|
smc_ret = SMC_UNK;
|
||||||
|
smc_resp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&debugfs_access_lock);
|
||||||
|
|
||||||
|
SMC_RET2(handle, smc_ret, smc_resp);
|
||||||
|
|
||||||
|
/* Not reached */
|
||||||
|
return smc_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int debugfs_smc_setup(void)
|
||||||
|
{
|
||||||
|
debugfs_initialized = false;
|
||||||
|
debugfs_access_lock.lock = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -122,6 +122,10 @@ const mmap_region_t plat_arm_mmap[] = {
|
||||||
#ifdef IMAGE_BL31
|
#ifdef IMAGE_BL31
|
||||||
const mmap_region_t plat_arm_mmap[] = {
|
const mmap_region_t plat_arm_mmap[] = {
|
||||||
ARM_MAP_SHARED_RAM,
|
ARM_MAP_SHARED_RAM,
|
||||||
|
#if USE_DEBUGFS
|
||||||
|
/* Required by devfip, can be removed if devfip is not used */
|
||||||
|
V2M_MAP_FLASH0_RW,
|
||||||
|
#endif /* USE_DEBUGFS */
|
||||||
ARM_MAP_EL3_TZC_DRAM,
|
ARM_MAP_EL3_TZC_DRAM,
|
||||||
V2M_MAP_IOFPGA,
|
V2M_MAP_IOFPGA,
|
||||||
MAP_DEVICE0,
|
MAP_DEVICE0,
|
||||||
|
|
|
@ -68,8 +68,12 @@
|
||||||
# define PLAT_SP_IMAGE_MAX_XLAT_TABLES 10
|
# define PLAT_SP_IMAGE_MAX_XLAT_TABLES 10
|
||||||
# else
|
# else
|
||||||
# define PLAT_ARM_MMAP_ENTRIES 8
|
# define PLAT_ARM_MMAP_ENTRIES 8
|
||||||
|
# if USE_DEBUGFS
|
||||||
|
# define MAX_XLAT_TABLES 6
|
||||||
|
# else
|
||||||
# define MAX_XLAT_TABLES 5
|
# define MAX_XLAT_TABLES 5
|
||||||
# endif
|
# endif
|
||||||
|
# endif
|
||||||
#elif defined(IMAGE_BL32)
|
#elif defined(IMAGE_BL32)
|
||||||
# define PLAT_ARM_MMAP_ENTRIES 8
|
# define PLAT_ARM_MMAP_ENTRIES 8
|
||||||
# define MAX_XLAT_TABLES 5
|
# define MAX_XLAT_TABLES 5
|
||||||
|
|
|
@ -291,6 +291,10 @@ else # if AArch64
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq (${USE_DEBUGFS},1)
|
||||||
|
BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
|
||||||
|
endif
|
||||||
|
|
||||||
# Add support for platform supplied linker script for BL31 build
|
# Add support for platform supplied linker script for BL31 build
|
||||||
$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
|
$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
#include <common/bl_common.h>
|
#include <common/bl_common.h>
|
||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
#include <drivers/console.h>
|
#include <drivers/console.h>
|
||||||
|
#include <lib/debugfs.h>
|
||||||
#include <lib/extensions/ras.h>
|
#include <lib/extensions/ras.h>
|
||||||
#include <lib/mmio.h>
|
#include <lib/mmio.h>
|
||||||
#include <lib/utils.h>
|
#include <lib/utils.h>
|
||||||
|
@ -231,6 +232,10 @@ void arm_bl31_platform_setup(void)
|
||||||
#if RAS_EXTENSION
|
#if RAS_EXTENSION
|
||||||
ras_init();
|
ras_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if USE_DEBUGFS
|
||||||
|
debugfs_init();
|
||||||
|
#endif /* USE_DEBUGFS */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
#include <common/runtime_svc.h>
|
#include <common/runtime_svc.h>
|
||||||
|
#include <lib/debugfs.h>
|
||||||
#include <lib/pmf/pmf.h>
|
#include <lib/pmf/pmf.h>
|
||||||
#include <plat/arm/common/arm_sip_svc.h>
|
#include <plat/arm/common/arm_sip_svc.h>
|
||||||
#include <plat/arm/common/plat_arm.h>
|
#include <plat/arm/common/plat_arm.h>
|
||||||
|
@ -20,8 +21,18 @@ DEFINE_SVC_UUID2(arm_sip_svc_uid,
|
||||||
|
|
||||||
static int arm_sip_setup(void)
|
static int arm_sip_setup(void)
|
||||||
{
|
{
|
||||||
if (pmf_setup() != 0)
|
if (pmf_setup() != 0) {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_DEBUGFS
|
||||||
|
|
||||||
|
if (debugfs_smc_setup() != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_DEBUGFS */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +59,15 @@ static uintptr_t arm_sip_handler(unsigned int smc_fid,
|
||||||
handle, flags);
|
handle, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_DEBUGFS
|
||||||
|
|
||||||
|
if (is_debugfs_fid(smc_fid)) {
|
||||||
|
return debugfs_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
|
||||||
|
handle, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_DEBUGFS */
|
||||||
|
|
||||||
switch (smc_fid) {
|
switch (smc_fid) {
|
||||||
case ARM_SIP_SVC_EXE_STATE_SWITCH: {
|
case ARM_SIP_SVC_EXE_STATE_SWITCH: {
|
||||||
u_register_t pc;
|
u_register_t pc;
|
||||||
|
|
Loading…
Add table
Reference in a new issue