Platform: IOCTL for platform-specific services

Introduce new API function in HAL and a new generic platform
service to provide the means for platforms to implement proprietary
functions using a uniform framework and a single secure entry point.

Change-Id: I72ddbb3342ae851fe9851ccb27a54c8f4322b01f
Signed-off-by: Miklos Balint <miklos.balint@arm.com>
diff --git a/docs/user_guides/services/tfm_platform_integration_guide.rst b/docs/user_guides/services/tfm_platform_integration_guide.rst
index a1733a4..4dffb84 100644
--- a/docs/user_guides/services/tfm_platform_integration_guide.rst
+++ b/docs/user_guides/services/tfm_platform_integration_guide.rst
@@ -27,12 +27,6 @@
 *********************
 TF-M Platform service
 *********************
-The Platform service exposes the following interfaces:
-
-.. code-block:: c
-
-    enum tfm_platform_err_t tfm_platform_system_reset(void)
-
 The Platform service interfaces and types are defined and documented in
 ``interface/include/tfm_platform_api.h``
 
@@ -43,47 +37,49 @@
   when the secure partitions request an action to the Platform service
   (e.g system reset).
 
-*************************
-Platform HAL system reset
-*************************
+************
+Platform HAL
+************
 
-The Platform service service relies on a platform-specific implementation to
-perform some functionalities (e.g. system reset). The platform-specific
-implementation of those APIs will be located in the platform service code
-section (TF-M level 3 isolation) in order to protect it from a direct call from
-other secure partitions.
+The Platform Service relies on a platform-specific implementation to
+perform some functionalities. Mandatory functionality (e.g. system reset)
+that are required to be implemented for a platform to be supported by TF-M have
+their dedicated HAL API functions. Additional platform-specific services can be
+provided using the IOCTL function call.
 
 For API specification, please check: ``platform/include/tfm_platform_system.h``
 
-An implementation is provided in all the supported platforms. Please,
-check  ``platform/ext/target/<SPECIFIC_TARGET_FOLDER>/tfm_platform_system.c``
+An implementation is provided in all the supported platforms. Please, check
+``platform/ext/target/<SPECIFIC_TARGET_FOLDER>/services/src/tfm_platform_system.c``
+for examples.
 
 The API **must** be implemented by the system integrators for their targets.
 
-The API **must** be implemented by the system integrators for their
-targets.
+IOCTL
+=====
 
-********************
-Platform pin service
-********************
-This service is designed to perform secure pin services of the platform
-(e.g alternate function setting, pin mode setting, etc).
-The veneer implementation follows IOVEC API implementation, which allows
-the NS application to pack many pin service requests into one service call
-to reduce the overhead of the Secure-Non-Secure context switch.
-Since packing many service requests into one call is application and use-case
-specific, the API implementations in ``tfm_platform_api.c`` and
-```tfm_platform_secure_api.c`` follow the one service in one veneer call design
-but the service implementation in tfm_platform_system.c is prepared to serve
-packed requests.
+A single entry point to platform-specific code across the HAL is provided by the
+IOCTL service and HAL function:
+
+.. code-block:: c
+
+  enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request,
+                                                 psa_invec *in_vec,
+                                                 psa_outvec *out_vec);
+
+A request type is provided by the client, with additional parameters contained
+in the optional ``in_vec`` parameter. An optional output buffer can be passed to
+the service in ``out_vec``.
+An IOCTL request type not supported on a particular platform should return
+``TFM_PLATFORM_ERR_NOT_SUPPORTED``
 
 ***************************
 Current Service Limitations
 ***************************
 - **system reset** - The system reset functionality is only supported in
-  isolation level 1. Currently, the mechanism by which PRoT services should run
-  in privileged mode in level 3, it is not in place due to an ongoing work in
-  TF-M Core. So, the ``NVIC_SystemReset`` call performed by the service, is
+  isolation level 1. Currently the mechanism by which PSA-RoT services should
+  run in privileged mode in level 3 is not in place due to an ongoing work in
+  TF-M Core. So, the ``NVIC_SystemReset`` call performed by the service is
   expected to generate a memory fault when it tries to access the ``SCB->AIRCR``
   register in level 3 isolation.
 
@@ -108,7 +104,7 @@
 `DEBUG_AUTHENTICATION` is `DAUTH_CHIP_DEFAULT`.
 
 .. Note::
-   `void tfm_spm_hal_init_debug(void)` is called during the TF-M core
+   ``void tfm_spm_hal_init_debug(void)`` is called during the TF-M core
    initialisation phase, before initialising secure partition. This means that BL2
    runs with the chip default setting.
 
diff --git a/interface/include/tfm_platform_api.h b/interface/include/tfm_platform_api.h
index 7cc57ab..9c4e023 100644
--- a/interface/include/tfm_platform_api.h
+++ b/interface/include/tfm_platform_api.h
@@ -10,6 +10,7 @@
 
 #include <limits.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include "tfm_api.h"
 
 #ifdef __cplusplus
@@ -20,7 +21,7 @@
  * \brief TFM secure partition platform API version
  */
 #define TFM_PLATFORM_API_VERSION_MAJOR (0)
-#define TFM_PLATFORM_API_VERSION_MINOR (2)
+#define TFM_PLATFORM_API_VERSION_MINOR (3)
 
 /* The return value is shared with the TF-M partition status value.
  * The Platform return codes shouldn't overlap with predefined TFM status
@@ -38,11 +39,14 @@
     TFM_PLATFORM_ERR_SUCCESS = 0,
     TFM_PLATFORM_ERR_SYSTEM_ERROR = TFM_PLATFORM_ERR_OFFSET,
     TFM_PLATFORM_ERR_INVALID_PARAM,
+    TFM_PLATFORM_ERR_NOT_SUPPORTED,
 
     /* Following entry is only to ensure the error code of int size */
     TFM_PLATFORM_ERR_FORCE_INT_SIZE = INT_MAX
 };
 
+typedef int32_t tfm_platform_ioctl_req_t;
+
 /*!
  * \brief Resets the system.
  *
@@ -51,47 +55,18 @@
 enum tfm_platform_err_t tfm_platform_system_reset(void);
 
 /*!
- * \brief Sets pin alternate function for the given pins
+ * \brief Performs a platform-specific service
  *
- * \param[in]  alt_func     Alternate function to set (allowed values vary
+ * \param[in]  request      Request identifier (valid values vary
  *                          based on the platform)
- * \param[in]  pin_mask     Pin mask of the selected pins
- * \param[out] result       Return error value
+ * \param[in]  input        Input buffer to the requested service (or NULL)
+ * \param[in,out] output    Output buffer to the requested service (or NULL)
  *
  * \return Returns values as specified by the \ref tfm_platform_err_t
  */
-enum tfm_platform_err_t
-tfm_platform_set_pin_alt_func(uint32_t alt_func, uint64_t pin_mask,
-                              uint32_t *result);
-
-/*!
- * \brief Sets default in value to use when the alternate function is not
- *        selected for the pin
- *
- * \param[in]  alt_func          Alternate function to use (allowed values vary
- *                               based on the platform)
- * \param[in]  pin_value         Pin value to use
- * \param[in]  default_in_value  Default in value to set
- * \param[out] result            Return error value
- *
- * \return Returns values as specified by the \ref tfm_platform_err_t
- */
-enum tfm_platform_err_t
-tfm_platform_set_pin_default_in(uint32_t alt_func, uint32_t pin_value,
-                                bool default_in_value, uint32_t *result);
-
-/*!
- * \brief Sets pin mode for the selected pins
- *
- * \param[in]  pin_mask     Pin mask of the selected pins
- * \param[in]  pin_mode     Pin mode to set for the selected pins
- * \param[out] result       Return error value
- *
- * \return Returns values as specified by the \ref tfm_platform_err_t
- */
-enum tfm_platform_err_t
-tfm_platform_set_pin_mode(uint64_t pin_mask, uint32_t pin_mode,
-                          uint32_t *result);
+enum tfm_platform_err_t tfm_platform_ioctl(tfm_platform_ioctl_req_t request,
+                                           psa_invec *input,
+                                           psa_outvec *output);
 
 
 #ifdef __cplusplus
diff --git a/interface/include/tfm_platform_defs.h b/interface/include/tfm_platform_defs.h
deleted file mode 100644
index 23fe4e0..0000000
--- a/interface/include/tfm_platform_defs.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2019, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef __TFM_PLATFORM_DEFS__
-#define __TFM_PLATFORM_DEFS__
-
-#include <stdint.h>
-#include <limits.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*!
- * \enum tfm_pin_service_type_t
- *
- * \brief Pin service types (supported types may vary based on the platform)
- */
-enum tfm_pin_service_type_t {
-    TFM_PIN_SERVICE_TYPE_SET_ALTFUNC     = 0,   /*!< Set alternate function type */
-    TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN,        /*!< Set default in function type */
-    TFM_PIN_SERVICE_TYPE_SET_PIN_MODE,          /*!< Set pin mode function type */
-    TFM_PIN_SERVICE_TYPE_MAX = INT_MAX          /*!< Max to force enum max size */
-};
-
-/*!
- * \struct tfm_pin_service_args_t
- *
- * \brief Argument list for each platform pin service
- */
-struct tfm_pin_service_args_t {
-    enum tfm_pin_service_type_t type;
-    union {
-        struct set_altfunc { /*!< TFM_PIN_SERVICE_TYPE_SET_ALTFUNC */
-            uint32_t alt_func;
-            uint64_t pin_mask;
-        } set_altfunc;
-        struct set_default_in { /*!< TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN */
-            uint32_t alt_func;
-            uint32_t pin_value;
-            bool default_in_value;
-        } set_default_in;
-        struct set_pin_mode { /*!< TFM_PIN_SERVICE_TYPE_SET_PIN_MODE */
-            uint64_t pin_mask;
-            uint32_t pin_mode;
-        } set_pin_mode;
-    } u;
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __TFM_PLATFORM_DEFS__ */
diff --git a/interface/include/tfm_platform_veneers.h b/interface/include/tfm_platform_veneers.h
deleted file mode 100644
index 313927e..0000000
--- a/interface/include/tfm_platform_veneers.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef __TFM_PLATFORM_VENEERS_H__
-#define __TFM_PLATFORM_VENEERS_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "tfm_platform_api.h"
-
-/*!
- * \brief Resets the system.
- *
- * \return Returns values as specified by the \ref tfm_platform_err_t
- */
-enum tfm_platform_err_t tfm_platform_veneer_system_reset(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __TFM_PLATFORM_VENEERS_H__ */
diff --git a/interface/include/tfm_veneers.h b/interface/include/tfm_veneers.h
index db3de27..71bc9e8 100644
--- a/interface/include/tfm_veneers.h
+++ b/interface/include/tfm_veneers.h
@@ -80,7 +80,7 @@
 #ifdef TFM_PARTITION_PLATFORM
 /******** TFM_SP_PLATFORM ********/
 psa_status_t tfm_platform_sp_system_reset_veneer(psa_invec *in_vec, size_t in_len, psa_outvec *out_vec, size_t out_len);
-psa_status_t tfm_platform_sp_pin_service_veneer(psa_invec *in_vec, size_t in_len, psa_outvec *out_vec, size_t out_len);
+psa_status_t tfm_platform_sp_ioctl_veneer(psa_invec *in_vec, size_t in_len, psa_outvec *out_vec, size_t out_len);
 #endif /* TFM_PARTITION_PLATFORM */
 
 /******** TFM_SP_INITIAL_ATTESTATION ********/
diff --git a/interface/src/tfm_platform_api.c b/interface/src/tfm_platform_api.c
index 9b6f787..b3daa07 100644
--- a/interface/src/tfm_platform_api.c
+++ b/interface/src/tfm_platform_api.c
@@ -7,14 +7,13 @@
 
 #include <stdbool.h>
 #include "tfm_platform_api.h"
-#include "tfm_platform_veneers.h"
 #include "tfm_ns_lock.h"
-#include "tfm_platform_defs.h"
 #include "tfm_veneers.h"
 
 enum tfm_platform_err_t tfm_platform_system_reset(void)
 {
-    return tfm_ns_lock_dispatch((veneer_fn)tfm_platform_veneer_system_reset,
+    return (enum tfm_platform_err_t) tfm_ns_lock_dispatch(
+                                (veneer_fn)tfm_platform_sp_system_reset_veneer,
                                 0,
                                 0,
                                 0,
@@ -22,93 +21,32 @@
 }
 
 enum tfm_platform_err_t
-tfm_platform_set_pin_alt_func(uint32_t alt_func, uint64_t pin_mask,
-                              uint32_t *result)
+tfm_platform_ioctl(tfm_platform_ioctl_req_t request,
+                   psa_invec *input, psa_outvec *output)
 {
-    enum tfm_platform_err_t ret;
-    psa_invec in_vec;
-    psa_outvec out_vec;
-    struct tfm_pin_service_args_t args;
+    tfm_platform_ioctl_req_t req = request;
+    struct psa_invec in_vec[2];
+    size_t inlen, outlen;
 
-    if (result == NULL) {
-        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    in_vec[0].base = &req;
+    in_vec[0].len = sizeof(req);
+    if (input != NULL) {
+        in_vec[1].base = input->base;
+        in_vec[1].len = input->len;
+        inlen = 2;
+    } else {
+        inlen = 1;
     }
 
-    args.type = TFM_PIN_SERVICE_TYPE_SET_ALTFUNC;
-    args.u.set_altfunc.alt_func = alt_func;
-    args.u.set_altfunc.pin_mask = pin_mask;
-
-    in_vec.base = (const void *)&args;
-    in_vec.len = sizeof(args);
-
-    out_vec.base = (void *)result;
-    out_vec.len = sizeof(*result);
-
-    ret = tfm_ns_lock_dispatch((veneer_fn)tfm_platform_sp_pin_service_veneer,
-                                (uint32_t)&in_vec,  1,
-                                (uint32_t)&out_vec, 1);
-
-    return ret;
-}
-
-enum tfm_platform_err_t
-tfm_platform_set_pin_default_in(uint32_t alt_func, uint32_t pin_value,
-                              bool default_in_value, uint32_t *result)
-{
-    enum tfm_platform_err_t ret;
-    psa_invec in_vec;
-    psa_outvec out_vec;
-    struct tfm_pin_service_args_t args;
-
-    if (result == NULL) {
-        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    if (output != NULL) {
+        outlen = 1;
+    } else {
+        outlen = 0;
     }
 
-    args.type = TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN;
-    args.u.set_default_in.alt_func = alt_func;
-    args.u.set_default_in.pin_value = pin_value;
-    args.u.set_default_in.default_in_value = default_in_value;
-
-    in_vec.base = (const void *)&args;
-    in_vec.len = sizeof(args);
-
-    out_vec.base = (void *)result;
-    out_vec.len = sizeof(*result);
-
-    ret = tfm_ns_lock_dispatch((veneer_fn)tfm_platform_sp_pin_service_veneer,
-                                (uint32_t)&in_vec,  1,
-                                (uint32_t)&out_vec, 1);
-
-    return ret;
-}
-
-enum tfm_platform_err_t
-tfm_platform_set_pin_mode(uint64_t pin_mask, uint32_t pin_mode,
-                          uint32_t *result)
-{
-    enum tfm_platform_err_t ret;
-    psa_invec in_vec;
-    psa_outvec out_vec;
-    struct tfm_pin_service_args_t args;
-
-    if (result == NULL) {
-        return TFM_PLATFORM_ERR_INVALID_PARAM;
-    }
-
-    args.type = TFM_PIN_SERVICE_TYPE_SET_PIN_MODE;
-    args.u.set_pin_mode.pin_mask = pin_mask;
-    args.u.set_pin_mode.pin_mode = pin_mode;
-
-    in_vec.base = (const void *)&args;
-    in_vec.len = sizeof(args);
-
-    out_vec.base = (void *)result;
-    out_vec.len = sizeof(*result);
-
-    ret = tfm_ns_lock_dispatch((veneer_fn)tfm_platform_sp_pin_service_veneer,
-                                (uint32_t)&in_vec,  1,
-                                (uint32_t)&out_vec, 1);
-
-    return ret;
+    return (enum tfm_platform_err_t) tfm_ns_lock_dispatch(
+                                (veneer_fn)tfm_platform_sp_ioctl_veneer,
+                                (uint32_t)in_vec, (uint32_t)inlen,
+                                (uint32_t)output, (uint32_t)outlen);
 }
 
diff --git a/platform/ext/Mps2AN519.cmake b/platform/ext/Mps2AN519.cmake
index 53f5833..1268299 100644
--- a/platform/ext/Mps2AN519.cmake
+++ b/platform/ext/Mps2AN519.cmake
@@ -121,7 +121,7 @@
   list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an519/attest_hal.c")
   list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an519/native_drivers/mpu_armv8m_drv.c")
   if (TFM_PARTITION_PLATFORM)
-    list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an519/tfm_platform_system.c")
+    list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an519/services/src/tfm_platform_system.c")
   endif()
   embedded_include_directories(PATH "${PLATFORM_DIR}/common" ABSOLUTE)
 endif()
diff --git a/platform/ext/Mps2AN521.cmake b/platform/ext/Mps2AN521.cmake
index f15b976..339ebf0 100644
--- a/platform/ext/Mps2AN521.cmake
+++ b/platform/ext/Mps2AN521.cmake
@@ -122,7 +122,7 @@
   list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an521/attest_hal.c")
   list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an521/native_drivers/mpu_armv8m_drv.c")
   if (TFM_PARTITION_PLATFORM)
-    list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an521/tfm_platform_system.c")
+    list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/mps2/an521/services/src/tfm_platform_system.c")
   endif()
   embedded_include_directories(PATH "${PLATFORM_DIR}/common" ABSOLUTE)
 endif()
diff --git a/platform/ext/musca_a.cmake b/platform/ext/musca_a.cmake
index 913061d..950e96b 100644
--- a/platform/ext/musca_a.cmake
+++ b/platform/ext/musca_a.cmake
@@ -122,7 +122,7 @@
   list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_a/attest_hal.c")
   list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_a/Native_Driver/mpu_armv8m_drv.c")
   if (TFM_PARTITION_PLATFORM)
-    list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_a/tfm_platform_system.c")
+    list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_a/services/src/tfm_platform_system.c")
   endif()
   embedded_include_directories(PATH "${PLATFORM_DIR}/common" ABSOLUTE)
 endif()
diff --git a/platform/ext/musca_b1.cmake b/platform/ext/musca_b1.cmake
index 5fbd488..894d731 100644
--- a/platform/ext/musca_b1.cmake
+++ b/platform/ext/musca_b1.cmake
@@ -51,8 +51,13 @@
 embedded_include_directories(PATH "${PLATFORM_DIR}/target/musca_b1/Device/Include" ABSOLUTE)
 embedded_include_directories(PATH "${PLATFORM_DIR}/target/musca_b1/Native_Driver" ABSOLUTE)
 embedded_include_directories(PATH "${PLATFORM_DIR}/target/musca_b1/partition" ABSOLUTE)
+embedded_include_directories(PATH "${PLATFORM_DIR}/target/musca_b1/services/include" ABSOLUTE)
 
 # Gather all source files we need.
+if (TFM_PARTITION_PLATFORM)
+    list(APPEND ALL_SRC_C_NS "${PLATFORM_DIR}/target/musca_b1/services/src/tfm_ioctl_ns_api.c")
+endif()
+
 if (NOT DEFINED BUILD_CMSIS_CORE)
     message(FATAL_ERROR "Configuration variable BUILD_CMSIS_CORE (true|false) is undefined!")
 elseif (BUILD_CMSIS_CORE)
@@ -122,7 +127,8 @@
     list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_b1/attest_hal.c")
     list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_b1/Native_Driver/mpu_armv8m_drv.c")
     if (TFM_PARTITION_PLATFORM)
-        list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_b1/tfm_platform_system.c")
+        list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_b1/services/src/tfm_platform_system.c")
+        list(APPEND ALL_SRC_C_S "${PLATFORM_DIR}/target/musca_b1/services/src/tfm_ioctl_s_api.c")
     endif()
     embedded_include_directories(PATH "${PLATFORM_DIR}/common" ABSOLUTE)
 endif()
diff --git a/platform/ext/target/mps2/an519/services/src/tfm_platform_system.c b/platform/ext/target/mps2/an519/services/src/tfm_platform_system.c
new file mode 100644
index 0000000..93ba614
--- /dev/null
+++ b/platform/ext/target/mps2/an519/services/src/tfm_platform_system.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "platform/include/tfm_platform_system.h"
+#include "cmsis.h"
+
+void tfm_platform_hal_system_reset(void)
+{
+    /* Reset the system */
+    NVIC_SystemReset();
+}
+
+enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request,
+                                               psa_invec  *in_vec,
+                                               psa_outvec *out_vec)
+{
+    (void)request;
+    (void)in_vec;
+    (void)out_vec;
+
+    /* Not needed for this platform */
+    return TFM_PLATFORM_ERR_NOT_SUPPORTED;
+}
+
diff --git a/platform/ext/target/mps2/an519/tfm_platform_system.c b/platform/ext/target/mps2/an519/tfm_platform_system.c
deleted file mode 100644
index 26c2a73..0000000
--- a/platform/ext/target/mps2/an519/tfm_platform_system.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include "platform/include/tfm_platform_system.h"
-#include "cmsis.h"
-
-void tfm_platform_hal_system_reset(void)
-{
-    /* Reset the system */
-    NVIC_SystemReset();
-}
-
-enum tfm_plat_err_t
-tfm_platform_hal_pin_service(const psa_invec  *in_vec,  uint32_t num_invec,
-                             const psa_outvec *out_vec, uint32_t num_outvec)
-{
-    (void)in_vec;
-    (void)num_invec;
-    (void)out_vec;
-    (void)num_outvec;
-    /* Not needed for this platform */
-    return TFM_PLAT_ERR_SUCCESS;
-}
-
diff --git a/platform/ext/target/mps2/an521/services/src/tfm_platform_system.c b/platform/ext/target/mps2/an521/services/src/tfm_platform_system.c
new file mode 100644
index 0000000..93ba614
--- /dev/null
+++ b/platform/ext/target/mps2/an521/services/src/tfm_platform_system.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "platform/include/tfm_platform_system.h"
+#include "cmsis.h"
+
+void tfm_platform_hal_system_reset(void)
+{
+    /* Reset the system */
+    NVIC_SystemReset();
+}
+
+enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request,
+                                               psa_invec  *in_vec,
+                                               psa_outvec *out_vec)
+{
+    (void)request;
+    (void)in_vec;
+    (void)out_vec;
+
+    /* Not needed for this platform */
+    return TFM_PLATFORM_ERR_NOT_SUPPORTED;
+}
+
diff --git a/platform/ext/target/mps2/an521/tfm_platform_system.c b/platform/ext/target/mps2/an521/tfm_platform_system.c
deleted file mode 100644
index 26c2a73..0000000
--- a/platform/ext/target/mps2/an521/tfm_platform_system.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include "platform/include/tfm_platform_system.h"
-#include "cmsis.h"
-
-void tfm_platform_hal_system_reset(void)
-{
-    /* Reset the system */
-    NVIC_SystemReset();
-}
-
-enum tfm_plat_err_t
-tfm_platform_hal_pin_service(const psa_invec  *in_vec,  uint32_t num_invec,
-                             const psa_outvec *out_vec, uint32_t num_outvec)
-{
-    (void)in_vec;
-    (void)num_invec;
-    (void)out_vec;
-    (void)num_outvec;
-    /* Not needed for this platform */
-    return TFM_PLAT_ERR_SUCCESS;
-}
-
diff --git a/platform/ext/target/musca_a/services/src/tfm_platform_system.c b/platform/ext/target/musca_a/services/src/tfm_platform_system.c
new file mode 100644
index 0000000..78d8f38
--- /dev/null
+++ b/platform/ext/target/musca_a/services/src/tfm_platform_system.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "platform/include/tfm_platform_system.h"
+#include "platform_description.h"
+
+void tfm_platform_hal_system_reset(void)
+{
+    /* Reset the system */
+    NVIC_SystemReset();
+}
+
+enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request,
+                                               psa_invec  *in_vec,
+                                               psa_outvec *out_vec)
+{
+    (void)request;
+    (void)in_vec;
+    (void)out_vec;
+
+    /* Not needed for this platform */
+    return TFM_PLATFORM_ERR_NOT_SUPPORTED;
+}
+
diff --git a/platform/ext/target/musca_a/tfm_platform_system.c b/platform/ext/target/musca_a/tfm_platform_system.c
deleted file mode 100644
index cc21804..0000000
--- a/platform/ext/target/musca_a/tfm_platform_system.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include "platform/include/tfm_platform_system.h"
-#include "platform_description.h"
-
-void tfm_platform_hal_system_reset(void)
-{
-    /* Reset the system */
-    NVIC_SystemReset();
-}
-
-enum tfm_plat_err_t
-tfm_platform_hal_pin_service(const psa_invec  *in_vec,  uint32_t num_invec,
-                             const psa_outvec *out_vec, uint32_t num_outvec)
-{
-    (void)in_vec;
-    (void)num_invec;
-    (void)out_vec;
-    (void)num_outvec;
-    /* SCC is configured as non-secure through PPC,
-     * so this function is not needed on this platform
-     */
-    return TFM_PLAT_ERR_SUCCESS;
-}
-
diff --git a/platform/ext/target/musca_b1/readme.rst b/platform/ext/target/musca_b1/readme.rst
index 159af55..212c28f 100644
--- a/platform/ext/target/musca_b1/readme.rst
+++ b/platform/ext/target/musca_b1/readme.rst
@@ -10,6 +10,16 @@
 `Arm Community page <https://community.arm.com/developer/tools-software/oss-platforms/w/docs/425/musca-b1-firmware-update-qspi-boot-recovery>`__
 A short description of how to update the DAPLink FW can be found there as well.
 
+********************
+Platform pin service
+********************
+
+This service is designed to perform secure pin services of the platform
+(e.g alternate function setting, pin mode setting, etc).
+The service uses the IOCTL API of TF-M's Platform Service, which allows the
+non-secure application to make pin service requests on Musca B1 based on a
+generic service request delivery mechanism.
+
 --------------
 
 *Copyright (c) 2017-2019, Arm Limited. All rights reserved.*
diff --git a/platform/ext/target/musca_b1/services/include/tfm_ioctl_api.h b/platform/ext/target/musca_b1/services/include/tfm_ioctl_api.h
new file mode 100644
index 0000000..6109a7e
--- /dev/null
+++ b/platform/ext/target/musca_b1/services/include/tfm_ioctl_api.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_IOCTL_API__
+#define __TFM_IOCTL_API__
+
+#include <limits.h>
+#include <stdbool.h>
+#include "tfm_api.h"
+#include "tfm_platform_api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum tfm_platform_ioctl_reqest_types_t {
+    TFM_PLATFORM_IOCTL_PIN_SERVICE,
+};
+
+/*!
+ * \enum tfm_pin_service_type_t
+ *
+ * \brief Pin service types
+ */
+enum tfm_pin_service_type_t {
+    TFM_PIN_SERVICE_TYPE_SET_ALTFUNC     = 0,   /*!< Set alternate function type */
+    TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN,        /*!< Set default in function type */
+    TFM_PIN_SERVICE_TYPE_SET_PIN_MODE,          /*!< Set pin mode function type */
+    TFM_PIN_SERVICE_TYPE_MAX = INT_MAX          /*!< Max to force enum max size */
+};
+
+/*!
+ * \struct tfm_pin_service_args_t
+ *
+ * \brief Argument list for each platform pin service
+ */
+struct tfm_pin_service_args_t {
+    enum tfm_pin_service_type_t type;
+    union {
+        struct set_altfunc { /*!< TFM_PIN_SERVICE_TYPE_SET_ALTFUNC */
+            uint32_t alt_func;
+            uint64_t pin_mask;
+        } set_altfunc;
+        struct set_default_in { /*!< TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN */
+            uint32_t alt_func;
+            uint32_t pin_value;
+            bool default_in_value;
+        } set_default_in;
+        struct set_pin_mode { /*!< TFM_PIN_SERVICE_TYPE_SET_PIN_MODE */
+            uint64_t pin_mask;
+            uint32_t pin_mode;
+        } set_pin_mode;
+    } u;
+};
+
+/*!
+ * \brief Sets pin alternate function for the given pins
+ *
+ * \param[in]  alt_func     Alternate function to set (allowed values vary
+ *                          based on the platform)
+ * \param[in]  pin_mask     Pin mask of the selected pins
+ * \param[out] result       Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t
+tfm_platform_set_pin_alt_func(uint32_t alt_func, uint64_t pin_mask,
+                              uint32_t *result);
+
+/*!
+ * \brief Sets default in value to use when the alternate function is not
+ *        selected for the pin
+ *
+ * \param[in]  alt_func          Alternate function to use (allowed values vary
+ *                               based on the platform)
+ * \param[in]  pin_value         Pin value to use
+ * \param[in]  default_in_value  Default in value to set
+ * \param[out] result            Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t
+tfm_platform_set_pin_default_in(uint32_t alt_func, uint32_t pin_value,
+                                bool default_in_value, uint32_t *result);
+
+/*!
+ * \brief Sets pin mode for the selected pins
+ *
+ * \param[in]  pin_mask     Pin mask of the selected pins
+ * \param[in]  pin_mode     Pin mode to set for the selected pins
+ * \param[out] result       Return error value
+ *
+ * \return Returns values as specified by the \ref tfm_platform_err_t
+ */
+enum tfm_platform_err_t
+tfm_platform_set_pin_mode(uint64_t pin_mask, uint32_t pin_mode,
+                          uint32_t *result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_IOCTL_API__ */
diff --git a/platform/ext/target/musca_b1/services/src/tfm_ioctl_ns_api.c b/platform/ext/target/musca_b1/services/src/tfm_ioctl_ns_api.c
new file mode 100644
index 0000000..6c83aeb
--- /dev/null
+++ b/platform/ext/target/musca_b1/services/src/tfm_ioctl_ns_api.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_platform_api.h"
+#include "services/include/tfm_ioctl_api.h"
+
+enum tfm_platform_err_t
+tfm_platform_set_pin_alt_func(uint32_t alt_func, uint64_t pin_mask,
+                              uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_pin_service_args_t args;
+
+    if (result == NULL) {
+        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    }
+
+    args.type = TFM_PIN_SERVICE_TYPE_SET_ALTFUNC;
+    args.u.set_altfunc.alt_func = alt_func;
+    args.u.set_altfunc.pin_mask = pin_mask;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)result;
+    out_vec.len = sizeof(*result);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_PIN_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    return ret;
+}
+
+enum tfm_platform_err_t
+tfm_platform_set_pin_default_in(uint32_t alt_func, uint32_t pin_value,
+                              bool default_in_value, uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_pin_service_args_t args;
+
+    if (result == NULL) {
+        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    }
+
+    args.type = TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN;
+    args.u.set_default_in.alt_func = alt_func;
+    args.u.set_default_in.pin_value = pin_value;
+    args.u.set_default_in.default_in_value = default_in_value;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)result;
+    out_vec.len = sizeof(*result);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_PIN_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    return ret;
+}
+
+enum tfm_platform_err_t
+tfm_platform_set_pin_mode(uint64_t pin_mask, uint32_t pin_mode,
+                          uint32_t *result)
+{
+    enum tfm_platform_err_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_pin_service_args_t args;
+
+    if (result == NULL) {
+        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    }
+
+    args.type = TFM_PIN_SERVICE_TYPE_SET_PIN_MODE;
+    args.u.set_pin_mode.pin_mask = pin_mask;
+    args.u.set_pin_mode.pin_mode = pin_mode;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)result;
+    out_vec.len = sizeof(*result);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_PIN_SERVICE,
+                             &in_vec,
+                             &out_vec);
+
+    return ret;
+}
+
diff --git a/platform/ext/target/musca_b1/services/src/tfm_ioctl_s_api.c b/platform/ext/target/musca_b1/services/src/tfm_ioctl_s_api.c
new file mode 100644
index 0000000..29efe86
--- /dev/null
+++ b/platform/ext/target/musca_b1/services/src/tfm_ioctl_s_api.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_platform_api.h"
+#include "services/include/tfm_ioctl_api.h"
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t
+tfm_platform_set_pin_alt_func(uint32_t alt_func, uint64_t pin_mask,
+                              uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_pin_service_args_t args;
+
+    if (result == NULL) {
+        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    }
+
+    args.type = TFM_PIN_SERVICE_TYPE_SET_ALTFUNC;
+    args.u.set_altfunc.alt_func = alt_func;
+    args.u.set_altfunc.pin_mask = pin_mask;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)result;
+    out_vec.len = sizeof(*result);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_PIN_SERVICE, &in_vec, &out_vec);
+
+    if (ret != PSA_SUCCESS) {
+        return TFM_PLATFORM_ERR_SYSTEM_ERROR;
+    }
+
+    return TFM_PLATFORM_ERR_SUCCESS;
+}
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t
+tfm_platform_set_pin_default_in(uint32_t alt_func, uint32_t pin_value,
+                              bool default_in_value, uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_pin_service_args_t args;
+
+    if (result == NULL) {
+        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    }
+
+    args.type = TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN;
+    args.u.set_default_in.alt_func = alt_func;
+    args.u.set_default_in.pin_value = pin_value;
+    args.u.set_default_in.default_in_value = default_in_value;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)result;
+    out_vec.len = sizeof(*result);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_PIN_SERVICE, &in_vec, &out_vec);
+
+    if (ret != PSA_SUCCESS) {
+        return TFM_PLATFORM_ERR_SYSTEM_ERROR;
+    }
+
+    return TFM_PLATFORM_ERR_SUCCESS;
+}
+
+__attribute__((section("SFN")))
+enum tfm_platform_err_t
+tfm_platform_set_pin_mode(uint64_t pin_mask, uint32_t pin_mode,
+                          uint32_t *result)
+{
+    psa_status_t ret;
+    psa_invec in_vec;
+    psa_outvec out_vec;
+    struct tfm_pin_service_args_t args;
+
+    if (result == NULL) {
+        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    }
+
+    args.type = TFM_PIN_SERVICE_TYPE_SET_PIN_MODE;
+    args.u.set_pin_mode.pin_mask = pin_mask;
+    args.u.set_pin_mode.pin_mode = pin_mode;
+
+    in_vec.base = (const void *)&args;
+    in_vec.len = sizeof(args);
+
+    out_vec.base = (void *)result;
+    out_vec.len = sizeof(*result);
+
+    ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_PIN_SERVICE, &in_vec, &out_vec);
+
+    if (ret != PSA_SUCCESS) {
+        return TFM_PLATFORM_ERR_SYSTEM_ERROR;
+    }
+
+    return TFM_PLATFORM_ERR_SUCCESS;
+}
+
diff --git a/platform/ext/target/musca_b1/services/src/tfm_platform_system.c b/platform/ext/target/musca_b1/services/src/tfm_platform_system.c
new file mode 100644
index 0000000..be11acd
--- /dev/null
+++ b/platform/ext/target/musca_b1/services/src/tfm_platform_system.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include "platform/include/tfm_platform_system.h"
+#include "platform_description.h"
+#include "target_cfg.h"
+#include "device_definition.h"
+#include "psa_client.h"
+#include "tfm_secure_api.h"
+#include "services/include/tfm_ioctl_api.h"
+
+/*!
+ * \brief Verify access rights for memory addresses sent in io vectors
+ *
+ * \param[in] in_vec     Pointer to in_vec array, which contains pointer
+ *                       to input arguments for the service
+ * \param[in] out_vec    Pointer out_vec array, which contains pointer to
+ *                       output data of the pin service
+ *
+ * \return Returns true if memory is accessible by the service
+ */
+static bool memory_addr_check(const psa_invec *in_vec,
+                              const psa_outvec *out_vec)
+{
+    if ((in_vec->base != NULL) &&
+        (tfm_core_memory_permission_check((void *)in_vec->base, in_vec->len,
+                                        TFM_MEMORY_ACCESS_RO) == TFM_SUCCESS) &&
+        (out_vec->base != NULL) &&
+        (tfm_core_memory_permission_check((void *)out_vec->base, out_vec->len,
+                                        TFM_MEMORY_ACCESS_RW) == TFM_SUCCESS)) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+void tfm_platform_hal_system_reset(void)
+{
+    __disable_irq();
+    mpc_revert_non_secure_to_secure_cfg();
+
+    NVIC->ICPR[0] = UINT32_MAX;         /* Clear all pending interrupts */
+    NVIC->ICPR[1] = UINT32_MAX;         /* Clear all pending interrupts */
+    NVIC->ICPR[2] = UINT32_MAX;         /* Clear all pending interrupts */
+    NVIC->ICPR[3] = UINT32_MAX;         /* Clear all pending interrupts */
+    NVIC->ICPR[4] = UINT32_MAX;         /* Clear all pending interrupts */
+    NVIC->ICPR[5] = UINT32_MAX;         /* Clear all pending interrupts */
+    NVIC->ICPR[6] = UINT32_MAX;         /* Clear all pending interrupts */
+    NVIC->ICPR[7] = UINT32_MAX;         /* Clear all pending interrupts */
+
+    NVIC_SystemReset();
+}
+
+static enum tfm_platform_err_t
+musca_b1_pin_service(const psa_invec  *in_vec,
+                     const psa_outvec *out_vec)
+{
+    struct tfm_pin_service_args_t *args;
+    uint32_t *result;
+    enum gpio_altfunc_t altfunc;
+    enum pinmode_select_t pin_mode;
+
+    if (memory_addr_check(in_vec, out_vec) == false) {
+        return TFM_PLATFORM_ERR_SYSTEM_ERROR;
+    }
+    if (in_vec->len != sizeof(struct tfm_pin_service_args_t) ||
+                                         out_vec->len != sizeof(uint32_t)) {
+        return TFM_PLATFORM_ERR_SYSTEM_ERROR;
+    }
+
+    args = (struct tfm_pin_service_args_t *)in_vec->base;
+    result = (uint32_t *)out_vec->base;
+    switch (args->type) {
+    case TFM_PIN_SERVICE_TYPE_SET_ALTFUNC:
+        altfunc = (enum gpio_altfunc_t)args->u.set_altfunc.alt_func;
+        *result = musca_b1_scc_set_alt_func(&MUSCA_B1_SCC_DEV_S, altfunc,
+                                            args->u.set_altfunc.pin_mask);
+        break;
+    case TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN:
+        altfunc = (enum gpio_altfunc_t)args->u.set_altfunc.alt_func;
+        *result = musca_b1_scc_set_default_in(&MUSCA_B1_SCC_DEV_S, altfunc,
+                                   args->u.set_default_in.pin_value,
+                                   args->u.set_default_in.default_in_value);
+        break;
+    case TFM_PIN_SERVICE_TYPE_SET_PIN_MODE:
+        pin_mode = (enum pinmode_select_t)args->u.set_pin_mode.pin_mode;
+        *result = musca_b1_scc_set_pinmode(&MUSCA_B1_SCC_DEV_S,
+                                           args->u.set_pin_mode.pin_mask,
+                                           pin_mode);
+        break;
+     default:
+        *result = SCC_INVALID_ARG;
+        break;
+    }
+
+    return TFM_PLATFORM_ERR_SUCCESS;
+}
+
+enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request,
+                                               psa_invec  *in_vec,
+                                               psa_outvec *out_vec)
+{
+    switch (request)
+    {
+        case TFM_PLATFORM_IOCTL_PIN_SERVICE:
+            return musca_b1_pin_service(in_vec, out_vec);
+        default:
+            return TFM_PLATFORM_ERR_NOT_SUPPORTED;
+    }
+}
+
diff --git a/platform/ext/target/musca_b1/tfm_platform_system.c b/platform/ext/target/musca_b1/tfm_platform_system.c
deleted file mode 100644
index 2fb9657..0000000
--- a/platform/ext/target/musca_b1/tfm_platform_system.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include <stdbool.h>
-#include "platform/include/tfm_platform_system.h"
-#include "platform_description.h"
-#include "target_cfg.h"
-#include "device_definition.h"
-#include "psa_client.h"
-#include "tfm_platform_defs.h"
-#include "tfm_secure_api.h"
-
-/*!
- * \brief Verify access rights for memory addresses sent in io vectors
- *
- * \param[in] in_vec     Pointer to in_vec array, which contains pointer
- *                       to input arguments for the service
- * \param[in] out_vec    Pointer out_vec array, which contains pointer to
- *                       output data of the pin service
- *
- * \return Returns true if memory is accessible by the service
- */
-static bool memory_addr_check(const psa_invec *in_vec,
-                              const psa_outvec *out_vec)
-{
-    if ((in_vec->base != NULL) &&
-        (tfm_core_memory_permission_check((void *)in_vec->base, in_vec->len,
-                                        TFM_MEMORY_ACCESS_RO) == TFM_SUCCESS) &&
-        (out_vec->base != NULL) &&
-        (tfm_core_memory_permission_check((void *)out_vec->base, out_vec->len,
-                                        TFM_MEMORY_ACCESS_RW) == TFM_SUCCESS)) {
-        return true;
-    } else {
-        return false;
-    }
-}
-
-void tfm_platform_hal_system_reset(void)
-{
-    __disable_irq();
-    mpc_revert_non_secure_to_secure_cfg();
-
-    NVIC->ICPR[0] = UINT32_MAX;         /* Clear all pending interrupts */
-    NVIC->ICPR[1] = UINT32_MAX;         /* Clear all pending interrupts */
-    NVIC->ICPR[2] = UINT32_MAX;         /* Clear all pending interrupts */
-    NVIC->ICPR[3] = UINT32_MAX;         /* Clear all pending interrupts */
-    NVIC->ICPR[4] = UINT32_MAX;         /* Clear all pending interrupts */
-    NVIC->ICPR[5] = UINT32_MAX;         /* Clear all pending interrupts */
-    NVIC->ICPR[6] = UINT32_MAX;         /* Clear all pending interrupts */
-    NVIC->ICPR[7] = UINT32_MAX;         /* Clear all pending interrupts */
-
-    NVIC_SystemReset();
-}
-
-enum tfm_plat_err_t
-tfm_platform_hal_pin_service(const psa_invec  *in_vec,  uint32_t num_invec,
-                             const psa_outvec *out_vec, uint32_t num_outvec)
-{
-    struct tfm_pin_service_args_t *args;
-    uint32_t *result;
-    enum gpio_altfunc_t altfunc;
-    enum pinmode_select_t pin_mode;
-
-    while (num_invec && num_outvec) {
-        if (memory_addr_check(in_vec, out_vec) == false) {
-            return TFM_PLAT_ERR_SYSTEM_ERR;
-        }
-        if (in_vec->len != sizeof(struct tfm_pin_service_args_t) ||
-                                             out_vec->len != sizeof(uint32_t)) {
-            return TFM_PLAT_ERR_SYSTEM_ERR;
-        }
-
-        args = (struct tfm_pin_service_args_t *)in_vec->base;
-        result = (uint32_t *)out_vec->base;
-        switch (args->type) {
-        case TFM_PIN_SERVICE_TYPE_SET_ALTFUNC:
-            altfunc = (enum gpio_altfunc_t)args->u.set_altfunc.alt_func;
-            *result = musca_b1_scc_set_alt_func(&MUSCA_B1_SCC_DEV_S, altfunc,
-                                                args->u.set_altfunc.pin_mask);
-            break;
-        case TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN:
-            altfunc = (enum gpio_altfunc_t)args->u.set_altfunc.alt_func;
-            *result = musca_b1_scc_set_default_in(&MUSCA_B1_SCC_DEV_S, altfunc,
-                                       args->u.set_default_in.pin_value,
-                                       args->u.set_default_in.default_in_value);
-            break;
-        case TFM_PIN_SERVICE_TYPE_SET_PIN_MODE:
-            pin_mode = (enum pinmode_select_t)args->u.set_pin_mode.pin_mode;
-            *result = musca_b1_scc_set_pinmode(&MUSCA_B1_SCC_DEV_S,
-                                               args->u.set_pin_mode.pin_mask,
-                                               pin_mode);
-            break;
-         default:
-            *result = SCC_INVALID_ARG;
-            break;
-        }
-
-        num_invec--;
-        num_outvec--;
-        in_vec++;
-        out_vec++;
-    }
-
-    return TFM_PLAT_ERR_SUCCESS;
-}
-
diff --git a/platform/include/tfm_platform_system.h b/platform/include/tfm_platform_system.h
index 411be49..8ad22b1 100644
--- a/platform/include/tfm_platform_system.h
+++ b/platform/include/tfm_platform_system.h
@@ -12,9 +12,9 @@
  *       target.
  */
 
-#include "tfm_plat_defs.h"
 #include "psa_client.h"
 #include "tfm_plat_defs.h"
+#include "tfm_platform_api.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -29,21 +29,19 @@
 void tfm_platform_hal_system_reset(void);
 
 /*!
- * \brief Performs pin services of the platform
+ * \brief Performs a platform-specific service
  *
- * \param[in]     in_vec     Pointer to in_vec array, which contains input
- *                           arguments for the pin service
- * \param[in]     num_invec  Number of elements in in_vec array
- * \param[in,out] out_vec    Pointer out_vec array, which contains output data
- *                           of the pin service
- * \param[in]     num_outvec Number of elements in out_vec array
+ * \param[in]  request      Request identifier (valid values vary
+ *                          based on the platform)
+ * \param[in]  in_vec       Input buffer to the requested service (or NULL)
+ * \param[out] out_vec      Output buffer to the requested service (or NULL)
  *
- * \return Returns values as specified by the \ref tfm_plat_err_t
+ * \return Returns values as specified by the \ref tfm_platform_err_t
  */
 TFM_LINK_SET_OBJECT_IN_PARTITION_SECTION("TFM_SP_PLATFORM")
-enum tfm_plat_err_t
-tfm_platform_hal_pin_service(const psa_invec  *in_vec,  uint32_t num_invec,
-                             const psa_outvec *out_vec, uint32_t num_outvec);
+enum tfm_platform_err_t tfm_platform_hal_ioctl(tfm_platform_ioctl_req_t request,
+                                               psa_invec *in_vec,
+                                               psa_outvec *out_vec);
 
 #ifdef __cplusplus
 }
diff --git a/platform/readme.rst b/platform/readme.rst
index 20e5fbc..0dac5e9 100644
--- a/platform/readme.rst
+++ b/platform/readme.rst
@@ -7,9 +7,9 @@
     This folder and subfolders, especially the target folder, are likely to be
     refactored and updated to improve the overall structure of dependencies.
 
-**************************
-Interfacing with TF-M core
-**************************
+*********************
+Interfacing with TF-M
+*********************
 
 platformext/target/tfm_peripherals_def.h
 ========================================
@@ -35,13 +35,19 @@
 platform/include/tfm_spm_hal.h
 ==============================
 This file contains the declarations of functions that a platform implementation
-has to provide for TF-M. For details see the comments in the file.
+has to provide for TF-M's SPM. For details see the comments in the file.
 
 secure_fw/core/tfm_platform_core_api.h
 ======================================
 This file contains declarations of functions that can be or have to be called
 from platform implementations. For details see the comments in the file.
 
+platform/include/tfm_platform_system.h
+======================================
+This file contains the declarations of functions that a platform implementation
+has to provide for TF-M's Platform Service. For details see
+``docs/user_guides/services/tfm_platform_integration_guide.rst``
+
 ***********
 Sub-folders
 ***********
diff --git a/secure_fw/ns_callable/CMakeLists.inc b/secure_fw/ns_callable/CMakeLists.inc
index 3abee33..b8fcf5f 100644
--- a/secure_fw/ns_callable/CMakeLists.inc
+++ b/secure_fw/ns_callable/CMakeLists.inc
@@ -29,10 +29,6 @@
 	set (SS_NS_CALLABLE_C_SRC "${CMAKE_CURRENT_LIST_DIR}/tfm_veneers.c")
 endif()
 
-if (TFM_PARTITION_PLATFORM)
-    list(APPEND SS_NS_CALLABLE_C_SRC "${CMAKE_CURRENT_LIST_DIR}/tfm_platform_veneers.c")
-endif()
-
 if (TFM_PARTITION_AUDIT_LOG)
 	list(APPEND SS_NS_CALLABLE_C_SRC "${CMAKE_CURRENT_LIST_DIR}/tfm_audit_veneers.c")
 endif()
diff --git a/secure_fw/ns_callable/tfm_platform_veneers.c b/secure_fw/ns_callable/tfm_platform_veneers.c
deleted file mode 100644
index c2515fe..0000000
--- a/secure_fw/ns_callable/tfm_platform_veneers.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include "tfm_platform_veneers.h"
-#include "secure_fw/services/platform/platform_sp.h"
-#include "tfm_secure_api.h"
-#include "tfm_api.h"
-#include "spm_partition_defs.h"
-
-__tfm_secure_gateway_attributes__
-enum tfm_platform_err_t tfm_platform_veneer_system_reset(void)
-{
-    TFM_CORE_SFN_REQUEST(TFM_SP_PLATFORM_ID,
-                         platform_sp_system_reset,
-                         0, 0, 0, 0);
-}
diff --git a/secure_fw/ns_callable/tfm_veneers.c b/secure_fw/ns_callable/tfm_veneers.c
index aff38e8..3effa95 100644
--- a/secure_fw/ns_callable/tfm_veneers.c
+++ b/secure_fw/ns_callable/tfm_veneers.c
@@ -74,7 +74,7 @@
 #ifdef TFM_PARTITION_PLATFORM
 /******** TFM_SP_PLATFORM ********/
 psa_status_t platform_sp_system_reset(psa_invec *, size_t, psa_outvec *, size_t);
-psa_status_t platform_sp_pin_service(psa_invec *, size_t, psa_outvec *, size_t);
+psa_status_t platform_sp_ioctl(psa_invec *, size_t, psa_outvec *, size_t);
 #endif /* TFM_PARTITION_PLATFORM */
 
 /******** TFM_SP_INITIAL_ATTESTATION ********/
@@ -186,7 +186,7 @@
 #ifdef TFM_PARTITION_PLATFORM
 /******** TFM_SP_PLATFORM ********/
 TFM_VENEER_FUNCTION(TFM_SP_PLATFORM, platform_sp_system_reset)
-TFM_VENEER_FUNCTION(TFM_SP_PLATFORM, platform_sp_pin_service)
+TFM_VENEER_FUNCTION(TFM_SP_PLATFORM, platform_sp_ioctl)
 #endif /* TFM_PARTITION_PLATFORM */
 
 /******** TFM_SP_INITIAL_ATTESTATION ********/
diff --git a/secure_fw/services/platform/manifest.yaml b/secure_fw/services/platform/manifest.yaml
index 283802e..9a5c7b1 100644
--- a/secure_fw/services/platform/manifest.yaml
+++ b/secure_fw/services/platform/manifest.yaml
@@ -23,9 +23,9 @@
       "minor_policy": "strict"
     },
     {
-      "sfid": "TFM_SP_PLATFORM_PIN_SERVICE_SFID",
-      "signal": "TFM_SP_PLATFORM_PIN_SERVICE",
-      "tfm_symbol": "platform_sp_pin_service",
+      "sfid": "TFM_SP_PLATFORM_IOCTL_SFID",
+      "signal": "TFM_SP_PLATFORM_IOCTL",
+      "tfm_symbol": "platform_sp_ioctl",
       "non_secure_clients": true,
       "minor_version": 1,
       "minor_policy": "strict"
diff --git a/secure_fw/services/platform/platform_sp.c b/secure_fw/services/platform/platform_sp.c
index 59fa186..13aed6a 100644
--- a/secure_fw/services/platform/platform_sp.c
+++ b/secure_fw/services/platform/platform_sp.c
@@ -28,11 +28,6 @@
 
     /* FIXME: The system reset functionality is only supported in isolation
      *        level 1.
-     *        Currently, the mechanism by which PRoT services should run in
-     *        privileged mode in level 3, it is not in place due to an ongoing
-     *        work in TF-M Core. So, the NVIC_SystemReset call performed by the
-     *        service, it is expected to generate a memory fault when it tries
-     *        to access the SCB->AIRCR register in level 3 isolation.
      */
 
     tfm_platform_hal_system_reset();
@@ -41,13 +36,23 @@
 }
 
 enum tfm_platform_err_t
-platform_sp_pin_service(const psa_invec  *in_vec,  uint32_t num_invec,
-                        const psa_outvec *out_vec, uint32_t num_outvec)
+platform_sp_ioctl(psa_invec  *in_vec,  uint32_t num_invec,
+                  psa_outvec *out_vec, uint32_t num_outvec)
 {
-    enum tfm_plat_err_t ret = tfm_platform_hal_pin_service(in_vec, num_invec,
-                                                           out_vec, num_outvec);
+    void *input, *output;
+    tfm_platform_ioctl_req_t request;
 
-    return ((ret == TFM_PLAT_ERR_SUCCESS) ? TFM_PLATFORM_ERR_SUCCESS :
-                                                 TFM_PLATFORM_ERR_SYSTEM_ERROR);
+    if ((num_invec < 1) || (num_invec > 2) ||
+        (num_outvec > 1) ||
+        (in_vec[0].base == NULL) ||
+        (in_vec[0].len != sizeof(tfm_platform_ioctl_req_t))) {
+        return TFM_PLATFORM_ERR_SYSTEM_ERROR;
+    }
+
+    input = (num_invec == 1) ? NULL : &in_vec[1];
+    output = out_vec;
+    request = *((tfm_platform_ioctl_req_t *)in_vec[0].base);
+
+    return tfm_platform_hal_ioctl(request, input, output);
 }
 
diff --git a/secure_fw/services/platform/tfm_platform_secure_api.c b/secure_fw/services/platform/tfm_platform_secure_api.c
index dccd3ce..9103ab4 100644
--- a/secure_fw/services/platform/tfm_platform_secure_api.c
+++ b/secure_fw/services/platform/tfm_platform_secure_api.c
@@ -6,113 +6,42 @@
  */
 
 #include "tfm_platform_api.h"
-#include "tfm_platform_veneers.h"
-#include "tfm_platform_defs.h"
 #include "tfm_veneers.h"
 
 __attribute__((section("SFN")))
 enum tfm_platform_err_t tfm_platform_system_reset(void)
 {
-    return tfm_platform_veneer_system_reset();
+    return (enum tfm_platform_err_t) tfm_platform_sp_system_reset_veneer(
+                                                              NULL, 0, NULL, 0);
 }
 
 __attribute__((section("SFN")))
 enum tfm_platform_err_t
-tfm_platform_set_pin_alt_func(uint32_t alt_func, uint64_t pin_mask,
-                              uint32_t *result)
+tfm_platform_ioctl(tfm_platform_ioctl_req_t request,
+                   psa_invec *input, psa_outvec *output)
 {
-    psa_status_t ret;
-    psa_invec in_vec;
-    psa_outvec out_vec;
-    struct tfm_pin_service_args_t args;
+    tfm_platform_ioctl_req_t req = request;
+    struct psa_invec in_vec[2];
+    size_t inlen, outlen;
 
-    if (result == NULL) {
-        return TFM_PLATFORM_ERR_INVALID_PARAM;
+    in_vec[0].base = &req;
+    in_vec[0].len = sizeof(req);
+    if (input != NULL) {
+        in_vec[1].base = input->base;
+        in_vec[1].len = input->len;
+        inlen = 2;
+    } else {
+        inlen = 1;
     }
 
-    args.type = TFM_PIN_SERVICE_TYPE_SET_ALTFUNC;
-    args.u.set_altfunc.alt_func = alt_func;
-    args.u.set_altfunc.pin_mask = pin_mask;
-
-    in_vec.base = (const void *)&args;
-    in_vec.len = sizeof(args);
-
-    out_vec.base = (void *)result;
-    out_vec.len = sizeof(*result);
-
-    ret = tfm_platform_sp_pin_service_veneer(&in_vec,  1, &out_vec, 1);
-
-    if (ret != PSA_SUCCESS) {
-        return TFM_PLATFORM_ERR_SYSTEM_ERROR;
+    if (output != NULL) {
+        outlen = 1;
+    } else {
+        outlen = 0;
     }
 
-    return TFM_PLATFORM_ERR_SUCCESS;
-}
+    return (enum tfm_platform_err_t) tfm_platform_sp_ioctl_veneer(
+                                                in_vec, inlen, output, outlen);
 
-__attribute__((section("SFN")))
-enum tfm_platform_err_t
-tfm_platform_set_pin_default_in(uint32_t alt_func, uint32_t pin_value,
-                              bool default_in_value, uint32_t *result)
-{
-    psa_status_t ret;
-    psa_invec in_vec;
-    psa_outvec out_vec;
-    struct tfm_pin_service_args_t args;
-
-    if (result == NULL) {
-        return TFM_PLATFORM_ERR_INVALID_PARAM;
-    }
-
-    args.type = TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN;
-    args.u.set_default_in.alt_func = alt_func;
-    args.u.set_default_in.pin_value = pin_value;
-    args.u.set_default_in.default_in_value = default_in_value;
-
-    in_vec.base = (const void *)&args;
-    in_vec.len = sizeof(args);
-
-    out_vec.base = (void *)result;
-    out_vec.len = sizeof(*result);
-
-    ret = tfm_platform_sp_pin_service_veneer(&in_vec,  1, &out_vec, 1);
-
-    if (ret != PSA_SUCCESS) {
-        return TFM_PLATFORM_ERR_SYSTEM_ERROR;
-    }
-
-    return TFM_PLATFORM_ERR_SUCCESS;
-}
-
-__attribute__((section("SFN")))
-enum tfm_platform_err_t
-tfm_platform_set_pin_mode(uint64_t pin_mask, uint32_t pin_mode,
-                          uint32_t *result)
-{
-    psa_status_t ret;
-    psa_invec in_vec;
-    psa_outvec out_vec;
-    struct tfm_pin_service_args_t args;
-
-    if (result == NULL) {
-        return TFM_PLATFORM_ERR_INVALID_PARAM;
-    }
-
-    args.type = TFM_PIN_SERVICE_TYPE_SET_PIN_MODE;
-    args.u.set_pin_mode.pin_mask = pin_mask;
-    args.u.set_pin_mode.pin_mode = pin_mode;
-
-    in_vec.base = (const void *)&args;
-    in_vec.len = sizeof(args);
-
-    out_vec.base = (void *)result;
-    out_vec.len = sizeof(*result);
-
-    ret = tfm_platform_sp_pin_service_veneer(&in_vec,  1, &out_vec, 1);
-
-    if (ret != PSA_SUCCESS) {
-        return TFM_PLATFORM_ERR_SYSTEM_ERROR;
-    }
-
-    return TFM_PLATFORM_ERR_SUCCESS;
 }