Merge "debugfs: add SMC channel" into integration
diff --git a/docs/components/arm-sip-service.rst b/docs/components/arm-sip-service.rst
index 2d58586..01bc04d 100644
--- a/docs/components/arm-sip-service.rst
+++ b/docs/components/arm-sip-service.rst
@@ -17,6 +17,7 @@
 
 -  Performance Measurement Framework (PMF)
 -  Execution State Switching service
+-  DebugFS interface
 
 Source definitions for Arm SiP service are located in the ``arm_sip_svc.h`` header
 file.
@@ -87,6 +88,346 @@
 and 1 populated with the supplied *Cookie hi* and *Cookie lo* values,
 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.*
diff --git a/docs/components/debugfs-design.rst b/docs/components/debugfs-design.rst
new file mode 100644
index 0000000..06916f3
--- /dev/null
+++ b/docs/components/debugfs-design.rst
@@ -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
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 87429f2..37c28a5 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -558,6 +558,10 @@
    (Coherent memory region is included) or 0 (Coherent memory region is
    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.
    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
diff --git a/include/lib/debugfs.h b/include/lib/debugfs.h
index b7e3330..8ed237a 100644
--- a/include/lib/debugfs.h
+++ b/include/lib/debugfs.h
@@ -56,5 +56,28 @@
 
 /* DebugFS initialization */
 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 */
diff --git a/include/plat/arm/common/arm_sip_svc.h b/include/plat/arm/common/arm_sip_svc.h
index 16573ce..85fdb28 100644
--- a/include/plat/arm/common/arm_sip_svc.h
+++ b/include/plat/arm/common/arm_sip_svc.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
  */
@@ -16,9 +16,15 @@
 /*					U(0x8200ff02) is reserved */
 #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 */
 #define ARM_SIP_SVC_EXE_STATE_SWITCH	U(0x82000020)
 
+/* DEBUGFS_SMC_32			0x82000030U */
+/* DEBUGFS_SMC_64			0xC2000030U */
+
 /* ARM SiP Service Calls version numbers */
 #define ARM_SIP_SVC_VERSION_MAJOR		U(0x0)
 #define ARM_SIP_SVC_VERSION_MINOR		U(0x2)
diff --git a/lib/debugfs/debugfs.mk b/lib/debugfs/debugfs.mk
index 2c02600..138fc72 100644
--- a/lib/debugfs/debugfs.mk
+++ b/lib/debugfs/debugfs.mk
@@ -9,3 +9,5 @@
 			devc.c				\
 			devroot.c			\
 			devfip.c)
+
+DEBUGFS_SRCS    += lib/debugfs/debugfs_smc.c
diff --git a/lib/debugfs/debugfs_smc.c b/lib/debugfs/debugfs_smc.c
new file mode 100644
index 0000000..400c166
--- /dev/null
+++ b/lib/debugfs/debugfs_smc.c
@@ -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;
+}
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index c36cd6f..ffaa93d 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -119,6 +119,10 @@
 #ifdef IMAGE_BL31
 const mmap_region_t plat_arm_mmap[] = {
 	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,
 	V2M_MAP_IOFPGA,
 	MAP_DEVICE0,
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index fa855cf..f1afe36 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -68,7 +68,11 @@
 #  define PLAT_SP_IMAGE_MAX_XLAT_TABLES	10
 # else
 #  define PLAT_ARM_MMAP_ENTRIES		8
-#  define MAX_XLAT_TABLES		5
+#  if USE_DEBUGFS
+#   define MAX_XLAT_TABLES		6
+#  else
+#   define MAX_XLAT_TABLES		5
+#  endif
 # endif
 #elif defined(IMAGE_BL32)
 # define PLAT_ARM_MMAP_ENTRIES		8
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 55ad1c7..ea72e79 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -286,6 +286,10 @@
     endif
 endif
 
+ifeq (${USE_DEBUGFS},1)
+    BL31_CFLAGS	+=	-DPLAT_XLAT_TABLES_DYNAMIC=1
+endif
+
 # Add support for platform supplied linker script for BL31 build
 $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
 
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index ab90f46..939885f 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -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
  */
@@ -11,6 +11,7 @@
 #include <common/bl_common.h>
 #include <common/debug.h>
 #include <drivers/console.h>
+#include <lib/debugfs.h>
 #include <lib/extensions/ras.h>
 #include <lib/mmio.h>
 #include <lib/utils.h>
@@ -231,6 +232,10 @@
 #if RAS_EXTENSION
 	ras_init();
 #endif
+
+#if USE_DEBUGFS
+	debugfs_init();
+#endif /* USE_DEBUGFS */
 }
 
 /*******************************************************************************
diff --git a/plat/arm/common/arm_sip_svc.c b/plat/arm/common/arm_sip_svc.c
index a61f5f8..9f5d455 100644
--- a/plat/arm/common/arm_sip_svc.c
+++ b/plat/arm/common/arm_sip_svc.c
@@ -8,6 +8,7 @@
 
 #include <common/debug.h>
 #include <common/runtime_svc.h>
+#include <lib/debugfs.h>
 #include <lib/pmf/pmf.h>
 #include <plat/arm/common/arm_sip_svc.h>
 #include <plat/arm/common/plat_arm.h>
@@ -20,8 +21,18 @@
 
 static int arm_sip_setup(void)
 {
-	if (pmf_setup() != 0)
+	if (pmf_setup() != 0) {
 		return 1;
+	}
+
+#if USE_DEBUGFS
+
+	if (debugfs_smc_setup() != 0) {
+		return 1;
+	}
+
+#endif /* USE_DEBUGFS */
+
 	return 0;
 }
 
@@ -48,6 +59,15 @@
 				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) {
 	case ARM_SIP_SVC_EXE_STATE_SWITCH: {
 		/* Execution state can be switched only if EL3 is AArch64 */