Merge 'integration' into 'topics/corstone1000'

Refresh the topic branch from integration. Refactor se-proxy
deployment to align with deployment structure changes:
  - introduce a CS1K specific infrastructure to se-proxy
    deployment
  - restore HW independence of "stub" infra of se-proxy
  - clean up components added from se-proxy.cmake and
    se_proxy_sp.cmake (remove duplicates and add what's missing)

Signed-off-by: Gyorgy Szing <Gyorgy.Szing@arm.com>
Change-Id: Ib7f2c25c5057e95771cc16c3774759933e3f2c9c
diff --git a/components/messaging/openamp/sp/component.cmake b/components/messaging/openamp/sp/component.cmake
new file mode 100644
index 0000000..cee76a0
--- /dev/null
+++ b/components/messaging/openamp/sp/component.cmake
@@ -0,0 +1,24 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+	"${CMAKE_CURRENT_LIST_DIR}/openamp_messenger_api.h"
+	)
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/openamp_messenger.c"
+	"${CMAKE_CURRENT_LIST_DIR}/openamp_virtio.c"
+	"${CMAKE_CURRENT_LIST_DIR}/openamp_mhu.c"
+	)
+
+target_include_directories(${TGT}
+	 PUBLIC
+		"${CMAKE_CURRENT_LIST_DIR}"
+	)
diff --git a/components/messaging/openamp/sp/openamp_messenger.c b/components/messaging/openamp/sp/openamp_messenger.c
new file mode 100644
index 0000000..2b77ea4
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_messenger.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <trace.h>
+#include "openamp_messenger.h"
+#include "openamp_messenger_api.h"
+#include "openamp_mhu.h"
+#include "openamp_virtio.h"
+#include <protocols/rpc/common/packed-c/status.h>
+
+#define OPENAMP_TRANSACTION_IDLE	0x0
+#define OPENAMP_TRANSACTION_INPROGRESS	0x1
+#define OPENAMP_TRANSACTION_INVOKED	0x2
+
+int openamp_messenger_call_begin(struct openamp_messenger *openamp,
+				 uint8_t **req_buf, size_t req_len)
+{
+	const struct openamp_platform_ops *ops = openamp->platform_ops;
+	int ret;
+
+	if (!openamp)
+		return -EINVAL;
+
+	ops = openamp->platform_ops;
+	if (!req_buf) {
+		EMSG("openamp: call_begin: not req_buf");
+		return -EINVAL;
+	}
+
+	if (req_len > UINT32_MAX || req_len == 0) {
+		EMSG("openamp: call_begin: resp_len invalid: %lu", req_len);
+		return -EINVAL;
+	}
+
+	if (openamp->status != OPENAMP_TRANSACTION_IDLE) {
+		EMSG("openamp: call_begin: transaction not idle");
+		return -EINVAL;
+	}
+
+	ret = ops->platform_call_begin(openamp, req_buf, req_len);
+	if (ret < 0) {
+		EMSG("openamp: call_begin: platform begin failed: %d", ret);
+		return -EINVAL;
+	}
+
+	openamp->status = OPENAMP_TRANSACTION_INPROGRESS;
+
+	return 0;
+}
+
+int openamp_messenger_call_invoke(struct openamp_messenger *openamp,
+				  uint8_t **resp_buf, size_t *resp_len)
+{
+	const struct openamp_platform_ops *ops;
+	int ret;
+
+	if (!openamp || !resp_buf || !resp_len) {
+		EMSG("openamp: call_invoke: invalid arguments");
+		return -EINVAL;
+	}
+
+	if (openamp->status != OPENAMP_TRANSACTION_INPROGRESS) {
+		EMSG("openamp: call_invoke: transaction needed to be started");
+		return -ENOTCONN;
+	}
+
+	ops = openamp->platform_ops;
+
+	ret = ops->platform_call_invoke(openamp, resp_buf, resp_len);
+	if (ret < 0)
+		return ret;
+
+	openamp->status = OPENAMP_TRANSACTION_INVOKED;
+
+	return 0;
+}
+
+void openamp_messenger_call_end(struct openamp_messenger *openamp)
+{
+	const struct openamp_platform_ops *ops;
+
+	if (!openamp)
+		return;
+
+	if (openamp->status == OPENAMP_TRANSACTION_IDLE) {
+		EMSG("openamp: call_end: transaction idle");
+		return;
+	}
+
+	ops = openamp->platform_ops;
+
+	ops->platform_call_end(openamp);
+
+	openamp->status = OPENAMP_TRANSACTION_IDLE;
+}
+
+void *openamp_messenger_phys_to_virt(struct openamp_messenger *openamp,
+				     void *pa)
+{
+	const struct openamp_platform_ops *ops = openamp->platform_ops;
+
+	return ops->platform_phys_to_virt(openamp, pa);
+}
+
+void *openamp_messenger_virt_to_phys(struct openamp_messenger *openamp,
+				     void *va)
+{
+	const struct openamp_platform_ops *ops = openamp->platform_ops;
+
+	return ops->platform_virt_to_phys(openamp, va);
+}
+
+static const struct openamp_platform_ops openamp_virtio_ops = {
+	.transport_init = openamp_mhu_init,
+	.transport_deinit = openamp_mhu_deinit,
+	.transport_notify = openamp_mhu_notify_peer,
+	.transport_receive = openamp_mhu_receive,
+	.platform_init = openamp_virtio_init,
+	.platform_call_begin = openamp_virtio_call_begin,
+	.platform_call_invoke = openamp_virtio_call_invoke,
+	.platform_call_end = openamp_virtio_call_end,
+	.platform_virt_to_phys = openamp_virtio_virt_to_phys,
+	.platform_phys_to_virt = openamp_virtio_phys_to_virt,
+};
+
+int openamp_messenger_init(struct openamp_messenger *openamp)
+{
+	const struct openamp_platform_ops *ops;
+	int ret;
+
+	if (openamp->ref_count)
+		return 0;
+
+	openamp->platform_ops = &openamp_virtio_ops;
+
+	ops = openamp->platform_ops;
+
+	ret = ops->transport_init(openamp);
+	if (ret < 0)
+		return ret;
+
+	ret = ops->platform_init(openamp);
+	if (ret < 0)
+		goto denit_transport;
+
+	openamp->ref_count++;
+
+	return 0;
+
+denit_transport:
+	ops->transport_deinit(openamp);
+
+	return ret;
+}
+
+void openamp_messenger_deinit(struct openamp_messenger *openamp)
+{
+	if (--openamp->ref_count)
+		return;
+}
diff --git a/components/messaging/openamp/sp/openamp_messenger.h b/components/messaging/openamp/sp/openamp_messenger.h
new file mode 100644
index 0000000..e863c4f
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_messenger.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef OPENAMP_MESSENGER_H
+#define OPENAMP_MESSENGER_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct openamp_messenger;
+
+struct openamp_platform_ops {
+	int (*transport_init)(struct openamp_messenger *openamp);
+	int (*transport_deinit)(struct openamp_messenger *openamp);
+	int (*transport_notify)(struct openamp_messenger *openamp);
+	int (*transport_receive)(struct openamp_messenger *openamp);
+	int (*platform_init)(struct openamp_messenger *openamp);
+	int (*platform_deinit)(struct openamp_messenger *openamp);
+	int (*platform_call_begin)(struct openamp_messenger *openamp,
+				   uint8_t **req_buf, size_t req_len);
+	int (*platform_call_invoke)(struct openamp_messenger *openamp,
+				    uint8_t **resp_buf, size_t *resp_len);
+	int (*platform_call_end)(struct openamp_messenger *openamp);
+	void *(*platform_virt_to_phys)(struct openamp_messenger *openamp,
+				       void *va);
+	void *(*platform_phys_to_virt)(struct openamp_messenger *openamp,
+				       void *pa);
+};
+
+#endif
diff --git a/components/messaging/openamp/sp/openamp_messenger_api.h b/components/messaging/openamp/sp/openamp_messenger_api.h
new file mode 100644
index 0000000..61ab37a
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_messenger_api.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef OPENAMP_MESSENGER_API_H
+#define OPENAMP_MESSENGER_API_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "openamp_messenger.h"
+
+struct openamp_messenger {
+	const struct openamp_platform_ops *platform_ops;
+	uint32_t ref_count;
+	uint8_t status;
+
+	void *transport;
+	void *platform;
+};
+
+int openamp_messenger_init(struct openamp_messenger *openamp);
+void openamp_messenger_deinit(struct openamp_messenger *openamp);
+void openamp_messenger_call_end(struct openamp_messenger *openamp);
+int openamp_messenger_call_invoke(struct openamp_messenger *openamp,
+				  uint8_t **resp_buf, size_t *resp_len);
+int openamp_messenger_call_begin(struct openamp_messenger *openamp,
+				 uint8_t **req_buf, size_t req_len);
+
+void *openamp_messenger_phys_to_virt(struct openamp_messenger *openamp,
+				     void *pa);
+void *openamp_messenger_virt_to_phys(struct openamp_messenger *openamp,
+				     void *va);
+#endif
diff --git a/components/messaging/openamp/sp/openamp_mhu.c b/components/messaging/openamp/sp/openamp_mhu.c
new file mode 100644
index 0000000..bafba3e
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_mhu.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <config/interface/config_store.h>
+#include <config/interface/config_blob.h>
+#include <platform/interface/device_region.h>
+#include <platform/drivers/arm/mhu_driver/mhu_v2.h>
+#include <trace.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
+
+#include "openamp_messenger_api.h"
+
+#define MHU_V_2_NOTIFY_CHANNEL	0
+#define MHU_V_2_NOTIFY_VALUE	0xff
+
+struct openamp_mhu {
+	struct device_region rx_region;
+	struct device_region tx_region;
+	struct mhu_v2_x_dev_t rx_dev;
+	struct mhu_v2_x_dev_t tx_dev;
+};
+
+static int openamp_mhu_device_get(const char *dev,
+				  struct device_region *dev_region)
+{
+	bool found;
+
+	found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
+				   dev_region, sizeof(*dev_region));
+	if (!found)
+		return -EINVAL;
+
+	if (!dev_region->base_addr)
+		return -EINVAL;
+
+	IMSG("mhu: device region found: %s addr: 0x%p size: %lu", dev,
+	     (void *)dev_region->base_addr, dev_region->io_region_size);
+
+	return 0;
+}
+
+int openamp_mhu_receive(struct openamp_messenger *openamp)
+{
+	struct mhu_v2_x_dev_t *rx_dev;
+	enum mhu_v2_x_error_t ret;
+	struct openamp_mhu *mhu;
+	uint32_t channel = 0;
+	uint32_t irq_status;
+
+	if (!openamp->transport) {
+		EMSG("openamp: mhu: receive transport not initialized");
+		return -EINVAL;
+	}
+
+	mhu = openamp->transport;
+	rx_dev = &mhu->rx_dev;
+
+	irq_status = 0;
+
+	do {
+		irq_status = mhu_v2_x_get_interrupt_status(rx_dev);
+	} while(!irq_status);
+
+	ret = mhu_v2_1_get_ch_interrupt_num(rx_dev, &channel);
+
+	ret = mhu_v2_x_channel_clear(rx_dev, channel);
+	if (ret != MHU_V_2_X_ERR_NONE) {
+		EMSG("openamp: mhu: failed to clear channel: %d", channel);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+int openamp_mhu_notify_peer(struct openamp_messenger *openamp)
+{
+	struct mhu_v2_x_dev_t *tx_dev;
+	enum mhu_v2_x_error_t ret;
+	struct openamp_mhu *mhu;
+	uint32_t access_ready;
+
+	if (!openamp->transport) {
+		EMSG("openamp: mhu: notify transport not initialized");
+		return -EINVAL;
+	}
+
+	mhu = openamp->transport;
+	tx_dev = &mhu->tx_dev;
+
+	ret = mhu_v2_x_set_access_request(tx_dev);
+	if (ret != MHU_V_2_X_ERR_NONE) {
+		EMSG("openamp: mhu: set access request failed");
+		return -EPROTO;
+	}
+
+	do {
+		ret = mhu_v2_x_get_access_ready(tx_dev, &access_ready);
+		if (ret != MHU_V_2_X_ERR_NONE) {
+			EMSG("openamp: mhu: failed to get access_ready");
+			return -EPROTO;
+		}
+	} while (!access_ready);
+
+	ret = mhu_v2_x_channel_send(tx_dev, MHU_V_2_NOTIFY_CHANNEL,
+				    MHU_V_2_NOTIFY_VALUE);
+	if (ret != MHU_V_2_X_ERR_NONE) {
+		EMSG("openamp: mhu: failed send over channel");
+		return -EPROTO;
+	}
+
+	ret = mhu_v2_x_reset_access_request(tx_dev);
+	if (ret != MHU_V_2_X_ERR_NONE) {
+		EMSG("openamp: mhu: failed reset access request");
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+int openamp_mhu_init(struct openamp_messenger *openamp)
+{
+	struct mhu_v2_x_dev_t *rx_dev;
+	struct mhu_v2_x_dev_t *tx_dev;
+	struct openamp_mhu *mhu;
+	int ret;
+
+	/* if we already have initialized skip this */
+	if (openamp->transport)
+		return 0;
+
+	mhu = malloc(sizeof(*mhu));
+	if (!mhu)
+		return -1;
+
+	ret = openamp_mhu_device_get("mhu-sender", &mhu->tx_region);
+	if (ret < 0)
+		goto free_mhu;
+
+	ret = openamp_mhu_device_get("mhu-receiver", &mhu->rx_region);
+	if (ret < 0)
+		goto free_mhu;
+
+	rx_dev = &mhu->rx_dev;
+	tx_dev = &mhu->tx_dev;
+
+	rx_dev->base =  mhu->rx_region.base_addr;
+	rx_dev->frame = MHU_V2_X_RECEIVER_FRAME;
+
+	tx_dev->base =  mhu->tx_region.base_addr;
+	tx_dev->frame = MHU_V2_X_SENDER_FRAME;
+
+	ret = mhu_v2_x_driver_init(rx_dev, MHU_REV_READ_FROM_HW);
+	if (ret < 0)
+		goto free_mhu;
+
+	ret = mhu_v2_x_driver_init(tx_dev, MHU_REV_READ_FROM_HW);
+	if (ret < 0)
+		goto free_mhu;
+
+	openamp->transport = (void *)mhu;
+
+	return 0;
+
+free_mhu:
+	free(mhu);
+
+	return ret;
+}
+
+int openamp_mhu_deinit(struct openamp_messenger *openamp)
+{
+	struct openamp_mhu *mhu;
+
+	if (!openamp->transport)
+		return 0;
+
+	mhu = openamp->transport;
+	free(mhu);
+
+	openamp->transport = NULL;
+
+	return 0;
+}
diff --git a/components/messaging/openamp/sp/openamp_mhu.h b/components/messaging/openamp/sp/openamp_mhu.h
new file mode 100644
index 0000000..4ba427a
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_mhu.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef OPENAMP_MHU_H
+#define OPENAMP_MHU_H
+
+#include <stddef.h>
+#include "openamp_messenger_api.h"
+
+int openamp_mhu_init(struct openamp_messenger *openamp);
+int openamp_mhu_deinit(struct openamp_messenger *openamp);
+
+int openamp_mhu_notify_peer(struct openamp_messenger *openamp);
+int openamp_mhu_receive(struct openamp_messenger *openamp);
+
+#endif
diff --git a/components/messaging/openamp/sp/openamp_virtio.c b/components/messaging/openamp/sp/openamp_virtio.c
new file mode 100644
index 0000000..71d1ceb
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_virtio.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <metal/device.h>
+#include <metal/spinlock.h>
+#include <openamp/open_amp.h>
+#include <platform/interface/device_region.h>
+#include <config/interface/config_store.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <trace.h>
+#include "openamp_messenger_api.h"
+
+#define OPENAMP_SHEM_DEVICE_NAME "openamp-virtio"
+#define OPENAMP_RPMSG_ENDPOINT_NAME OPENAMP_SHEM_DEVICE_NAME
+#define OPENAMP_RPMSG_ENDPOINT_ADDR 1024
+
+#define OPENAMP_SHEM_PHYS 0x88000000
+#define OPENAMP_SHEM_PHYS_PAGES 1
+#define OPENAMP_SHEM_SE_PHYS 0xa8000000
+
+#define OPENAMP_SHEM_VDEV_SIZE (4 * 1024)
+#define OPENAMP_SHEM_VRING_SIZE (4 * 1024)
+
+#define OPENAMP_BUFFER_NO_WAIT  0
+#define OPENAMP_BUFFER_WAIT     1
+
+#define VIRTQUEUE_NR            2
+#define VQ_TX                   0
+#define VQ_RX                   1
+
+#define VRING_DESCRIPTORS       16
+#define VRING_ALIGN             4
+
+#define container_of(ptr, type, member) \
+	((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
+
+struct openamp_virtio_shm {
+	uintptr_t base_addr;
+	size_t size;
+	uintptr_t vdev_status;
+	size_t vdev_status_size;
+	uintptr_t payload_addr;
+	size_t payload_size;
+	uintptr_t vring_tx;
+	size_t vring_tx_size;
+	uintptr_t vring_rx;
+	size_t vring_rx_size;
+
+	metal_phys_addr_t shm_physmap[OPENAMP_SHEM_PHYS_PAGES];
+};
+
+struct openamp_virtio_metal {
+	struct metal_spinlock lock;
+	struct metal_device shm_dev;
+	struct metal_device *io_dev;
+
+	struct metal_io_region *io;
+	struct openamp_virtio_shm shm;
+};
+
+struct openamp_virtio_device {
+	struct virtio_device virtio_dev;
+	struct virtqueue *vq[VIRTQUEUE_NR];
+	struct virtio_vring_info rvrings[VIRTQUEUE_NR];
+};
+
+struct openamp_virtio_rpmsg {
+	struct rpmsg_virtio_device rpmsg_vdev;
+	struct rpmsg_endpoint ep;
+	uint8_t *req_buf;
+	uint32_t req_len;
+	uint8_t *resp_buf;
+	size_t resp_len;
+};
+
+struct openamp_virtio {
+	struct openamp_messenger *openamp;
+	struct openamp_virtio_rpmsg rpmsg;
+	struct openamp_virtio_device vdev;
+	struct openamp_virtio_metal metal;
+};
+
+static struct openamp_virtio *openamp_virtio_from_dev(struct virtio_device *vdev)
+{
+	struct openamp_virtio_device *openamp_vdev;
+
+	openamp_vdev = container_of(vdev, struct openamp_virtio_device,
+			    virtio_dev);
+
+	return container_of(openamp_vdev, struct openamp_virtio, vdev);
+}
+
+static struct openamp_virtio_rpmsg *openamp_virtio_rpmsg_from_dev(struct rpmsg_device *rdev)
+{
+	struct rpmsg_virtio_device *rvdev;
+
+	rvdev = container_of(rdev, struct rpmsg_virtio_device, rdev);
+
+	return container_of(rvdev, struct openamp_virtio_rpmsg, rpmsg_vdev);
+
+}
+
+static void openamp_virtio_metal_device_setup(struct metal_device *shm_dev,
+					      struct openamp_virtio_shm *shm)
+{
+	struct metal_io_region *shm_region;
+
+	shm_region = &shm_dev->regions[0];
+
+	shm_dev->name = OPENAMP_SHEM_DEVICE_NAME;
+	shm_dev->num_regions = 1;
+
+	shm_region->virt = (void *)shm->payload_addr;
+	shm_region->size = shm->payload_size;
+
+	shm_region->physmap = (metal_phys_addr_t *)&shm->shm_physmap;
+	shm_region->page_shift = (metal_phys_addr_t)(-1);
+	shm_region->page_mask = (metal_phys_addr_t)(-1);
+}
+
+static int openamp_virtio_metal_init(struct openamp_virtio_metal *metal)
+{
+	struct metal_init_params params = METAL_INIT_DEFAULTS;
+	struct metal_device *shm_dev = &metal->shm_dev;
+	int ret;
+
+	openamp_virtio_metal_device_setup(shm_dev, &metal->shm);
+
+	metal_spinlock_init(&metal->lock);
+
+	ret = metal_init(&params);
+	if (ret < 0)
+		return ret;
+
+	ret = metal_register_generic_device(shm_dev);
+	if (ret < 0)
+		goto metal_finish;
+
+	ret = metal_device_open("generic", OPENAMP_SHEM_DEVICE_NAME,
+				&metal->io_dev);
+	if (ret < 0)
+		goto metal_finish;
+
+	metal->io = metal_device_io_region(metal->io_dev, 0);
+	if (!metal->io) {
+		EMSG("openamp: virtio: failed to init metal io");
+		ret = -EPROTO;
+		goto metal_finish;
+	}
+
+	return 0;
+
+metal_finish:
+	metal_finish();
+	return ret;
+}
+
+static unsigned char openamp_virtio_status_get(struct virtio_device *vdev)
+{
+	struct openamp_virtio *virtio = openamp_virtio_from_dev(vdev);
+	struct openamp_virtio_shm *shm = &virtio->metal.shm;
+
+	uint32_t status = *(volatile uint32_t *)shm->vdev_status;
+
+	return status;
+}
+
+static void openamp_virtio_status_set(struct virtio_device *vdev,
+				      unsigned char status)
+{
+	struct openamp_virtio *virtio = openamp_virtio_from_dev(vdev);
+	struct openamp_virtio_shm *shm = &virtio->metal.shm;
+
+	*(volatile uint32_t *)shm->vdev_status = status;
+}
+
+static uint32_t openamp_virtio_features_get(struct virtio_device *vdev)
+{
+	return 1 << VIRTIO_RPMSG_F_NS;
+}
+
+static void openamp_virtio_notify(struct virtqueue *vq)
+{
+	struct openamp_virtio_device *openamp_vdev;
+	struct openamp_messenger *openamp;
+	struct openamp_virtio *virtio;
+	int ret;
+
+	openamp_vdev = container_of(vq->vq_dev, struct openamp_virtio_device, virtio_dev);
+	virtio = container_of(openamp_vdev, struct openamp_virtio, vdev);
+	openamp = virtio->openamp;
+
+	ret = openamp->platform_ops->transport_notify(openamp);
+	if (ret < 0)
+		EMSG("openamp: virtio: erro in transport_notify: %d", ret);
+}
+
+const static struct virtio_dispatch openamp_virtio_dispatch = {
+	.get_status = openamp_virtio_status_get,
+	.set_status = openamp_virtio_status_set,
+	.get_features = openamp_virtio_features_get,
+	.notify = openamp_virtio_notify,
+};
+
+static int openamp_virtio_device_setup(struct openamp_virtio *virtio)
+{
+	struct openamp_virtio_metal *metal = &virtio->metal;
+	struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
+	struct virtio_device *vdev = &openamp_vdev->virtio_dev;
+	struct openamp_virtio_shm *shm = &metal->shm;
+	struct virtio_vring_info *rvring;
+
+	rvring = &openamp_vdev->rvrings[0];
+
+	vdev->role = RPMSG_REMOTE;
+	vdev->vrings_num = VIRTQUEUE_NR;
+	vdev->func = &openamp_virtio_dispatch;
+
+	openamp_vdev->vq[VQ_TX] = virtqueue_allocate(VRING_DESCRIPTORS);
+	if (!openamp_vdev->vq[VQ_TX]) {
+		EMSG("openamp: virtio: failed to allocate virtqueue 0");
+		return -ENOMEM;
+	}
+	rvring->io = metal->io;
+	rvring->info.vaddr = (void *)shm->vring_tx;
+	rvring->info.num_descs = VRING_DESCRIPTORS;
+	rvring->info.align = VRING_ALIGN;
+	rvring->vq = openamp_vdev->vq[VQ_TX];
+
+	openamp_vdev->vq[VQ_RX] = virtqueue_allocate(VRING_DESCRIPTORS);
+	if (!openamp_vdev->vq[VQ_RX]) {
+		EMSG("openamp: virtio: failed to allocate virtqueue 1");
+		goto free_vq;
+	}
+	rvring = &openamp_vdev->rvrings[VQ_RX];
+	rvring->io = metal->io;
+	rvring->info.vaddr = (void *)shm->vring_rx;
+	rvring->info.num_descs = VRING_DESCRIPTORS;
+	rvring->info.align = VRING_ALIGN;
+	rvring->vq = openamp_vdev->vq[VQ_RX];
+
+	vdev->vrings_info = &openamp_vdev->rvrings[0];
+
+	return 0;
+
+free_vq:
+	virtqueue_free(openamp_vdev->vq[VQ_TX]);
+	virtqueue_free(openamp_vdev->vq[VQ_RX]);
+
+	return -ENOMEM;
+}
+
+static int openamp_virtio_rpmsg_endpoint_callback(struct rpmsg_endpoint *ep,
+						  void *data, size_t len,
+						  uint32_t src, void *priv)
+{
+	struct openamp_virtio_rpmsg *vrpmsg;
+	struct rpmsg_device *rdev;
+
+	rdev = ep->rdev;
+	vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
+
+	rpmsg_hold_rx_buffer(ep, data);
+	vrpmsg->resp_buf = data;
+	vrpmsg->resp_len = len;
+
+	return 0;
+}
+
+static void openamp_virtio_rpmsg_service_unbind(struct rpmsg_endpoint *ep)
+{
+	struct openamp_virtio_rpmsg *vrpmsg;
+	struct rpmsg_device *rdev;
+
+	rdev = container_of(ep, struct rpmsg_device, ns_ept);
+	vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
+
+	rpmsg_destroy_ept(&vrpmsg->ep);
+}
+
+static void openamp_virtio_rpmsg_endpoint_bind(struct rpmsg_device *rdev,
+					       const char *name,
+					       unsigned int dest)
+{
+	struct openamp_virtio_rpmsg *vrpmsg;
+
+	vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
+
+	rpmsg_create_ept(&vrpmsg->ep, rdev, name, RPMSG_ADDR_ANY, dest,
+			 openamp_virtio_rpmsg_endpoint_callback,
+			 openamp_virtio_rpmsg_service_unbind);
+}
+
+static int openamp_virtio_rpmsg_device_setup(struct openamp_virtio *virtio,
+					     struct device_region *virtio_dev)
+{
+	struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
+	struct rpmsg_virtio_device *rpmsg_vdev = &vrpmsg->rpmsg_vdev;
+	struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
+	struct virtio_device *vdev = &openamp_vdev->virtio_dev;
+	struct openamp_virtio_metal *metal = &virtio->metal;
+	int ret;
+
+	/*
+	 * we assume here that we are the client side and do not need to
+	 * initialize the share memory poll (this is done at server side).
+	 */
+	ret = rpmsg_init_vdev(rpmsg_vdev, vdev,
+			      openamp_virtio_rpmsg_endpoint_bind, metal->io,
+			      NULL);
+	if (ret < 0) {
+		EMSG("openamp: virtio: init vdev failed: %d", ret);
+		return ret;
+	}
+
+
+	ret = rpmsg_create_ept(&vrpmsg->ep, &rpmsg_vdev->rdev,
+			       OPENAMP_RPMSG_ENDPOINT_NAME, RPMSG_ADDR_ANY,
+			       RPMSG_ADDR_ANY,
+			       openamp_virtio_rpmsg_endpoint_callback,
+			       openamp_virtio_rpmsg_service_unbind);
+	if (ret < 0) {
+		EMSG("openamp: virtio: failed to create endpoint: %d", ret);
+		return ret;
+	}
+
+	/* set default remote addr */
+	vrpmsg->ep.dest_addr = OPENAMP_RPMSG_ENDPOINT_ADDR;
+
+	return 0;
+}
+
+static void openamp_virtio_shm_set(struct openamp_virtio *virtio,
+				   struct device_region *virtio_region)
+{
+	struct openamp_virtio_shm *shm = &virtio->metal.shm;
+
+	shm->base_addr = virtio_region->base_addr;
+	shm->size = virtio_region->io_region_size;
+
+	shm->vdev_status = shm->base_addr;
+	shm->vdev_status_size = OPENAMP_SHEM_VDEV_SIZE;
+
+	shm->vring_rx = shm->base_addr + shm->size -
+		(2 * OPENAMP_SHEM_VRING_SIZE);
+	shm->vring_rx_size = OPENAMP_SHEM_VRING_SIZE;
+
+	shm->vring_tx = shm->vring_rx + shm->vring_rx_size;
+	shm->vring_tx_size = OPENAMP_SHEM_VRING_SIZE;
+
+	shm->payload_addr = shm->vdev_status + shm->vdev_status_size;
+	shm->payload_size = shm->size - shm->vdev_status_size -
+		shm->vring_rx_size - shm->vring_tx_size;
+
+	shm->shm_physmap[0] = OPENAMP_SHEM_PHYS + shm->vdev_status_size;
+
+	IMSG("SHEM: base: 0x%p size: %ld",
+	     (void *)shm->base_addr, shm->size);
+	IMSG("VDEV: base: 0x%p size: %ld",
+	     (void *)shm->vdev_status, shm->vdev_status_size);
+	IMSG("PAYLOAD: base: 0x%p size: %ld",
+	     (void *)shm->payload_addr, shm->payload_size);
+	IMSG("VRING_TX: base: 0x%p size: %ld",
+	     (void *)shm->vring_tx, shm->vring_tx_size);
+	IMSG("VRING_RX: base: 0x%p size: %ld",
+	     (void *)shm->vring_rx, shm->vring_rx_size);
+	IMSG("PHYMAP: base: 0x%p", (void *)shm->shm_physmap[0]);
+}
+
+static int openamp_virtio_device_get(const char *dev,
+				     struct device_region *dev_region)
+{
+	bool found;
+
+	found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
+				   dev_region, sizeof(*dev_region));
+	if (!found) {
+		EMSG("openamp: virtio: device region not found: %s", dev);
+		return -EINVAL;
+	}
+
+	if (dev_region->base_addr == 0 || dev_region->io_region_size == 0) {
+		EMSG("openamp: virtio: device region not valid");
+		return -EINVAL;
+	}
+
+	IMSG("openamp: virtio: device region found: %s addr: 0x%p size: %ld",
+	     dev, (void *)dev_region->base_addr, dev_region->io_region_size);
+
+	return  0;
+}
+
+int openamp_virtio_call_begin(struct openamp_messenger *openamp, uint8_t **req_buf,
+			      size_t req_len)
+{
+	struct openamp_virtio *virtio = openamp->platform;
+	struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
+	struct rpmsg_endpoint *ep = &vrpmsg->ep;
+
+
+	*req_buf = rpmsg_get_tx_payload_buffer(ep, &vrpmsg->req_len,
+					       OPENAMP_BUFFER_WAIT);
+	if (*req_buf == NULL)
+		return -EINVAL;
+
+	if (vrpmsg->req_len < req_len)
+		return -E2BIG;
+
+	vrpmsg->req_buf = *req_buf;
+
+	return 0;
+}
+
+int openamp_virtio_call_invoke(struct openamp_messenger *openamp,
+			       uint8_t **resp_buf, size_t *resp_len)
+{
+	const struct openamp_platform_ops *ops = openamp->platform_ops;
+	struct openamp_virtio *virtio = openamp->platform;
+	struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
+	struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
+	struct rpmsg_endpoint *ep = &vrpmsg->ep;
+	int ret;
+
+	ret = rpmsg_send_nocopy(ep, vrpmsg->req_buf, vrpmsg->req_len);
+	if (ret < 0) {
+		EMSG("openamp: virtio: send nocopy failed: %d", ret);
+		return -EIO;
+	}
+
+	if (ret != vrpmsg->req_len) {
+		EMSG("openamp: virtio: send less bytes %d than requested %d",
+		     ret, vrpmsg->req_len);
+		return -EIO;
+	}
+
+	if (!ops->transport_receive)
+		return 0;
+
+	ret = ops->transport_receive(openamp);
+	if (ret < 0) {
+		EMSG("openamp: virtio: failed transport_receive");
+		return -EIO;
+	}
+
+	virtqueue_notification(openamp_vdev->vq[VQ_RX]);
+
+	*resp_buf = vrpmsg->resp_buf;
+	*resp_len = vrpmsg->resp_len;
+
+	return  0;
+}
+
+void openamp_virtio_call_end(struct openamp_messenger *openamp)
+{
+	struct openamp_virtio *virtio = openamp->platform;
+	struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
+
+	rpmsg_release_rx_buffer(&vrpmsg->ep, vrpmsg->resp_buf);
+
+	vrpmsg->req_buf = NULL;
+	vrpmsg->req_len = 0;
+	vrpmsg->resp_buf = NULL;
+	vrpmsg->resp_len = 0;
+}
+
+void *openamp_virtio_virt_to_phys(struct openamp_messenger *openamp, void *va)
+{
+	struct openamp_virtio *virtio = openamp->platform;
+	struct openamp_virtio_metal *metal = &virtio->metal;
+
+	return (void *)metal_io_virt_to_phys(metal->io, va);
+}
+
+void *openamp_virtio_phys_to_virt(struct openamp_messenger *openamp, void *pa)
+{
+	struct openamp_virtio *virtio = openamp->platform;
+	struct openamp_virtio_metal *metal = &virtio->metal;
+
+	return metal_io_phys_to_virt(metal->io, (metal_phys_addr_t)pa);
+}
+
+int openamp_virtio_init(struct openamp_messenger *openamp)
+{
+	struct device_region virtio_dev;
+	struct openamp_virtio *virtio;
+	int ret;
+
+	if (openamp->platform)
+		return 0;
+
+
+	virtio = malloc(sizeof(*virtio));
+	if (!virtio)
+		return -ENOMEM;
+
+	virtio->openamp = openamp;
+
+	ret = openamp_virtio_device_get(OPENAMP_SHEM_DEVICE_NAME, &virtio_dev);
+	if (ret < 0)
+		goto free_virtio;
+
+	openamp_virtio_shm_set(virtio, &virtio_dev);
+
+	ret = openamp_virtio_metal_init(&virtio->metal);
+	if (ret < 0)
+		goto free_virtio;
+
+	ret = openamp_virtio_device_setup(virtio);
+	if (ret < 0)
+		goto finish_metal;
+
+	ret = openamp_virtio_rpmsg_device_setup(virtio, &virtio_dev);
+	if (ret < 0) {
+		EMSG("openamp: virtio: rpmsg device setup failed: %d", ret);
+		goto finish_metal;
+	}
+
+	openamp->platform = virtio;
+
+	return 0;
+
+finish_metal:
+	metal_finish();
+
+free_virtio:
+	free(virtio);
+
+	return ret;
+}
+
+int openamp_virtio_deinit(struct openamp_messenger *openamp)
+{
+	struct openamp_virtio *virtio;
+
+	if (!openamp->platform)
+		return 0;
+
+	virtio = openamp->platform;
+
+	metal_finish();
+	free(virtio);
+
+	openamp->platform = NULL;
+
+	return 0;
+}
diff --git a/components/messaging/openamp/sp/openamp_virtio.h b/components/messaging/openamp/sp/openamp_virtio.h
new file mode 100644
index 0000000..bb4f7a5
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_virtio.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef OPENAMP_VIRTIO_H
+#define OPENAMP_VIRTIO_H
+
+#include <stddef.h>
+#include "openamp_messenger_api.h"
+
+int openamp_virtio_call_begin(struct openamp_messenger *openamp,
+			      uint8_t **req_buf, size_t req_len);
+int openamp_virtio_call_invoke(struct openamp_messenger *openamp,
+			       uint8_t **resp_buf, size_t *resp_len);
+int openamp_virtio_call_end(struct openamp_messenger *openamp);
+void *openamp_virtio_virt_to_phys(struct openamp_messenger *openamp, void *va);
+void *openamp_virtio_phys_to_virt(struct openamp_messenger *openamp, void *pa);
+
+int openamp_virtio_init(struct openamp_messenger *openamp);
+int openamp_virtio_deinit(struct openamp_messenger *openamp);
+
+#endif
diff --git a/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.c b/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.c
new file mode 100644
index 0000000..bc5dfe7
--- /dev/null
+++ b/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "psa_ipc_caller.h"
+#include <openamp_messenger_api.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <rpc_caller.h>
+#include <rpc_status.h>
+#include <trace.h>
+#include <errno.h>
+#include <stdint.h>
+
+static rpc_call_handle psa_ipc_call_begin(void *context, uint8_t **req_buf,
+					  size_t req_len)
+{
+	struct psa_ipc_caller *psa_ipc = context;
+	struct openamp_messenger *openamp = &psa_ipc->openamp;
+	rpc_call_handle handle;
+	int ret;
+
+	ret = openamp_messenger_call_begin(openamp, req_buf, req_len);
+	if (ret < 0)
+		return NULL;
+
+	handle = psa_ipc;
+
+	return handle;
+}
+
+static rpc_status_t psa_ipc_call_invoke(void *context, rpc_call_handle handle,
+					uint32_t opcode, long int *opstatus,
+					uint8_t **resp_buf, size_t *resp_len)
+{
+	struct psa_ipc_caller *psa_ipc = context;
+	struct openamp_messenger *openamp = &psa_ipc->openamp;
+	int ret;
+
+	(void)opcode;
+
+	ret = openamp_messenger_call_invoke(openamp, resp_buf, resp_len);
+	if (ret == -EINVAL)
+		return TS_RPC_ERROR_INVALID_PARAMETER;
+	if (ret == -ENOTCONN)
+		return TS_RPC_ERROR_NOT_READY;
+	if (ret < 0)
+		return TS_RPC_ERROR_INTERNAL;
+
+	*opstatus = 0;
+
+	return TS_RPC_CALL_ACCEPTED;
+}
+
+static void psa_ipc_call_end(void *context, rpc_call_handle handle)
+{
+	struct psa_ipc_caller *psa_ipc = context;
+
+	if (!psa_ipc || psa_ipc != handle) {
+		EMSG("psa_ipc: call_end: invalid arguments");
+		return;
+	}
+
+	openamp_messenger_call_end(&psa_ipc->openamp);
+}
+
+
+void *psa_ipc_phys_to_virt(void *context, void *pa)
+{
+	struct psa_ipc_caller *psa_ipc = context;
+	struct openamp_messenger *openamp = &psa_ipc->openamp;
+
+	return openamp_messenger_phys_to_virt(openamp, pa);
+}
+
+void *psa_ipc_virt_to_phys(void *context, void *va)
+{
+	struct psa_ipc_caller *psa_ipc = context;
+	struct openamp_messenger *openamp = &psa_ipc->openamp;
+
+	return openamp_messenger_virt_to_phys(openamp, va);
+}
+
+struct rpc_caller *psa_ipc_caller_init(struct psa_ipc_caller *psa_ipc)
+{
+	struct rpc_caller *rpc = &psa_ipc->rpc_caller;
+	int ret;
+
+	ret = openamp_messenger_init(&psa_ipc->openamp);
+	if (ret < 0)
+		return NULL;
+
+	rpc_caller_init(rpc, &psa_ipc->rpc_caller);
+	rpc->call_begin = psa_ipc_call_begin;
+	rpc->call_invoke = psa_ipc_call_invoke;
+	rpc->call_end = psa_ipc_call_end;
+
+	return rpc;
+}
+
+struct rpc_caller *psa_ipc_caller_deinit(struct psa_ipc_caller *psa_ipc)
+{
+	struct rpc_caller *rpc = &psa_ipc->rpc_caller;
+
+	rpc->context = NULL;
+	rpc->call_begin = NULL;
+	rpc->call_invoke = NULL;
+	rpc->call_end = NULL;
+
+	return rpc;
+}
diff --git a/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.h b/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.h
new file mode 100644
index 0000000..1b84e98
--- /dev/null
+++ b/components/rpc/psa_ipc/caller/sp/psa_ipc_caller.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <rpc_caller.h>
+#include <openamp_messenger_api.h>
+
+struct psa_ipc_caller {
+	struct rpc_caller rpc_caller;
+	struct openamp_messenger openamp;
+};
+
+void *psa_ipc_phys_to_virt(void *context, void *pa);
+void *psa_ipc_virt_to_phys(void *context, void *va);
+
+struct rpc_caller *psa_ipc_caller_init(struct psa_ipc_caller *psaipc);
+struct rpc_caller *psa_ipc_caller_deinit(struct psa_ipc_caller *psaipc);
diff --git a/components/rpc/psa_ipc/component.cmake b/components/rpc/psa_ipc/component.cmake
new file mode 100644
index 0000000..5d9c72b
--- /dev/null
+++ b/components/rpc/psa_ipc/component.cmake
@@ -0,0 +1,24 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+set_property(TARGET ${TGT} APPEND PROPERTY PUBLIC_HEADER
+	${CMAKE_CURRENT_LIST_DIR}/caller/sp/psa_ipc_caller.h
+	)
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/service_psa_ipc.c"
+	"${CMAKE_CURRENT_LIST_DIR}/caller/sp/psa_ipc_caller.c"
+	)
+
+target_include_directories(${TGT}
+	 PUBLIC
+		"${CMAKE_CURRENT_LIST_DIR}/caller/sp/"
+	)
+
diff --git a/components/rpc/psa_ipc/service_psa_ipc.c b/components/rpc/psa_ipc/service_psa_ipc.c
new file mode 100644
index 0000000..830f461
--- /dev/null
+++ b/components/rpc/psa_ipc/service_psa_ipc.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <trace.h>
+
+#include <protocols/rpc/common/packed-c/status.h>
+#include <psa/error.h>
+#include <rpc_caller.h>
+
+#include <psa/client.h>
+#include <psa_ipc_caller.h>
+#include "service_psa_ipc_openamp_lib.h"
+
+static inline void *unaligned_memcpy(void *dst_init, const void *src_init,
+				     size_t len)
+{
+	char *dst = dst_init;
+	const char *src = src_init;
+
+	while (len--)
+		*dst++ = *src++;
+
+	return dst_init;
+}
+
+static struct psa_invec *psa_call_in_vec_param(uint8_t *req)
+{
+	return (struct psa_invec *)(req + sizeof(struct ns_openamp_msg));
+}
+
+static struct psa_outvec *psa_call_out_vec_param(uint8_t *req, size_t in_len)
+{
+	return (struct psa_outvec *)(req + sizeof(struct ns_openamp_msg) +
+				     (in_len * sizeof(struct psa_invec)));
+}
+
+static size_t psa_call_header_len(const struct psa_invec *in_vec, size_t in_len,
+				  struct psa_outvec *out_vec, size_t out_len)
+{
+	return sizeof(struct ns_openamp_msg) + (in_len * sizeof(*in_vec)) +
+		(out_len * sizeof(*out_vec));
+}
+
+static size_t psa_call_in_vec_len(const struct psa_invec *in_vec, size_t in_len)
+{
+	size_t req_len = 0;
+	int i;
+
+	if (!in_vec || !in_len)
+		return 0;
+
+	for (i = 0; i < in_len; i++)
+		req_len += in_vec[i].len;
+
+	return req_len;
+}
+
+static uint32_t psa_virt_to_phys_u32(struct rpc_caller *caller, void *va)
+{
+	return (uintptr_t)psa_ipc_virt_to_phys(caller->context, va);
+}
+
+psa_handle_t psa_connect(struct rpc_caller *caller, uint32_t sid,
+			 uint32_t version)
+{
+	rpc_opstatus_t opstatus = PSA_SUCCESS;
+	struct s_openamp_msg *resp_msg = NULL;
+	struct ns_openamp_msg *req_msg;
+	rpc_call_handle rpc_handle;
+	size_t resp_len;
+	uint8_t *resp;
+	uint8_t *req;
+	int ret;
+
+	rpc_handle = rpc_caller_begin(caller, &req,
+				      sizeof(struct ns_openamp_msg));
+	if (!rpc_handle) {
+		EMSG("psa_connect: could not get rpc handle");
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	req_msg = (struct ns_openamp_msg *)req;
+
+	req_msg->call_type = OPENAMP_PSA_CONNECT;
+	req_msg->params.psa_connect_params.sid = sid;
+	req_msg->params.psa_connect_params.version = version;
+
+	ret = rpc_caller_invoke(caller, rpc_handle, 0, &opstatus, &resp,
+				&resp_len);
+	if (ret != TS_RPC_CALL_ACCEPTED) {
+		EMSG("psa_connect: invoke failed: %d", ret);
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	if (opstatus == PSA_SUCCESS)
+		resp_msg = (struct s_openamp_msg *)resp;
+
+	rpc_caller_end(caller, rpc_handle);
+
+	return resp_msg ? (psa_handle_t)resp_msg->reply : PSA_NULL_HANDLE;
+}
+
+static psa_status_t __psa_call(struct rpc_caller *caller, psa_handle_t psa_handle,
+			       int32_t client_id, int32_t type,
+			       const struct psa_invec *in_vec, size_t in_len,
+			       struct psa_outvec *out_vec, size_t out_len)
+{
+	rpc_opstatus_t opstatus = PSA_SUCCESS;
+	struct s_openamp_msg *resp_msg = NULL;
+	struct psa_outvec *out_vec_param;
+	struct psa_invec *in_vec_param;
+	struct ns_openamp_msg *req_msg;
+	rpc_call_handle rpc_handle;
+	size_t in_vec_len;
+	size_t header_len;
+	uint8_t *payload;
+	size_t resp_len;
+	uint8_t *resp;
+	uint8_t *req;
+	int ret;
+	int i;
+
+	if ((psa_handle == PSA_NULL_HANDLE) || !caller)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	header_len = psa_call_header_len(in_vec, in_len, out_vec, out_len);
+	in_vec_len = psa_call_in_vec_len(in_vec, in_len);
+
+	rpc_handle = rpc_caller_begin(caller, &req, header_len + in_vec_len);
+	if (!rpc_handle) {
+		EMSG("psa_call: could not get handle");
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	payload = req + header_len;
+
+	out_vec_param = psa_call_out_vec_param(req, in_len);
+	in_vec_param = psa_call_in_vec_param(req);
+
+	req_msg = (struct ns_openamp_msg *)req;
+
+	req_msg->call_type = OPENAMP_PSA_CALL;
+	req_msg->request_id = 1234;
+	req_msg->client_id = client_id;
+	req_msg->params.psa_call_params.handle = psa_handle;
+	req_msg->params.psa_call_params.type = type;
+	req_msg->params.psa_call_params.in_len = in_len;
+	req_msg->params.psa_call_params.in_vec = psa_virt_to_phys_u32(caller, in_vec_param);
+	req_msg->params.psa_call_params.out_len = out_len;
+	req_msg->params.psa_call_params.out_vec = psa_virt_to_phys_u32(caller, out_vec_param);
+
+	for (i = 0; i < in_len; i++) {
+		in_vec_param[i].base = psa_virt_to_phys_u32(caller, payload);
+		in_vec_param[i].len = in_vec[i].len;
+
+		unaligned_memcpy(payload, psa_u32_to_ptr(in_vec[i].base),
+				 in_vec[i].len);
+		payload += in_vec[i].len;
+	}
+
+	for (i = 0; i < out_len; i++) {
+		out_vec_param[i].base = 0;
+		out_vec_param[i].len = out_vec[i].len;
+	}
+
+	ret = rpc_caller_invoke(caller, rpc_handle, 0, &opstatus, &resp,
+				&resp_len);
+	if (ret != TS_RPC_CALL_ACCEPTED) {
+		EMSG("psa_call: invoke failed: %d", ret);
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	if (opstatus != PSA_SUCCESS) {
+		EMSG("psa_call: psa_status invoke failed: %ld", opstatus);
+		return PSA_ERROR_GENERIC_ERROR;
+	}
+
+	resp_msg = (struct s_openamp_msg *)resp;
+
+	if (!resp_msg || !out_len || resp_msg->reply != PSA_SUCCESS)
+		goto caller_end;
+
+	out_vec_param = (struct psa_outvec *)psa_ipc_phys_to_virt(caller,
+				psa_u32_to_ptr(resp_msg->params.out_vec));
+
+	for (i = 0; i < resp_msg->params.out_len; i++) {
+		out_vec[i].len = out_vec_param[i].len;
+		unaligned_memcpy(psa_u32_to_ptr(out_vec[i].base),
+				 psa_ipc_phys_to_virt(caller,
+				      psa_u32_to_ptr(out_vec_param[i].base)),
+				 out_vec[i].len);
+	}
+
+caller_end:
+	rpc_caller_end(caller, rpc_handle);
+
+	return resp_msg ? resp_msg->reply : PSA_ERROR_COMMUNICATION_FAILURE;
+}
+
+psa_status_t psa_call_client_id(struct rpc_caller *caller,
+				psa_handle_t psa_handle, int32_t client_id,
+				int32_t type, const struct psa_invec *in_vec,
+				size_t in_len, struct psa_outvec *out_vec,
+				size_t out_len)
+{
+	return __psa_call(caller, psa_handle, client_id, type, in_vec, in_len,
+			  out_vec, out_len);
+}
+
+psa_status_t psa_call(struct rpc_caller *caller, psa_handle_t psa_handle,
+		      int32_t type, const struct psa_invec *in_vec,
+		      size_t in_len, struct psa_outvec *out_vec, size_t out_len)
+{
+	return __psa_call(caller, psa_handle, 0, type, in_vec, in_len, out_vec,
+			  out_len);
+}
+
+void psa_close(struct rpc_caller *caller, psa_handle_t psa_handle)
+{
+	rpc_opstatus_t opstatus = PSA_SUCCESS;
+	struct ns_openamp_msg *req_msg;
+	rpc_call_handle rpc_handle;
+	size_t resp_len;
+	uint8_t *resp;
+	uint8_t *req;
+	int ret;
+
+	if ((psa_handle == PSA_NULL_HANDLE) || !caller)
+		return;
+
+	rpc_handle = rpc_caller_begin(caller, &req,
+				      sizeof(struct ns_openamp_msg));
+	if (!rpc_handle) {
+		EMSG("psa_close: could not get handle");
+		return;
+	}
+
+	req_msg = (struct ns_openamp_msg *)req;
+
+	req_msg->call_type = OPENAMP_PSA_CLOSE;
+	req_msg->params.psa_close_params.handle = psa_handle;
+
+	ret = rpc_caller_invoke(caller, rpc_handle, 0, &opstatus, &resp,
+				&resp_len);
+	if (ret != TS_RPC_CALL_ACCEPTED) {
+		EMSG("psa_close: invoke failed: %d", ret);
+		return;
+	}
+
+	rpc_caller_end(caller, rpc_handle);
+}
diff --git a/components/rpc/psa_ipc/service_psa_ipc_openamp_lib.h b/components/rpc/psa_ipc/service_psa_ipc_openamp_lib.h
new file mode 100644
index 0000000..38ad2ed
--- /dev/null
+++ b/components/rpc/psa_ipc/service_psa_ipc_openamp_lib.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SERVICE_PSA_IPC_OPENAMP_LIB_H
+#define SERVICE_PSA_IPC_OPENAMP_LIB_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <compiler.h>
+#include <psa/error.h>
+
+#include <stdint.h>
+#include <psa/client.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* PSA client call type value */
+#define OPENAMP_PSA_FRAMEWORK_VERSION       (0x1)
+#define OPENAMP_PSA_VERSION                 (0x2)
+#define OPENAMP_PSA_CONNECT                 (0x3)
+#define OPENAMP_PSA_CALL                    (0x4)
+#define OPENAMP_PSA_CLOSE                   (0x5)
+
+/* Return code of openamp APIs */
+#define OPENAMP_SUCCESS                     (0)
+#define OPENAMP_MAP_FULL                    (INT32_MIN + 1)
+#define OPENAMP_MAP_ERROR                   (INT32_MIN + 2)
+#define OPENAMP_INVAL_PARAMS                (INT32_MIN + 3)
+#define OPENAMP_NO_PERMS                    (INT32_MIN + 4)
+#define OPENAMP_NO_PEND_EVENT               (INT32_MIN + 5)
+#define OPENAMP_CHAN_BUSY                   (INT32_MIN + 6)
+#define OPENAMP_CALLBACK_REG_ERROR          (INT32_MIN + 7)
+#define OPENAMP_INIT_ERROR                  (INT32_MIN + 8)
+
+#define HOLD_INPUT_BUFFER (1) /* IF true, TF-M Library will hold the openamp
+			       * buffer so that openamp shared memory buffer
+			       * does not get freed.
+			       */
+
+/*
+ * This structure holds the parameters used in a PSA client call.
+ */
+typedef struct __packed psa_client_in_params {
+	union {
+		struct __packed {
+			uint32_t        sid;
+		} psa_version_params;
+
+		struct __packed {
+			uint32_t        sid;
+			uint32_t        version;
+		} psa_connect_params;
+
+		struct __packed {
+			psa_handle_t     handle;
+			int32_t          type;
+			uint32_t         in_vec;
+			uint32_t         in_len;
+			uint32_t         out_vec;
+			uint32_t         out_len;
+		} psa_call_params;
+
+		struct __packed {
+			psa_handle_t    handle;
+		} psa_close_params;
+	};
+} psa_client_in_params_t;
+
+/* Openamp message passed from NSPE to SPE to deliver a PSA client call */
+struct __packed ns_openamp_msg {
+	uint32_t                      call_type;   /* PSA client call type */
+	struct psa_client_in_params   params;      /* Contain parameters used in PSA
+						  * client call
+						  */
+
+	int32_t                     client_id;   /* Optional client ID of the
+						  * non-secure caller.
+						  * It is required to identify the
+						  * non-secure task when NSPE OS
+						  * enforces non-secure task
+						  * isolation
+						  */
+	int32_t                     request_id;  /* This is the unique ID for a
+						  * request send to TF-M by the
+						  * non-secure core. TF-M forward
+						  * the ID back to non-secure on the
+						  * reply to a given request. Using
+						  * this id, the non-secure library
+						  * can identify the request for
+						  * which the reply has received.
+						  */
+};
+
+/*
+ * This structure holds the location of the out data of the PSA client call.
+ */
+struct __packed psa_client_out_params {
+	uint32_t              out_vec;
+	uint32_t              out_len;
+};
+
+
+/* Openamp message from SPE to NSPE delivering the reply back for a PSA client
+ * call.
+ */
+struct __packed s_openamp_msg {
+	int32_t                     request_id;  /* Using this id, the non-secure
+						  * library identifies the request.
+						  * TF-M forwards the same
+						  * request-id received on the
+						  * initial request.
+						  */
+	int32_t                     reply;       /* Reply of the PSA client call */
+	struct psa_client_out_params     params;      /* Contain out data result of the
+						       * PSA client call.
+						       */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SERVICE_PSA_IPC_OPENAMP_LIB_H */
+
+
diff --git a/components/service/attestation/client/psa_ipc/component.cmake b/components/service/attestation/client/psa_ipc/component.cmake
new file mode 100644
index 0000000..ec581de
--- /dev/null
+++ b/components/service/attestation/client/psa_ipc/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/iat_ipc_client.c"
+	)
diff --git a/components/service/attestation/client/psa_ipc/iat_ipc_client.c b/components/service/attestation/client/psa_ipc/iat_ipc_client.c
new file mode 100644
index 0000000..c26a0fe
--- /dev/null
+++ b/components/service/attestation/client/psa_ipc/iat_ipc_client.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "../psa/iat_client.h"
+#include <protocols/rpc/common/packed-c/status.h>
+#include <psa/initial_attestation.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+
+/**
+ * @brief      The singleton psa_iat_client instance
+ *
+ * The psa attestation C API assumes a single backend service provider.
+ */
+static struct service_client instance;
+
+
+psa_status_t psa_iat_client_init(struct rpc_caller *caller)
+{
+	return service_client_init(&instance, caller);
+}
+
+void psa_iat_client_deinit(void)
+{
+	service_client_deinit(&instance);
+}
+
+int psa_iat_client_rpc_status(void)
+{
+	return instance.rpc_status;
+}
+
+psa_status_t psa_initial_attest_get_token(const uint8_t *auth_challenge,
+					  size_t challenge_size,
+					  uint8_t *token_buf,
+					  size_t token_buf_size,
+					  size_t *token_size)
+{
+	psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+	struct rpc_caller *caller = instance.caller;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_const_to_u32(auth_challenge), .len = challenge_size},
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(token_buf), .len = token_buf_size},
+	};
+
+	if (!token_buf || !token_buf_size)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	status = psa_call(caller, TFM_ATTESTATION_SERVICE_HANDLE,
+			  TFM_ATTEST_GET_TOKEN, in_vec, IOVEC_LEN(in_vec),
+			  out_vec, IOVEC_LEN(out_vec));
+	if (status == PSA_SUCCESS) {
+		*token_size = out_vec[0].len;
+	}
+
+	return status;
+}
+
+psa_status_t psa_initial_attest_get_token_size(size_t challenge_size,
+						size_t *token_size)
+{
+	struct rpc_caller *caller = instance.caller;
+	psa_status_t status;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&challenge_size), .len = sizeof(uint32_t)}
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(token_size), .len = sizeof(uint32_t)}
+	};
+
+	status = psa_call(caller, TFM_ATTESTATION_SERVICE_HANDLE,
+			  TFM_ATTEST_GET_TOKEN_SIZE,
+			  in_vec, IOVEC_LEN(in_vec),
+			  out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
diff --git a/components/service/attestation/reporter/psa_ipc/component.cmake b/components/service/attestation/reporter/psa_ipc/component.cmake
new file mode 100644
index 0000000..e3dd0b7
--- /dev/null
+++ b/components/service/attestation/reporter/psa_ipc/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/psa_ipc_attest_report.c"
+	)
diff --git a/components/service/attestation/reporter/psa_ipc/psa_ipc_attest_report.c b/components/service/attestation/reporter/psa_ipc/psa_ipc_attest_report.c
new file mode 100644
index 0000000..c0bda91
--- /dev/null
+++ b/components/service/attestation/reporter/psa_ipc/psa_ipc_attest_report.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * A attestation reporter for psa ipc
+ */
+
+#include <stddef.h>
+#include <psa/error.h>
+#include <service/attestation/reporter/attest_report.h>
+#include <psa/initial_attestation.h>
+
+#define TOKEN_BUF_SIZE	1024
+
+static uint8_t token_buf[TOKEN_BUF_SIZE];
+
+int attest_report_create(int32_t client_id, const uint8_t *auth_challenge_data,
+			 size_t auth_challenge_len, const uint8_t **report,
+			 size_t *report_len)
+{
+	*report = token_buf;
+	psa_status_t ret;
+	size_t token_size = 0;
+
+	ret = psa_initial_attest_get_token(auth_challenge_data,
+					   auth_challenge_len, token_buf,
+					   TOKEN_BUF_SIZE, &token_size);
+	if (ret != PSA_SUCCESS) {
+		*report = NULL;
+		*report_len = 0;
+		return ret;
+	}
+
+	*report_len = token_size;
+
+	return PSA_SUCCESS;
+}
+
+void attest_report_destroy(const uint8_t *report)
+{
+	(void)report;
+}
diff --git a/components/service/common/include/psa/client.h b/components/service/common/include/psa/client.h
new file mode 100644
index 0000000..2f39aa6
--- /dev/null
+++ b/components/service/common/include/psa/client.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2018-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SERVICE_PSA_IPC_H
+#define SERVICE_PSA_IPC_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <rpc_caller.h>
+#include <psa/error.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef IOVEC_LEN
+#define IOVEC_LEN(arr) ((uint32_t)(sizeof(arr)/sizeof(arr[0])))
+#endif
+
+/*********************** PSA Client Macros and Types *************************/
+
+typedef int32_t psa_handle_t;
+
+/**
+ * The version of the PSA Framework API that is being used to build the calling
+ * firmware. Only part of features of FF-M v1.1 have been implemented. FF-M v1.1
+ * is compatible with v1.0.
+ */
+#define PSA_FRAMEWORK_VERSION       (0x0101u)
+
+/**
+ * Return value from psa_version() if the requested RoT Service is not present
+ * in the system.
+ */
+#define PSA_VERSION_NONE            (0u)
+
+/**
+ * The zero-value null handle can be assigned to variables used in clients and
+ * RoT Services, indicating that there is no current connection or message.
+ */
+#define PSA_NULL_HANDLE             ((psa_handle_t)0)
+
+/**
+ * Tests whether a handle value returned by psa_connect() is valid.
+ */
+#define PSA_HANDLE_IS_VALID(handle) ((psa_handle_t)(handle) > 0)
+
+/**
+ * Converts the handle value returned from a failed call psa_connect() into
+ * an error code.
+ */
+#define PSA_HANDLE_TO_ERROR(handle) ((psa_status_t)(handle))
+
+/**
+ * Maximum number of input and output vectors for a request to psa_call().
+ */
+#define PSA_MAX_IOVEC               (4u)
+
+/**
+ * An IPC message type that indicates a generic client request.
+ */
+#define PSA_IPC_CALL                (0)
+
+/**
+ * A read-only input memory region provided to an RoT Service.
+ */
+struct __attribute__ ((__packed__)) psa_invec {
+    uint32_t base;           /*!< the start address of the memory buffer */
+    uint32_t len;                 /*!< the size in bytes                      */
+};
+
+/**
+ * A writable output memory region provided to an RoT Service.
+ */
+struct __attribute__ ((__packed__)) psa_outvec {
+    uint32_t base;                 /*!< the start address of the memory buffer */
+    uint32_t len;                 /*!< the size in bytes                      */
+};
+
+inline static void *psa_u32_to_ptr(uint32_t addr)
+{
+	return (void *)(uintptr_t)addr;
+}
+
+inline static uint32_t psa_ptr_to_u32(void *ptr)
+{
+	return (uintptr_t)ptr;
+}
+
+inline static uint32_t psa_ptr_const_to_u32(const void *ptr)
+{
+	return (uintptr_t)ptr;
+}
+
+/*************************** PSA Client API **********************************/
+
+/**
+ * \brief Retrieve the version of the PSA Framework API that is implemented.
+ *
+ * \param[in] rpc_caller        RPC caller to use
+ * \return version              The version of the PSA Framework implementation
+ *                              that is providing the runtime services to the
+ *                              caller. The major and minor version are encoded
+ *                              as follows:
+ * \arg                           version[15:8] -- major version number.
+ * \arg                           version[7:0]  -- minor version number.
+ */
+uint32_t psa_framework_version(struct rpc_caller *caller);
+
+/**
+ * \brief Retrieve the version of an RoT Service or indicate that it is not
+ *        present on this system.
+ *
+ * \param[in] rpc_caller        RPC caller to use
+ * \param[in] sid               ID of the RoT Service to query.
+ *
+ * \retval PSA_VERSION_NONE     The RoT Service is not implemented, or the
+ *                              caller is not permitted to access the service.
+ * \retval > 0                  The version of the implemented RoT Service.
+ */
+uint32_t psa_version(struct rpc_caller *caller, uint32_t sid);
+
+/**
+ * \brief Connect to an RoT Service by its SID.
+ *
+ * \param[in] rpc_caller        RPC caller to use
+ * \param[in] sid               ID of the RoT Service to connect to.
+ * \param[in] version           Requested version of the RoT Service.
+ *
+ * \retval > 0                  A handle for the connection.
+ * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
+ *                              connection.
+ * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
+ *                              connection at the moment.
+ * \retval "PROGRAMMER ERROR"   The call is a PROGRAMMER ERROR if one or more
+ *                              of the following are true:
+ * \arg                           The RoT Service ID is not present.
+ * \arg                           The RoT Service version is not supported.
+ * \arg                           The caller is not allowed to access the RoT
+ *                                service.
+ */
+psa_handle_t psa_connect(struct rpc_caller *caller, uint32_t sid,
+			 uint32_t version);
+
+/**
+ * \brief Call an RoT Service on an established connection.
+ *
+ * \note  FF-M 1.0 proposes 6 parameters for psa_call but the secure gateway ABI
+ *        support at most 4 parameters. TF-M chooses to encode 'in_len',
+ *        'out_len', and 'type' into a 32-bit integer to improve efficiency.
+ *        Compared with struct-based encoding, this method saves extra memory
+ *        check and memory copy operation. The disadvantage is that the 'type'
+ *        range has to be reduced into a 16-bit integer. So with this encoding,
+ *        the valid range for 'type' is 0-32767.
+ *
+ * \param[in] rpc_caller        RPC caller to use
+ * \param[in] handle            A handle to an established connection.
+ * \param[in] type              The request type.
+ *                              Must be zero( \ref PSA_IPC_CALL) or positive.
+ * \param[in] in_vec            Array of input \ref psa_invec structures.
+ * \param[in] in_len            Number of input \ref psa_invec structures.
+ * \param[in,out] out_vec       Array of output \ref psa_outvec structures.
+ * \param[in] out_len           Number of output \ref psa_outvec structures.
+ *
+ * \retval >=0                  RoT Service-specific status value.
+ * \retval <0                   RoT Service-specific error code.
+ * \retval PSA_ERROR_PROGRAMMER_ERROR The connection has been terminated by the
+ *                              RoT Service. The call is a PROGRAMMER ERROR if
+ *                              one or more of the following are true:
+ * \arg                           An invalid handle was passed.
+ * \arg                           The connection is already handling a request.
+ * \arg                           type < 0.
+ * \arg                           An invalid memory reference was provided.
+ * \arg                           in_len + out_len > PSA_MAX_IOVEC.
+ * \arg                           The message is unrecognized by the RoT
+ *                                Service or incorrectly formatted.
+ */
+psa_status_t psa_call(struct rpc_caller *caller, psa_handle_t handle,
+		      int32_t type, const struct psa_invec *in_vec,
+		      size_t in_len, struct psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief Call an RoT Service on an established connection.
+ *
+ * \note  FF-M 1.0 proposes 6 parameters for psa_call but the secure gateway ABI
+ *        support at most 4 parameters. TF-M chooses to encode 'in_len',
+ *        'out_len', and 'type' into a 32-bit integer to improve efficiency.
+ *        Compared with struct-based encoding, this method saves extra memory
+ *        check and memory copy operation. The disadvantage is that the 'type'
+ *        range has to be reduced into a 16-bit integer. So with this encoding,
+ *        the valid range for 'type' is 0-32767.
+ *
+ * \param[in] rpc_caller        RPC caller to use
+ * \param[in] handle            A handle to an established connection.
+ * \param[in] client_id         A client_id to be passed over the request
+ * \param[in] type              The request type.
+ *                              Must be zero( \ref PSA_IPC_CALL) or positive.
+ * \param[in] in_vec            Array of input \ref psa_invec structures.
+ * \param[in] in_len            Number of input \ref psa_invec structures.
+ * \param[in,out] out_vec       Array of output \ref psa_outvec structures.
+ * \param[in] out_len           Number of output \ref psa_outvec structures.
+ *
+ * \retval >=0                  RoT Service-specific status value.
+ * \retval <0                   RoT Service-specific error code.
+ * \retval PSA_ERROR_PROGRAMMER_ERROR The connection has been terminated by the
+ *                              RoT Service. The call is a PROGRAMMER ERROR if
+ *                              one or more of the following are true:
+ * \arg                           An invalid handle was passed.
+ * \arg                           The connection is already handling a request.
+ * \arg                           type < 0.
+ * \arg                           An invalid memory reference was provided.
+ * \arg                           in_len + out_len > PSA_MAX_IOVEC.
+ * \arg                           The message is unrecognized by the RoT
+ *                                Service or incorrectly formatted.
+ */
+psa_status_t psa_call_client_id(struct rpc_caller *caller, psa_handle_t handle,
+				int32_t client_id, int32_t type,
+				const struct psa_invec *in_vec, size_t in_len,
+				struct psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief Close a connection to an RoT Service.
+ *
+ * \param[in] rpc_caller        RPC caller to use
+ * \param[in] handle            A handle to an established connection, or the
+ *                              null handle.
+ *
+ * \retval void                 Success.
+ * \retval "PROGRAMMER ERROR"   The call is a PROGRAMMER ERROR if one or more
+ *                              of the following are true:
+ * \arg                           An invalid handle was provided that is not
+ *                                the null handle.
+ * \arg                           The connection is currently handling a
+ *                                request.
+ */
+void psa_close(struct rpc_caller *caller, psa_handle_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SERVICE_PSA_IPC_H */
+
+
diff --git a/components/service/common/include/psa/sid.h b/components/service/common/include/psa/sid.h
new file mode 100644
index 0000000..8e2c6bd
--- /dev/null
+++ b/components/service/common/include/psa/sid.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __PSA_MANIFEST_SID_H__
+#define __PSA_MANIFEST_SID_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******** TFM_SP_PS ********/
+#define TFM_PROTECTED_STORAGE_SERVICE_SID                          (0x00000060U)
+#define TFM_PROTECTED_STORAGE_SERVICE_VERSION                      (1U)
+#define TFM_PROTECTED_STORAGE_SERVICE_HANDLE                       (0x40000101U)
+
+/* Invalid UID */
+#define TFM_PS_INVALID_UID 0
+
+/* PS / ITS message types that distinguish PS services. */
+#define TFM_PS_ITS_SET                1001
+#define TFM_PS_ITS_GET                1002
+#define TFM_PS_ITS_GET_INFO           1003
+#define TFM_PS_ITS_REMOVE             1004
+#define TFM_PS_ITS_GET_SUPPORT        1005
+
+/******** TFM_SP_ITS ********/
+#define TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_SID                   (0x00000070U)
+#define TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_VERSION               (1U)
+#define TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_HANDLE                (0x40000102U)
+
+/******** TFM_SP_CRYPTO ********/
+#define TFM_CRYPTO_SID                                             (0x00000080U)
+#define TFM_CRYPTO_VERSION                                         (1U)
+#define TFM_CRYPTO_HANDLE                                          (0x40000100U)
+
+/**
+ * \brief Define a progressive numerical value for each SID which can be used
+ *        when dispatching the requests to the service
+ */
+enum {
+    TFM_CRYPTO_GET_KEY_ATTRIBUTES_SID = (0u),
+    TFM_CRYPTO_RESET_KEY_ATTRIBUTES_SID,
+    TFM_CRYPTO_OPEN_KEY_SID,
+    TFM_CRYPTO_CLOSE_KEY_SID,
+    TFM_CRYPTO_IMPORT_KEY_SID,
+    TFM_CRYPTO_DESTROY_KEY_SID,
+    TFM_CRYPTO_EXPORT_KEY_SID,
+    TFM_CRYPTO_EXPORT_PUBLIC_KEY_SID,
+    TFM_CRYPTO_PURGE_KEY_SID,
+    TFM_CRYPTO_COPY_KEY_SID,
+    TFM_CRYPTO_HASH_COMPUTE_SID,
+    TFM_CRYPTO_HASH_COMPARE_SID,
+    TFM_CRYPTO_HASH_SETUP_SID,
+    TFM_CRYPTO_HASH_UPDATE_SID,
+    TFM_CRYPTO_HASH_FINISH_SID,
+    TFM_CRYPTO_HASH_VERIFY_SID,
+    TFM_CRYPTO_HASH_ABORT_SID,
+    TFM_CRYPTO_HASH_CLONE_SID,
+    TFM_CRYPTO_MAC_COMPUTE_SID,
+    TFM_CRYPTO_MAC_VERIFY_SID,
+    TFM_CRYPTO_MAC_SIGN_SETUP_SID,
+    TFM_CRYPTO_MAC_VERIFY_SETUP_SID,
+    TFM_CRYPTO_MAC_UPDATE_SID,
+    TFM_CRYPTO_MAC_SIGN_FINISH_SID,
+    TFM_CRYPTO_MAC_VERIFY_FINISH_SID,
+    TFM_CRYPTO_MAC_ABORT_SID,
+    TFM_CRYPTO_CIPHER_ENCRYPT_SID,
+    TFM_CRYPTO_CIPHER_DECRYPT_SID,
+    TFM_CRYPTO_CIPHER_ENCRYPT_SETUP_SID,
+    TFM_CRYPTO_CIPHER_DECRYPT_SETUP_SID,
+    TFM_CRYPTO_CIPHER_GENERATE_IV_SID,
+    TFM_CRYPTO_CIPHER_SET_IV_SID,
+    TFM_CRYPTO_CIPHER_UPDATE_SID,
+    TFM_CRYPTO_CIPHER_FINISH_SID,
+    TFM_CRYPTO_CIPHER_ABORT_SID,
+    TFM_CRYPTO_AEAD_ENCRYPT_SID,
+    TFM_CRYPTO_AEAD_DECRYPT_SID,
+    TFM_CRYPTO_AEAD_ENCRYPT_SETUP_SID,
+    TFM_CRYPTO_AEAD_DECRYPT_SETUP_SID,
+    TFM_CRYPTO_AEAD_GENERATE_NONCE_SID,
+    TFM_CRYPTO_AEAD_SET_NONCE_SID,
+    TFM_CRYPTO_AEAD_SET_LENGTHS_SID,
+    TFM_CRYPTO_AEAD_UPDATE_AD_SID,
+    TFM_CRYPTO_AEAD_UPDATE_SID,
+    TFM_CRYPTO_AEAD_FINISH_SID,
+    TFM_CRYPTO_AEAD_VERIFY_SID,
+    TFM_CRYPTO_AEAD_ABORT_SID,
+    TFM_CRYPTO_SIGN_MESSAGE_SID,
+    TFM_CRYPTO_VERIFY_MESSAGE_SID,
+    TFM_CRYPTO_SIGN_HASH_SID,
+    TFM_CRYPTO_VERIFY_HASH_SID,
+    TFM_CRYPTO_ASYMMETRIC_ENCRYPT_SID,
+    TFM_CRYPTO_ASYMMETRIC_DECRYPT_SID,
+    TFM_CRYPTO_KEY_DERIVATION_SETUP_SID,
+    TFM_CRYPTO_KEY_DERIVATION_GET_CAPACITY_SID,
+    TFM_CRYPTO_KEY_DERIVATION_SET_CAPACITY_SID,
+    TFM_CRYPTO_KEY_DERIVATION_INPUT_BYTES_SID,
+    TFM_CRYPTO_KEY_DERIVATION_INPUT_KEY_SID,
+    TFM_CRYPTO_KEY_DERIVATION_KEY_AGREEMENT_SID,
+    TFM_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES_SID,
+    TFM_CRYPTO_KEY_DERIVATION_OUTPUT_KEY_SID,
+    TFM_CRYPTO_KEY_DERIVATION_ABORT_SID,
+    TFM_CRYPTO_RAW_KEY_AGREEMENT_SID,
+    TFM_CRYPTO_GENERATE_RANDOM_SID,
+    TFM_CRYPTO_GENERATE_KEY_SID,
+    TFM_CRYPTO_SID_MAX,
+};
+
+/******** TFM_SP_PLATFORM ********/
+#define TFM_SP_PLATFORM_SYSTEM_RESET_SID                           (0x00000040U)
+#define TFM_SP_PLATFORM_SYSTEM_RESET_VERSION                       (1U)
+#define TFM_SP_PLATFORM_IOCTL_SID                                  (0x00000041U)
+#define TFM_SP_PLATFORM_IOCTL_VERSION                              (1U)
+#define TFM_SP_PLATFORM_NV_COUNTER_SID                             (0x00000042U)
+#define TFM_SP_PLATFORM_NV_COUNTER_VERSION                         (1U)
+
+/******** TFM_SP_INITIAL_ATTESTATION ********/
+#define TFM_ATTESTATION_SERVICE_SID                                (0x00000020U)
+#define TFM_ATTESTATION_SERVICE_VERSION                            (1U)
+#define TFM_ATTESTATION_SERVICE_HANDLE                             (0x40000103U)
+
+/* Initial Attestation message types that distinguish Attest services. */
+#define TFM_ATTEST_GET_TOKEN       1001
+#define TFM_ATTEST_GET_TOKEN_SIZE  1002
+
+/******** TFM_SP_FWU ********/
+#define TFM_FWU_WRITE_SID                                          (0x000000A0U)
+#define TFM_FWU_WRITE_VERSION                                      (1U)
+#define TFM_FWU_INSTALL_SID                                        (0x000000A1U)
+#define TFM_FWU_INSTALL_VERSION                                    (1U)
+#define TFM_FWU_ABORT_SID                                          (0x000000A2U)
+#define TFM_FWU_ABORT_VERSION                                      (1U)
+#define TFM_FWU_QUERY_SID                                          (0x000000A3U)
+#define TFM_FWU_QUERY_VERSION                                      (1U)
+#define TFM_FWU_REQUEST_REBOOT_SID                                 (0x000000A4U)
+#define TFM_FWU_REQUEST_REBOOT_VERSION                             (1U)
+#define TFM_FWU_ACCEPT_SID                                         (0x000000A5U)
+#define TFM_FWU_ACCEPT_VERSION                                     (1U)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_SID_H__ */
diff --git a/components/service/crypto/backend/psa_ipc/component.cmake b/components/service/crypto/backend/psa_ipc/component.cmake
new file mode 100644
index 0000000..1a4922f
--- /dev/null
+++ b/components/service/crypto/backend/psa_ipc/component.cmake
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/crypto_ipc_backend.c"
+	)
+
+# The ipc crypto backend uses the psa crypto client to realize the
+# psa crypto API that the crypto provider depends on.  This define
+# configures the psa crypto client to be built with the ipc crypto
+# caller.
+target_compile_definitions(${TGT} PRIVATE
+	PSA_CRYPTO_CLIENT_CALLER_SELECTION_H="service/crypto/client/caller/psa_ipc/crypto_caller.h"
+)
diff --git a/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.c b/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.c
new file mode 100644
index 0000000..6262c0c
--- /dev/null
+++ b/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <psa/crypto.h>
+#include <service/crypto/client/psa/psa_crypto_client.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include "crypto_ipc_backend.h"
+
+psa_status_t crypto_ipc_backend_init(struct rpc_caller *caller)
+{
+	psa_status_t status = psa_crypto_client_init(caller);
+
+	if (status == PSA_SUCCESS)
+		status = psa_crypto_init();
+
+	return status;
+}
+
+void crypto_ipc_backend_deinit(void)
+{
+	psa_crypto_client_deinit();
+}
diff --git a/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.h b/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.h
new file mode 100644
index 0000000..678a358
--- /dev/null
+++ b/components/service/crypto/backend/psa_ipc/crypto_ipc_backend.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRYPTO_IPC_BACKEND_H
+#define CRYPTO_IPC_BACKEND_H
+
+#include <service/crypto/client/psa/psa_crypto_client.h>
+#include <psa/error.h>
+#include <rpc_caller.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief This type is used to overcome a limitation in the number of maximum
+ *        IOVECs that can be used especially in psa_aead_encrypt and
+ *        psa_aead_decrypt. To be removed in case the AEAD APIs number of
+ *        parameters passed gets restructured
+ */
+#define TFM_CRYPTO_MAX_NONCE_LENGTH (16u)
+struct psa_ipc_crypto_aead_pack_input {
+	uint8_t nonce[TFM_CRYPTO_MAX_NONCE_LENGTH];
+	uint32_t nonce_length;
+};
+
+struct psa_ipc_crypto_pack_iovec {
+	uint32_t sfn_id;             /*!< Secure function ID used to dispatch the
+				      *   request
+				      */
+	uint16_t step;               /*!< Key derivation step */
+	psa_key_id_t key_id;         /*!< Key id */
+	psa_algorithm_t alg;         /*!< Algorithm */
+	uint32_t op_handle;          /*!< Frontend context handle associated to a
+				      *   multipart operation
+				      */
+	uint32_t capacity;             /*!< Key derivation capacity */
+	uint32_t ad_length;            /*!< Additional Data length for multipart AEAD */
+	uint32_t plaintext_length;     /*!< Plaintext length for multipart AEAD */
+	struct psa_ipc_crypto_aead_pack_input aead_in; /*!< FixMe: Temporarily used for
+							    *   AEAD until the API is
+							    *   restructured
+							    */
+};
+
+#define iov_size sizeof(struct psa_ipc_crypto_pack_iovec)
+
+/**
+ * \brief Initialize the psa ipc crypto backend
+ *
+ * Initializes a crypto backend that uses the psa API client with a
+ * psa_ipc_backend caller to realize the PSA crypto API used by the crypto
+ * service proviser.
+ *
+ * \return PSA_SUCCESS if backend initialized successfully
+ */
+psa_status_t crypto_ipc_backend_init(struct rpc_caller *caller);
+
+/**
+ * \brief Clean-up to free any resource used by the crypto backend
+ */
+void crypto_ipc_backend_deinit(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* CRYPTO_IPC_BACKEND_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller.h
new file mode 100644
index 0000000..99a5ed3
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_H
+#define PSA_IPC_CRYPTO_CALLER_H
+
+/**
+ * Includes all header files that form the psa ipc crypto caller
+ * interface.  May be used by a client that needs to call operations
+ * provided by a crypto service instance using the psa ipc interface.
+ */
+#include "crypto_caller_aead.h"
+#include "crypto_caller_asymmetric_decrypt.h"
+#include "crypto_caller_asymmetric_encrypt.h"
+#include "crypto_caller_cipher.h"
+#include "crypto_caller_copy_key.h"
+#include "crypto_caller_destroy_key.h"
+#include "crypto_caller_export_key.h"
+#include "crypto_caller_export_public_key.h"
+#include "crypto_caller_generate_key.h"
+#include "crypto_caller_generate_random.h"
+#include "crypto_caller_get_key_attributes.h"
+#include "crypto_caller_hash.h"
+#include "crypto_caller_import_key.h"
+#include "crypto_caller_key_derivation.h"
+#include "crypto_caller_mac.h"
+#include "crypto_caller_purge_key.h"
+#include "crypto_caller_sign_hash.h"
+#include "crypto_caller_verify_hash.h"
+
+#endif /* PSA_IPC_CRYPTO_CALLER_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_aead.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_aead.h
new file mode 100644
index 0000000..66a2bc9
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_aead.h
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_AEAD_H
+#define PSA_IPC_CRYPTO_CALLER_AEAD_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_aead_encrypt(
+					      struct service_client *context,
+					      psa_key_id_t key,
+					      psa_algorithm_t alg,
+					      const uint8_t *nonce,
+					      size_t nonce_length,
+					      const uint8_t *additional_data,
+					      size_t additional_data_length,
+					      const uint8_t *plaintext,
+					      size_t plaintext_length,
+					      uint8_t *aeadtext,
+					      size_t aeadtext_size,
+					      size_t *aeadtext_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	size_t in_len;
+	int i;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_ENCRYPT_SID,
+		.key_id = key,
+		.alg = alg,
+		.aead_in = { .nonce = {0}, .nonce_length = nonce_length },
+	};
+
+	if (!additional_data && additional_data_length)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(plaintext),
+			.len = plaintext_length },
+		{ .base = psa_ptr_const_to_u32(additional_data),
+			.len = additional_data_length},
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(aeadtext), .len = aeadtext_size },
+	};
+
+	if (nonce_length > TFM_CRYPTO_MAX_NONCE_LENGTH)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	if (nonce) {
+		for (i = 0; i < nonce_length; i++)
+			iov.aead_in.nonce[i] = nonce[i];
+	}
+
+	in_len = IOVEC_LEN(in_vec);
+
+	if (!additional_data)
+		in_len--;
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  in_len, out_vec, IOVEC_LEN(out_vec));
+
+	*aeadtext_length = out_vec[0].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_decrypt(
+					      struct service_client *context,
+					      psa_key_id_t key,
+					      psa_algorithm_t alg,
+					      const uint8_t *nonce,
+					      size_t nonce_length,
+					      const uint8_t *additional_data,
+					      size_t additional_data_length,
+					      const uint8_t *aeadtext,
+					      size_t aeadtext_length,
+					      uint8_t *plaintext,
+					      size_t plaintext_size,
+					      size_t *plaintext_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	size_t in_len;
+	int i;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_DECRYPT_SID,
+		.key_id = key,
+		.alg = alg,
+		.aead_in = { .nonce = {0}, .nonce_length = nonce_length },
+	};
+
+	if (!additional_data && additional_data_length)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(aeadtext),
+			.len = aeadtext_length },
+		{ .base = psa_ptr_const_to_u32(additional_data),
+			.len = additional_data_length},
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(plaintext), .len = plaintext_size },
+	};
+
+	if (nonce_length > TFM_CRYPTO_MAX_NONCE_LENGTH)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	if (nonce) {
+		for (i = 0; i < nonce_length; i++)
+			iov.aead_in.nonce[i] = nonce[i];
+	}
+
+	in_len = IOVEC_LEN(in_vec);
+
+	if (!additional_data)
+		in_len--;
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  in_len, out_vec, IOVEC_LEN(out_vec));
+
+	*plaintext_length = out_vec[0].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_encrypt_setup(
+					    struct service_client *context,
+					    uint32_t *op_handle,
+					    psa_key_id_t key,
+					    psa_algorithm_t alg)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_ENCRYPT_SETUP_SID,
+		.key_id = key,
+		.alg = alg,
+		.op_handle = (*op_handle),
+	};
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_decrypt_setup(
+					    struct service_client *context,
+					    uint32_t *op_handle,
+					    psa_key_id_t key,
+					    psa_algorithm_t alg)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_DECRYPT_SETUP_SID,
+		.key_id = key,
+		.alg = alg,
+		.op_handle = (*op_handle),
+	};
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) }
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_generate_nonce(
+					     struct service_client *context,
+					     uint32_t op_handle,
+					     uint8_t *nonce,
+					     size_t nonce_size,
+					     size_t *nonce_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_GENERATE_NONCE_SID,
+		.op_handle = op_handle,
+	};
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_to_u32(nonce), .len = nonce_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*nonce_length = out_vec[1].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_set_nonce(
+						struct service_client *context,
+						uint32_t op_handle,
+						const uint8_t *nonce,
+						size_t nonce_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_SET_NONCE_SID,
+		.op_handle = op_handle,
+	};
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+		{ .base = psa_ptr_const_to_u32(nonce), .len = nonce_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_set_lengths(
+					  struct service_client *context,
+					  uint32_t op_handle,
+					  size_t ad_length,
+					  size_t plaintext_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_SET_LENGTHS_SID,
+		.ad_length = ad_length,
+		.plaintext_length = plaintext_length,
+		.op_handle = op_handle,
+	};
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_update_ad(
+						struct service_client *context,
+						uint32_t op_handle,
+						const uint8_t *input,
+						size_t input_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_UPDATE_AD_SID,
+		.op_handle = op_handle,
+	};
+
+	/* Sanitize the optional input */
+	if ((input == NULL) && (input_length != 0)) {
+		return PSA_ERROR_INVALID_ARGUMENT;
+	}
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+		{ .base = psa_ptr_const_to_u32(input), .len = input_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	size_t in_len = IOVEC_LEN(in_vec);
+
+	if (input == NULL)
+		in_len--;
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  in_len, out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_update(
+					     struct service_client *context,
+					     uint32_t op_handle,
+					     const uint8_t *input,
+					     size_t input_length,
+					     uint8_t *output,
+					     size_t output_size,
+					     size_t *output_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_UPDATE_SID,
+		.op_handle = op_handle,
+	};
+
+	/* Sanitize the optional input */
+	if ((input == NULL) && (input_length != 0)) {
+		return PSA_ERROR_INVALID_ARGUMENT;
+	}
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+		{ .base = psa_ptr_const_to_u32(input), .len = input_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_const_to_u32(output), .len = output_size },
+	};
+
+	size_t in_len = IOVEC_LEN(in_vec);
+
+	if (input == NULL)
+		in_len--;
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  in_len, out_vec, IOVEC_LEN(out_vec));
+
+	*output_length = out_vec[1].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_finish(
+					     struct service_client *context,
+					     uint32_t op_handle,
+					     uint8_t *aeadtext,
+					     size_t aeadtext_size,
+					     size_t *aeadtext_length,
+					     uint8_t *tag,
+					     size_t tag_size,
+					     size_t *tag_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_FINISH_SID,
+		.op_handle = op_handle,
+	};
+
+	/* Sanitize the optional output */
+	if ((aeadtext == NULL) && (aeadtext_size != 0)) {
+		return PSA_ERROR_INVALID_ARGUMENT;
+	}
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_const_to_u32(tag), .len = tag_size },
+		{ .base = psa_ptr_const_to_u32(aeadtext), .len = aeadtext_size }
+	};
+
+	size_t out_len = IOVEC_LEN(out_vec);
+
+	if (aeadtext == NULL || aeadtext_size == 0)
+		out_len--;
+
+	if ((out_len == 3) && (aeadtext_length == NULL))
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, out_len);
+
+	*tag_length = out_vec[1].len;
+
+	if (out_len == 3)
+		*aeadtext_length = out_vec[2].len;
+	else
+		*aeadtext_length = 0;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_verify(
+					     struct service_client *context,
+					     uint32_t op_handle,
+					     uint8_t *plaintext,
+					     size_t plaintext_size,
+					     size_t *plaintext_length,
+					     const uint8_t *tag,
+					     size_t tag_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_VERIFY_SID,
+		.op_handle = op_handle,
+	};
+
+	/* Sanitize the optional output */
+	if ((plaintext == NULL) && (plaintext_size != 0))
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+		{ .base = psa_ptr_const_to_u32(tag), .len = tag_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_const_to_u32(plaintext),
+			.len = plaintext_size },
+	};
+
+	size_t out_len = IOVEC_LEN(out_vec);
+
+	if (plaintext == NULL || plaintext_size == 0)
+		out_len--;
+
+	if ((out_len == 2) && (plaintext_length == NULL))
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, out_len);
+
+	if (out_len == 2)
+		*plaintext_length = out_vec[1].len;
+	else
+		*plaintext_length = 0;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_aead_abort(
+					    struct service_client *context,
+					    uint32_t op_handle)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_AEAD_ABORT_SID,
+		.op_handle = op_handle,
+	};
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov),
+			.len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline size_t crypto_caller_aead_max_update_size(
+					const struct service_client *context)
+{
+       /* Returns the maximum number of bytes that may be
+        * carried as a parameter of the mac_update operation
+        *  using the packed-c encoding.
+        */
+       size_t payload_space = context->service_info.max_payload;
+       size_t overhead = iov_size;
+
+       return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+static inline size_t crypto_caller_aead_max_update_ad_size(
+					   const struct service_client *context)
+{
+	/* Returns the maximum number of bytes that may be
+	 * carried as a parameter of the mac_update operation
+	 *  using the packed-c encoding.
+	 */
+	size_t payload_space = context->service_info.max_payload;
+	size_t overhead = iov_size;
+
+	return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_AEAD_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_decrypt.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_decrypt.h
new file mode 100644
index 0000000..d3e43b2
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_decrypt.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_DECRYPT_H
+#define PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_DECRYPT_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_asymmetric_decrypt(
+				    struct service_client *context,
+				    psa_key_id_t id,
+				    psa_algorithm_t alg,
+				    const uint8_t *input, size_t input_length,
+				    const uint8_t *salt, size_t salt_length,
+				    uint8_t *output, size_t output_size,
+				    size_t *output_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	size_t in_len;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_ASYMMETRIC_DECRYPT_SID,
+		.key_id = id,
+		.alg = alg,
+	};
+
+	/* Sanitize optional input */
+	if (!salt && salt_length)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(input), .len = input_length },
+		{ .base = psa_ptr_const_to_u32(salt), .len = salt_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(output), .len = output_size },
+	};
+
+
+	in_len = IOVEC_LEN(in_vec);
+	if (!salt)
+		in_len--;
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  in_len, out_vec, IOVEC_LEN(out_vec));
+
+	*output_length = out_vec[0].len;
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_DECRYPT_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_encrypt.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_encrypt.h
new file mode 100644
index 0000000..124b088
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_asymmetric_encrypt.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_ENCRYPT_H
+#define PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_ENCRYPT_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_asymmetric_encrypt(
+				    struct service_client *context,
+				    psa_key_id_t id,
+				    psa_algorithm_t alg,
+				    const uint8_t *input, size_t input_length,
+				    const uint8_t *salt, size_t salt_length,
+				    uint8_t *output, size_t output_size,
+				    size_t *output_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	size_t in_len;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_ASYMMETRIC_ENCRYPT_SID,
+		.key_id = id,
+		.alg = alg,
+	};
+
+	/* Sanitize optional input */
+	if (!salt && salt_length)
+		return PSA_ERROR_INVALID_ARGUMENT;
+
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(input), .len = input_length },
+		{ .base = psa_ptr_const_to_u32(salt), .len = salt_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(output), .len = output_size },
+	};
+
+
+	in_len = IOVEC_LEN(in_vec);
+	if (!salt)
+		in_len--;
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  in_len, out_vec, IOVEC_LEN(out_vec));
+
+	*output_length = out_vec[0].len;
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_ASYMMETRIC_ENCRYPT_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_cipher.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_cipher.h
new file mode 100644
index 0000000..8d906ae
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_cipher.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_CIPHER_H
+#define PSA_IPC_CRYPTO_CALLER_CIPHER_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_cipher_encrypt_setup(
+					      struct service_client *context,
+					      uint32_t *op_handle,
+					      psa_key_id_t key,
+					      psa_algorithm_t alg)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_CIPHER_ENCRYPT_SETUP_SID,
+		.key_id = key,
+		.alg = alg,
+		.op_handle = *op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_decrypt_setup(
+					      struct service_client *context,
+					      uint32_t *op_handle,
+					      psa_key_id_t key,
+					      psa_algorithm_t alg)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_CIPHER_DECRYPT_SETUP_SID,
+		.key_id = key,
+		.alg = alg,
+		.op_handle = *op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_generate_iv(
+					    struct service_client *context,
+					    uint32_t op_handle,
+					    uint8_t *iv,
+					    size_t iv_size,
+					    size_t *iv_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_CIPHER_GENERATE_IV_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_to_u32(iv), .len = iv_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*iv_length = out_vec[1].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_set_iv(
+					       struct service_client *context,
+					       uint32_t op_handle,
+					       const uint8_t *iv,
+					       size_t iv_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_CIPHER_SET_IV_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(iv), .len = iv_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_update(
+					       struct service_client *context,
+					       uint32_t op_handle,
+					       const uint8_t *input,
+					       size_t input_length,
+					       uint8_t *output,
+					       size_t output_size,
+					       size_t *output_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_CIPHER_UPDATE_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(input), .len = input_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_to_u32(output), .len = output_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*output_length = out_vec[1].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_finish(
+					       struct service_client *context,
+					       uint32_t op_handle,
+					       uint8_t *output,
+					       size_t output_size,
+					       size_t *output_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_CIPHER_FINISH_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_to_u32(output), .len = output_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*output_length = out_vec[1].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_cipher_abort(
+					      struct service_client *context,
+					      uint32_t op_handle)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_CIPHER_ABORT_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline size_t crypto_caller_cipher_max_update_size(const struct service_client *context)
+{
+	/* Returns the maximum number of bytes that may be
+	 * carried as a parameter of the cipher_update operation
+	 * using the ipc encoding.
+	 */
+	size_t payload_space = context->service_info.max_payload;
+	size_t overhead = iov_size;
+
+	/* Allow for output to be a whole number of blocks */
+	overhead += PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE;
+
+	return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_CIPHER_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_copy_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_copy_key.h
new file mode 100644
index 0000000..b2e57e1
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_copy_key.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_COPY_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_COPY_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_copy_key(struct service_client *context,
+						  psa_key_id_t source_key,
+						  const psa_key_attributes_t *attributes,
+						  psa_key_id_t *target_key)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_COPY_KEY_SID,
+		.key_id = source_key,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+		{ .base = psa_ptr_const_to_u32(attributes), .len = sizeof(psa_key_attributes_t) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(target_key), .len = sizeof(psa_key_id_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_COPY_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_destroy_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_destroy_key.h
new file mode 100644
index 0000000..94a0158
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_destroy_key.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_DESTROY_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_DESTROY_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_destroy_key(struct service_client *context,
+						     psa_key_id_t id)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_DESTROY_KEY_SID,
+		.key_id = id,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), NULL, 0);
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_DESTROY_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_key.h
new file mode 100644
index 0000000..b6dfda3
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_key.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021-2023 Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_EXPORT_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_EXPORT_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_export_key(struct service_client *context,
+						    psa_key_id_t id,
+						    uint8_t *data,
+						    size_t data_size,
+						    size_t *data_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_EXPORT_KEY_SID,
+		.key_id = id,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(data), .len = data_size }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*data_length = out_vec[0].len;
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_EXPORT_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_public_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_public_key.h
new file mode 100644
index 0000000..d154db8
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_export_public_key.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_EXPORT_PUBLIC_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_EXPORT_PUBLIC_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_export_public_key(struct service_client *context,
+							   psa_key_id_t id,
+							   uint8_t *data,
+							   size_t data_size,
+							   size_t *data_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_EXPORT_PUBLIC_KEY_SID,
+		.key_id = id,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(data), .len = data_size }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*data_length = out_vec[0].len;
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_EXPORT_PUBLIC_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_key.h
new file mode 100644
index 0000000..41dc3a1
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_key.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_GENERATE_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_GENERATE_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_generate_key(struct service_client *context,
+						      const psa_key_attributes_t *attributes,
+						      psa_key_id_t *id)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_GENERATE_KEY_SID,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+		{ .base = psa_ptr_const_to_u32(attributes), .len = sizeof(psa_key_attributes_t) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(id), .len = sizeof(psa_key_id_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_GENERATE_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_random.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_random.h
new file mode 100644
index 0000000..5043732
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_generate_random.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_GENERATE_RANDOM_H
+#define PSA_IPC_CRYPTO_CALLER_GENERATE_RANDOM_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_generate_random(struct service_client *context,
+							 uint8_t *output,
+							 size_t output_size)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_GENERATE_RANDOM_SID,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(output), .len = output_size }
+	};
+
+	if (!output_size)
+		return PSA_SUCCESS;
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_GENERATE_RANDOM_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_get_key_attributes.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_get_key_attributes.h
new file mode 100644
index 0000000..3531bd0
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_get_key_attributes.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_GET_KEY_ATTRIBUTES_H
+#define PSA_IPC_CRYPTO_CALLER_GET_KEY_ATTRIBUTES_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_get_key_attributes(
+					    struct service_client *context,
+					    psa_key_id_t key,
+					    psa_key_attributes_t *attributes)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_GET_KEY_ATTRIBUTES_SID,
+		.key_id = key,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(attributes), .len = sizeof(psa_key_attributes_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_GET_KEY_ATTRIBUTES_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_hash.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_hash.h
new file mode 100644
index 0000000..f63e981
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_hash.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_HASH_H
+#define PSA_IPC_CRYPTO_CALLER_HASH_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_hash_setup(
+					    struct service_client *context,
+					    uint32_t *op_handle,
+					    psa_algorithm_t alg)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_HASH_SETUP_SID,
+		.alg = alg,
+		.op_handle = *op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_hash_update(
+					     struct service_client *context,
+					     uint32_t op_handle,
+					     const uint8_t *input,
+					     size_t input_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_HASH_UPDATE_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(input), .len = input_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_hash_finish(
+					     struct service_client *context,
+					     uint32_t op_handle,
+					     uint8_t *hash,
+					     size_t hash_size,
+					     size_t *hash_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_HASH_FINISH_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_to_u32(hash), .len = hash_size},
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*hash_length = out_vec[1].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_hash_abort(
+					    struct service_client *context,
+					    uint32_t op_handle)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_HASH_ABORT_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_hash_verify(
+					     struct service_client *context,
+					     uint32_t op_handle,
+					     const uint8_t *hash,
+					     size_t hash_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_HASH_VERIFY_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(hash), .len = hash_length},
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_hash_clone(
+					    struct service_client *context,
+					    uint32_t source_op_handle,
+					    uint32_t *target_op_handle)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_HASH_CLONE_SID,
+		.op_handle = source_op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(target_op_handle),
+			.len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_hash_suspend(struct service_client *context,
+	uint32_t op_handle,
+	uint8_t *hash_state,
+	size_t hash_state_size,
+	size_t *hash_state_length)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static inline psa_status_t crypto_caller_hash_resume(struct service_client *context,
+	uint32_t op_handle,
+	const uint8_t *hash_state,
+	size_t hash_state_length)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static inline size_t crypto_caller_hash_max_update_size(const struct service_client *context)
+{
+	/* Returns the maximum number of bytes that may be
+	 * carried as a parameter of the hash_update operation
+	 * using the packed-c encoding.
+	 */
+	size_t payload_space = context->service_info.max_payload;
+	size_t overhead = iov_size;
+
+	return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_HASH_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_import_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_import_key.h
new file mode 100644
index 0000000..72a43c4
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_import_key.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_IMPORT_KEY_H
+#define PSA_IPC_CRYPTO_CALLER_IMPORT_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_import_key(struct service_client *context,
+				    const psa_key_attributes_t *attributes,
+				    const uint8_t *data, size_t data_length,
+				    psa_key_id_t *id)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_IMPORT_KEY_SID,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+		{ .base = psa_ptr_const_to_u32(attributes), .len = sizeof(psa_key_attributes_t) },
+		{ .base = psa_ptr_const_to_u32(data), .len = data_length }
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(id), .len = sizeof(psa_key_id_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PACKEDC_CRYPTO_CALLER_IMPORT_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_attributes.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_attributes.h
new file mode 100644
index 0000000..c3b9b46
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_attributes.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_CRYPTO_CALLER_KEY_ATTRIBUTES_H
+#define PACKEDC_CRYPTO_CALLER_KEY_ATTRIBUTES_H
+
+#include <psa/crypto.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline void packedc_crypto_caller_translate_key_attributes_to_proto(
+	struct ts_crypto_key_attributes *proto_attributes,
+	const psa_key_attributes_t *psa_attributes)
+{
+	proto_attributes->type = psa_get_key_type(psa_attributes);
+	proto_attributes->key_bits = psa_get_key_bits(psa_attributes);
+	proto_attributes->lifetime = psa_get_key_lifetime(psa_attributes);
+	proto_attributes->id = psa_get_key_id(psa_attributes);
+
+	proto_attributes->policy.usage = psa_get_key_usage_flags(psa_attributes);
+	proto_attributes->policy.alg = psa_get_key_algorithm(psa_attributes);
+ }
+
+static inline void packedc_crypto_caller_translate_key_attributes_from_proto(
+	psa_key_attributes_t *psa_attributes,
+	const struct ts_crypto_key_attributes *proto_attributes)
+{
+	psa_set_key_type(psa_attributes, proto_attributes->type);
+	psa_set_key_bits(psa_attributes, proto_attributes->key_bits);
+	psa_set_key_lifetime(psa_attributes, proto_attributes->lifetime);
+
+	if (proto_attributes->lifetime == PSA_KEY_LIFETIME_PERSISTENT) {
+
+		psa_set_key_id(psa_attributes, proto_attributes->id);
+	}
+
+	psa_set_key_usage_flags(psa_attributes, proto_attributes->policy.usage);
+	psa_set_key_algorithm(psa_attributes, proto_attributes->policy.alg);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PACKEDC_CRYPTO_CALLER_KEY_ATTRIBUTES_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_derivation.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_derivation.h
new file mode 100644
index 0000000..cacadf0
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_key_derivation.h
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_KEY_DERIVATION_H
+#define PSA_IPC_CRYPTO_CALLER_KEY_DERIVATION_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_key_derivation_setup(
+					      struct service_client *context,
+					      uint32_t *op_handle,
+					      psa_algorithm_t alg)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_KEY_DERIVATION_SETUP_SID,
+		.alg = alg,
+		.op_handle = *op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_get_capacity(
+					     struct service_client *context,
+					     const uint32_t op_handle,
+					     size_t *capacity)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_KEY_DERIVATION_GET_CAPACITY_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(capacity), .len = sizeof(uint32_t) }
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_set_capacity(
+					     struct service_client *context,
+					     uint32_t op_handle,
+					     size_t capacity)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_KEY_DERIVATION_SET_CAPACITY_SID,
+		.capacity = capacity,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), NULL, 0);
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_input_bytes(
+					    struct service_client *context,
+					    uint32_t op_handle,
+					    psa_key_derivation_step_t step,
+					    const uint8_t *data,
+					    size_t data_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_KEY_DERIVATION_INPUT_BYTES_SID,
+		.step = step,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(data), .len = data_length },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), NULL, 0);
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_input_key(
+					  struct service_client *context,
+					  uint32_t op_handle,
+					  psa_key_derivation_step_t step,
+					  psa_key_id_t key)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_KEY_DERIVATION_INPUT_KEY_SID,
+		.key_id = key,
+		.step = step,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), NULL, 0);
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_output_bytes(
+					     struct service_client *context,
+					     uint32_t op_handle,
+					     uint8_t *output,
+					     size_t output_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_KEY_DERIVATION_OUTPUT_BYTES_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(output), .len = output_length },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_output_key(
+				   struct service_client *context,
+				   const psa_key_attributes_t *attributes,
+				   uint32_t op_handle,
+				   psa_key_id_t *key)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_KEY_DERIVATION_OUTPUT_KEY_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(attributes),
+			.len = sizeof(psa_key_attributes_t) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(key), .len = sizeof(psa_key_id_t)},
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_abort(
+					      struct service_client *context,
+					      uint32_t op_handle)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_KEY_DERIVATION_ABORT_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_key_derivation_key_agreement(
+				      struct service_client *context,
+				      uint32_t op_handle,
+				      psa_key_derivation_step_t step,
+				      psa_key_id_t private_key,
+				      const uint8_t *peer_key,
+				      size_t peer_key_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_KEY_DERIVATION_KEY_AGREEMENT_SID,
+		.key_id = private_key,
+		.step = step,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(peer_key),
+			.len = peer_key_length},
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), NULL, 0);
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_raw_key_agreement(
+					   struct service_client *context,
+					   psa_algorithm_t alg,
+					   psa_key_id_t private_key,
+					   const uint8_t *peer_key,
+					   size_t peer_key_length,
+					   uint8_t *output,
+					   size_t output_size,
+					   size_t *output_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_RAW_KEY_AGREEMENT_SID,
+		.alg = alg,
+		.key_id = private_key,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(peer_key),
+			.len = peer_key_length},
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(output), .len = output_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*output_length = out_vec[0].len;
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_KEY_DERIVATION_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_mac.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_mac.h
new file mode 100644
index 0000000..a0092bf
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_mac.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_MAC_H
+#define PSA_IPC_CRYPTO_CALLER_MAC_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_mac_sign_setup(
+						struct service_client *context,
+						uint32_t *op_handle,
+						psa_key_id_t key,
+						psa_algorithm_t alg)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_MAC_SIGN_SETUP_SID,
+		.key_id = key,
+		.alg = alg,
+		.op_handle = *op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_mac_verify_setup(
+					  struct service_client *context,
+					  uint32_t *op_handle,
+					  psa_key_id_t key,
+					  psa_algorithm_t alg)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_MAC_VERIFY_SETUP_SID,
+		.key_id = key,
+		.alg = alg,
+		.op_handle = *op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_mac_update(
+					    struct service_client *context,
+					    uint32_t op_handle,
+					    const uint8_t *input,
+					    size_t input_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_MAC_UPDATE_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(input), .len = input_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_mac_sign_finish(
+						 struct service_client *context,
+						 uint32_t op_handle,
+						 uint8_t *mac,
+						 size_t mac_size,
+						 size_t *mac_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_MAC_SIGN_FINISH_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+		{ .base = psa_ptr_to_u32(mac), .len = mac_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*mac_length = out_vec[1].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_mac_verify_finish(
+					   struct service_client *context,
+					   uint32_t op_handle,
+					   const uint8_t *mac,
+					   size_t mac_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_MAC_VERIFY_FINISH_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(mac), .len = mac_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_mac_abort(
+					   struct service_client *context,
+					   uint32_t op_handle)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_MAC_ABORT_SID,
+		.op_handle = op_handle,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&op_handle), .len = sizeof(uint32_t) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	return status;
+}
+
+static inline size_t crypto_caller_mac_max_update_size(const struct service_client *context)
+{
+	/* Returns the maximum number of bytes that may be
+	 * carried as a parameter of the mac_update operation
+	 * using the packed-c encoding.
+	 */
+	size_t payload_space = context->service_info.max_payload;
+	size_t overhead = iov_size;
+
+	return (payload_space > overhead) ? payload_space - overhead : 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_MAC_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_purge_key.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_purge_key.h
new file mode 100644
index 0000000..36a0176
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_purge_key.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_CRYPTO_CALLER_PURGE_KEY_H
+#define PACKEDC_CRYPTO_CALLER_PURGE_KEY_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_purge_key(struct service_client *context,
+						   psa_key_id_t id)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_PURGE_KEY_SID,
+		.key_id = id,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), NULL, 0);
+
+	return status;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PACKEDC_CRYPTO_CALLER_PURGE_KEY_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_sign_hash.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_sign_hash.h
new file mode 100644
index 0000000..29bd56e
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_sign_hash.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_SIGN_HASH_H
+#define PSA_IPC_CRYPTO_CALLER_SIGN_HASH_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_sign_hash(struct service_client *context,
+						   psa_key_id_t id,
+						   psa_algorithm_t alg,
+						   const uint8_t *hash,
+						   size_t hash_length,
+						   uint8_t *signature,
+						   size_t signature_size,
+						   size_t *signature_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_SIGN_HASH_SID,
+		.key_id = id,
+		.alg = alg,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(hash), .len = hash_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(signature), .len = signature_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*signature_length = out_vec[0].len;
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_sign_message(struct service_client *context,
+						   psa_key_id_t id,
+						   psa_algorithm_t alg,
+						   const uint8_t *hash,
+						   size_t hash_length,
+						   uint8_t *signature,
+						   size_t signature_size,
+						   size_t *signature_length)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = TFM_CRYPTO_SIGN_MESSAGE_SID,
+		.key_id = id,
+		.alg = alg,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = iov_size },
+		{ .base = psa_ptr_const_to_u32(hash), .len = hash_length },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(signature), .len = signature_size },
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
+
+	*signature_length = out_vec[0].len;
+
+	return status;
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_SIGN_HASH_H */
diff --git a/components/service/crypto/client/caller/psa_ipc/crypto_caller_verify_hash.h b/components/service/crypto/client/caller/psa_ipc/crypto_caller_verify_hash.h
new file mode 100644
index 0000000..66281d5
--- /dev/null
+++ b/components/service/crypto/client/caller/psa_ipc/crypto_caller_verify_hash.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PSA_IPC_CRYPTO_CALLER_VERIFY_HASH_H
+#define PSA_IPC_CRYPTO_CALLER_VERIFY_HASH_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <psa/crypto.h>
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <service/common/client/service_client.h>
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include "crypto_caller_key_attributes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static inline psa_status_t crypto_caller_common(struct service_client *context,
+						     psa_key_id_t id,
+						     psa_algorithm_t alg,
+						     const uint8_t *hash,
+						     size_t hash_length,
+						     const uint8_t *signature,
+						     size_t signature_length,
+						     uint32_t sfn_id)
+{
+	struct service_client *ipc = context;
+	struct rpc_caller *caller = ipc->caller;
+	psa_status_t status;
+	struct psa_ipc_crypto_pack_iovec iov = {
+		.sfn_id = sfn_id,
+		.key_id = id,
+		.alg = alg,
+	};
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&iov), .len = sizeof(struct psa_ipc_crypto_pack_iovec) },
+		{ .base = psa_ptr_const_to_u32(hash), .len = hash_length },
+		{ .base = psa_ptr_const_to_u32(signature), .len = signature_length},
+	};
+
+	status = psa_call(caller, TFM_CRYPTO_HANDLE, PSA_IPC_CALL, in_vec,
+			  IOVEC_LEN(in_vec), NULL, 0);
+
+	return status;
+}
+
+static inline psa_status_t crypto_caller_verify_hash(struct service_client *context,
+						     psa_key_id_t id,
+						     psa_algorithm_t alg,
+						     const uint8_t *hash,
+						     size_t hash_length,
+						     const uint8_t *signature,
+						     size_t signature_length)
+{
+
+	return crypto_caller_common(context,id,alg,hash,hash_length,
+			signature,signature_length, TFM_CRYPTO_VERIFY_HASH_SID);
+}
+
+static inline psa_status_t crypto_caller_verify_message(struct service_client *context,
+						     psa_key_id_t id,
+						     psa_algorithm_t alg,
+						     const uint8_t *hash,
+						     size_t hash_length,
+						     const uint8_t *signature,
+						     size_t signature_length)
+{
+
+	return crypto_caller_common(context,id,alg,hash,hash_length,
+			signature,signature_length, TFM_CRYPTO_VERIFY_MESSAGE_SID);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_IPC_CRYPTO_CALLER_VERIFY_HASH_H */
diff --git a/components/service/crypto/include/psa/crypto_client_struct.h b/components/service/crypto/include/psa/crypto_client_struct.h
index abd420c..1f68aba 100644
--- a/components/service/crypto/include/psa/crypto_client_struct.h
+++ b/components/service/crypto/include/psa/crypto_client_struct.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -31,12 +31,12 @@
  * data structure internally. */
 struct psa_client_key_attributes_s
 {
-    uint32_t lifetime;
-    uint32_t id;
-    uint32_t alg;
-    uint32_t usage;
-    size_t bits;
     uint16_t type;
+    uint16_t bits;
+    uint32_t lifetime;
+    psa_key_id_t id;
+    uint32_t usage;
+    uint32_t alg;
 };
 
 #define PSA_CLIENT_KEY_ATTRIBUTES_INIT {0, 0, 0, 0, 0, 0}
diff --git a/components/service/crypto/include/psa/crypto_sizes.h b/components/service/crypto/include/psa/crypto_sizes.h
index 7a0149b..30aa102 100644
--- a/components/service/crypto/include/psa/crypto_sizes.h
+++ b/components/service/crypto/include/psa/crypto_sizes.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -81,7 +81,7 @@
 #define PSA_HASH_MAX_SIZE 64
 #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 128
 #else
-#define PSA_HASH_MAX_SIZE 32
+#define PSA_HASH_MAX_SIZE 64
 #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 64
 #endif
 
diff --git a/components/service/crypto/include/psa/crypto_struct.h b/components/service/crypto/include/psa/crypto_struct.h
index 1bc55e3..97cdf55 100644
--- a/components/service/crypto/include/psa/crypto_struct.h
+++ b/components/service/crypto/include/psa/crypto_struct.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -155,9 +155,19 @@
     return( attributes->lifetime );
 }
 
+static inline void psa_extend_key_usage_flags( psa_key_usage_t *usage_flags )
+{
+    if( *usage_flags & PSA_KEY_USAGE_SIGN_HASH )
+        *usage_flags |= PSA_KEY_USAGE_SIGN_MESSAGE;
+
+    if( *usage_flags & PSA_KEY_USAGE_VERIFY_HASH )
+        *usage_flags |= PSA_KEY_USAGE_VERIFY_MESSAGE;
+}
+
 static inline void psa_set_key_usage_flags(psa_key_attributes_t *attributes,
                                            psa_key_usage_t usage_flags)
 {
+    psa_extend_key_usage_flags( &usage_flags );
     attributes->usage = usage_flags;
 }
 
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/component.cmake b/components/service/secure_storage/backend/secure_storage_ipc/component.cmake
new file mode 100644
index 0000000..5d8f671
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_storage_ipc/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/secure_storage_ipc.c"
+	)
+
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
new file mode 100644
index 0000000..0609326
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <protocols/rpc/common/packed-c/status.h>
+#include "secure_storage_ipc.h"
+#include <psa/client.h>
+#include <psa/sid.h>
+#include <rpc_caller.h>
+#include <string.h>
+#include <trace.h>
+
+
+static psa_status_t secure_storage_ipc_set(void *context, uint32_t client_id,
+			 psa_storage_uid_t uid, size_t data_length,
+			 const void *p_data, psa_storage_create_flags_t create_flags)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_status_t psa_status;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
+		{ .base = psa_ptr_const_to_u32(p_data), .len = data_length },
+		{ .base = psa_ptr_to_u32(&create_flags), .len = sizeof(create_flags) },
+	};
+
+	ipc->client.rpc_status = TS_RPC_CALL_ACCEPTED;
+
+	psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+					TFM_PS_ITS_SET, in_vec,
+					IOVEC_LEN(in_vec), NULL, 0);
+	if (psa_status < 0)
+		EMSG("ipc_set: psa_call failed: %d", psa_status);
+
+	return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_get(void *context,
+					   uint32_t client_id,
+					   psa_storage_uid_t uid,
+					   size_t data_offset,
+					   size_t data_size,
+					   void *p_data,
+					   size_t *p_data_length)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_status_t psa_status;
+	uint32_t offset = (uint32_t)data_offset;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
+		{ .base = psa_ptr_to_u32(&offset), .len = sizeof(offset) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(p_data), .len = data_size },
+	};
+
+	if (!p_data_length) {
+		EMSG("ipc_get: p_data_length not defined");
+		return PSA_ERROR_INVALID_ARGUMENT;
+	}
+
+	psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+					TFM_PS_ITS_GET, in_vec,
+					IOVEC_LEN(in_vec), out_vec,
+					IOVEC_LEN(out_vec));
+	if (psa_status == PSA_SUCCESS)
+		*p_data_length = out_vec[0].len;
+
+	return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_get_info(void *context,
+						uint32_t client_id,
+						psa_storage_uid_t uid,
+						struct psa_storage_info_t *p_info)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_status_t psa_status;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
+	};
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(p_info), .len = sizeof(*p_info) },
+	};
+
+	psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+					TFM_PS_ITS_GET_INFO, in_vec,
+					IOVEC_LEN(in_vec), out_vec,
+					IOVEC_LEN(out_vec));
+	if (psa_status != PSA_SUCCESS)
+		EMSG("ipc_get_info: failed to psa_call: %d", psa_status);
+
+	return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_remove(void *context,
+						uint32_t client_id,
+						psa_storage_uid_t uid)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_status_t psa_status;
+	struct psa_invec in_vec[] = {
+		{ .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
+	};
+
+	psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+					TFM_PS_ITS_REMOVE, in_vec,
+					IOVEC_LEN(in_vec), NULL, 0);
+	if (psa_status != PSA_SUCCESS)
+		EMSG("ipc_remove: failed to psa_call: %d", psa_status);
+
+	return psa_status;
+}
+
+static psa_status_t secure_storage_ipc_create(void *context,
+					      uint32_t client_id,
+					      uint64_t uid,
+					      size_t capacity,
+					      uint32_t create_flags)
+{
+	(void)context;
+	(void)uid;
+	(void)client_id;
+	(void)capacity;
+	(void)create_flags;
+
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static psa_status_t secure_storage_set_extended(void *context,
+						uint32_t client_id,
+						uint64_t uid,
+						size_t data_offset,
+						size_t data_length,
+						const void *p_data)
+{
+	(void)context;
+	(void)uid;
+	(void)client_id;
+	(void)data_offset;
+	(void)data_length;
+	(void)p_data;
+
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+static uint32_t secure_storage_get_support(void *context, uint32_t client_id)
+{
+	struct secure_storage_ipc *ipc = context;
+	struct rpc_caller *caller = ipc->client.caller;
+	psa_status_t psa_status;
+	uint32_t support_flags;
+	struct psa_outvec out_vec[] = {
+		{ .base = psa_ptr_to_u32(&support_flags), .len =  sizeof(support_flags) },
+	};
+
+	psa_status = psa_call_client_id(caller, ipc->service_handle, client_id,
+					TFM_PS_ITS_GET_SUPPORT, NULL, 0,
+					out_vec, IOVEC_LEN(out_vec));
+	if (psa_status != PSA_SUCCESS)
+		EMSG("ipc_get_support: failed to psa_call: %d", psa_status);
+
+	return psa_status;
+}
+
+struct storage_backend *secure_storage_ipc_init(struct secure_storage_ipc *context,
+						struct rpc_caller *caller)
+{
+	service_client_init(&context->client, caller);
+
+	static const struct storage_backend_interface interface =
+	{
+		.set = secure_storage_ipc_set,
+		.get = secure_storage_ipc_get,
+		.get_info = secure_storage_ipc_get_info,
+		.remove = secure_storage_ipc_remove,
+		.create = secure_storage_ipc_create,
+		.set_extended = secure_storage_set_extended,
+		.get_support = secure_storage_get_support,
+	};
+
+	context->backend.context = context;
+	context->backend.interface = &interface;
+
+	return &context->backend;
+}
+
+void secure_storage_ipc_deinit(struct secure_storage_ipc *context)
+{
+	service_client_deinit(&context->client);
+}
diff --git a/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h
new file mode 100644
index 0000000..6bb47ac
--- /dev/null
+++ b/components/service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SECURE_STORAGE_IPC_H
+#define SECURE_STORAGE_IPC_H
+
+#include <service/secure_storage/backend/storage_backend.h>
+#include <service/common/client/service_client.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief      Secure storage ipc instance
+ */
+struct secure_storage_ipc
+{
+    struct storage_backend backend;
+    struct service_client client;
+    int32_t service_handle;
+};
+
+/**
+ * @brief      Initialize a secure storage ipc client
+ *
+ * A secure storage client is a storage backend that makes RPC calls
+ * to a remote secure storage provider.
+ *
+ * @param[in]  context    Instance data
+ * @param[in]  rpc_caller RPC caller instance
+ *
+ *
+ * @return     Pointer to inialized storage backend or NULL on failure
+ */
+struct storage_backend *secure_storage_ipc_init(struct secure_storage_ipc *context,
+						struct rpc_caller *caller);
+
+/**
+ * @brief      Deinitialize a secure storage ipc client
+ *
+ * @param[in]  context   Instance data
+ */
+void secure_storage_ipc_deinit(struct secure_storage_ipc *context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SECURE_STORAGE_IPC_H */
diff --git a/components/service/secure_storage/include/psa/storage_common.h b/components/service/secure_storage/include/psa/storage_common.h
index 4f6ba2a..3176545 100644
--- a/components/service/secure_storage/include/psa/storage_common.h
+++ b/components/service/secure_storage/include/psa/storage_common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -20,8 +20,8 @@
 typedef uint32_t psa_storage_create_flags_t;
 
 struct psa_storage_info_t {
-	size_t capacity;
-	size_t size;
+	uint32_t capacity;
+	uint32_t size;
 	psa_storage_create_flags_t flags;
 };
 
diff --git a/components/service/smm_variable/backend/uefi_variable_store.c b/components/service/smm_variable/backend/uefi_variable_store.c
index 611e2e2..de85bc5 100644
--- a/components/service/smm_variable/backend/uefi_variable_store.c
+++ b/components/service/smm_variable/backend/uefi_variable_store.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -200,10 +200,15 @@
 		/* Access permitted */
 		if (info->is_variable_set) {
 
-			/* It's a request to update to an existing variable */
-			if (!(var->Attributes &
+			/*
+			 * It's a request to update to an existing variable,
+			 * note that a variable without attributes means a
+			 * delete variable request, similar to how EDK-2
+			 * and EDK-2 test cases handle this.
+			 */
+			if (!(var->Attributes) || (!(var->Attributes &
 				(EFI_VARIABLE_APPEND_WRITE | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS_MASK)) &&
-				!var->DataSize) {
+				!var->DataSize)) {
 
 				/* It's a remove operation - for a remove, the variable
 				 * data must be removed from the storage backend before
diff --git a/deployments/se-proxy/config/corstone-1000-opteesp/CMakeLists.txt b/deployments/se-proxy/config/corstone-1000-opteesp/CMakeLists.txt
new file mode 100644
index 0000000..4e26c53
--- /dev/null
+++ b/deployments/se-proxy/config/corstone-1000-opteesp/CMakeLists.txt
@@ -0,0 +1,96 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+
+# Set default platform.
+set(TS_PLATFORM "arm/corstone1000" CACHE STRING "Target platform location.")
+include(../../../deployment.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+#  The CMakeLists.txt for building the se-proxy deployment for Corstone-1000
+#  using the "opteesp" environment.
+#
+#-------------------------------------------------------------------------------
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+project(trusted-services LANGUAGES C ASM)
+add_executable(se-proxy)
+target_include_directories(se-proxy PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+set(SP_UUID_CANON "46bb39d1-b4d9-45b5-88ff-040027dab249")
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "SEPROXY" CACHE STRING "Trace prefix")
+include(${TS_ROOT}/tools/cmake/common/TargetCompileDefinitions.cmake)
+set_target_uuids(
+	SP_UUID ${SP_UUID_CANON}
+	SP_NAME "se-proxy"
+)
+
+target_include_directories(se-proxy PRIVATE
+	${CMAKE_CURRENT_LIST_DIR}
+)
+
+#-------------------------------------------------------------------------------
+#  Components that are specific to deployment in the opteesp environment.
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "se-proxy"
+	BASE_DIR ${TS_ROOT}
+	COMPONENTS
+		"environments/opteesp"
+)
+
+include(../../env/commonsp/se_proxy_sp.cmake REQUIRED)
+include(../../infra/corstone-1000/infra.cmake REQUIRED)
+include(../../se-proxy.cmake REQUIRED)
+
+#-------------------------------------------------------------------------------
+#  Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET "se-proxy")
+
+#-------------------------------------------------------------------------------
+#  Deployment specific build options
+#-------------------------------------------------------------------------------
+target_compile_definitions(se-proxy PRIVATE
+	ARM64=1
+)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+	target_compile_options(se-proxy PRIVATE
+		-std=c99
+	)
+
+endif()
+
+compiler_generate_stripped_elf(TARGET se-proxy NAME "${SP_UUID_CANON}.stripped.elf" RES STRIPPED_ELF)
+
+#-------------------------------------------------------------------------------
+#  Deployment specific install options
+#-------------------------------------------------------------------------------
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+	set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+#TODO: api headers
+
+install(TARGETS se-proxy
+			PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+			RUNTIME DESTINATION ${TS_ENV}/bin
+		)
+install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
+
+get_property(_PROTO_FILES TARGET se-proxy PROPERTY PROTOBUF_FILES)
+install(FILES ${_PROTO_FILES} DESTINATION ${TS_ENV}/lib/protobuf)
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+	SP_UUID_CANON ${SP_UUID_CANON}
+	SP_UUID_LE ${SP_UUID_LE}
+	SP_NAME "se-proxy"
+	MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+	DTS_IN ${CMAKE_CURRENT_LIST_DIR}/default_se-proxy.dts.in
+	JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/se-proxy/config/corstone-1000-opteesp/default_se-proxy.dts.in b/deployments/se-proxy/config/corstone-1000-opteesp/default_se-proxy.dts.in
new file mode 100644
index 0000000..d0fa26a
--- /dev/null
+++ b/deployments/se-proxy/config/corstone-1000-opteesp/default_se-proxy.dts.in
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+	compatible = "arm,ffa-manifest-1.0";
+	ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+	uuid = <@EXPORT_SP_UUID_DT@>;
+	description = "SE Proxy";
+	execution-ctx-count = <1>;
+	exception-level = <1>; /* S-EL0 */
+	execution-state = <0>; /* AArch64 */
+	xlat-granule = <0>; /* 4KiB */
+	messaging-method = <3>; /* Direct messaging only */
+	elf-format = <1>;
+
+	device-regions {
+		compatible = "arm,ffa-manifest-device-regions";
+		mhu-sender {
+			/* Armv8 A Foundation Platform values */
+			base-address = <0x00000000 0x1b820000>;
+			pages-count = <16>;
+			attributes = <0x3>; /* read-write */
+		};
+		mhu-receiver {
+			/* Armv8 A Foundation Platform values */
+			base-address = <0x00000000 0x1b830000>;
+			pages-count = <16>;
+			attributes = <0x3>; /* read-write */
+		};
+		openamp-virtio {
+			/* Armv8 A Foundation Platform values */
+			base-address = <0x00000000 0x88000000>;
+			pages-count = <256>;
+			attributes = <0x3>; /* read-write */
+		};
+	};
+};
diff --git a/deployments/se-proxy/config/corstone-1000-opteesp/optee_sp_user_defines.h b/deployments/se-proxy/config/corstone-1000-opteesp/optee_sp_user_defines.h
new file mode 100644
index 0000000..efc1dfa
--- /dev/null
+++ b/deployments/se-proxy/config/corstone-1000-opteesp/optee_sp_user_defines.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef SP_HEADER_DEFINES_H
+#define SP_HEADER_DEFINES_H
+
+#define OPTEE_SP_FLAGS				0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE			(64 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/deployments/se-proxy/env/commonsp/se_proxy_sp.cmake b/deployments/se-proxy/env/commonsp/se_proxy_sp.cmake
index 3f05db2..32bb8e9 100644
--- a/deployments/se-proxy/env/commonsp/se_proxy_sp.cmake
+++ b/deployments/se-proxy/env/commonsp/se_proxy_sp.cmake
@@ -20,7 +20,6 @@
 		"components/config/ramstore"
 		"components/config/loader/sp"
 		"components/messaging/ffa/libsp"
-		"components/rpc/common/interface"
 		"components/rpc/ffarpc/endpoint"
 )
 
diff --git a/deployments/se-proxy/infra/corstone-1000/infra.cmake b/deployments/se-proxy/infra/corstone-1000/infra.cmake
new file mode 100644
index 0000000..675f2cd
--- /dev/null
+++ b/deployments/se-proxy/infra/corstone-1000/infra.cmake
@@ -0,0 +1,37 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# A stub infrastructure for the se-proxy. Infrastructure dependencies are all
+# realized with stub components that do absolutely nothing.
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+# Infrastructure components
+#
+#-------------------------------------------------------------------------------
+add_components(TARGET "se-proxy"
+	BASE_DIR ${TS_ROOT}
+	COMPONENTS
+		"components/rpc/common/caller"
+		"components/rpc/psa_ipc"
+		"components/messaging/openamp/sp"
+		"components/service/attestation/client/psa_ipc"
+		"components/service/attestation/key_mngr/local"
+		"components/service/attestation/reporter/psa_ipc"
+		"components/service/crypto/backend/psa_ipc"
+		"components/service/secure_storage/backend/secure_storage_ipc"
+)
+
+# libmetal
+include(${TS_ROOT}/external/openamp/libmetal.cmake)
+
+# OpenAMP
+include(${TS_ROOT}/external/openamp/openamp.cmake)
+target_link_libraries(se-proxy PRIVATE openamp libmetal)
+
+target_sources(se-proxy PRIVATE
+
+	${CMAKE_CURRENT_LIST_DIR}/service_proxy_factory.c
+)
diff --git a/deployments/se-proxy/infra/corstone-1000/service_proxy_factory.c b/deployments/se-proxy/infra/corstone-1000/service_proxy_factory.c
new file mode 100644
index 0000000..bacab1d
--- /dev/null
+++ b/deployments/se-proxy/infra/corstone-1000/service_proxy_factory.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <psa/sid.h>
+#include <rpc/common/endpoint/rpc_interface.h>
+#include <rpc/psa_ipc/caller/sp/psa_ipc_caller.h>
+#include <service/attestation/provider/attest_provider.h>
+#include <service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h>
+#include <service/crypto/factory/crypto_provider_factory.h>
+#include <service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h>
+#include <trace.h>
+
+/* backends */
+#include <service/crypto/backend/psa_ipc/crypto_ipc_backend.h>
+#include <service/secure_storage/backend/secure_storage_ipc/secure_storage_ipc.h>
+#include <service/attestation/client/psa/iat_client.h>
+
+struct psa_ipc_caller psa_ipc;
+
+struct rpc_interface *attest_proxy_create(void)
+{
+	struct rpc_interface *attest_iface;
+	struct rpc_caller *attest_caller;
+
+	/* Static objects for proxy instance */
+	static struct attest_provider attest_provider;
+
+	attest_caller = psa_ipc_caller_init(&psa_ipc);
+	if (!attest_caller)
+		return NULL;
+
+	/* Initialize the service provider */
+	attest_iface = attest_provider_init(&attest_provider);
+	psa_iat_client_init(&psa_ipc.rpc_caller);
+
+	attest_provider_register_serializer(&attest_provider,
+		TS_RPC_ENCODING_PACKED_C, packedc_attest_provider_serializer_instance());
+
+	return attest_iface;
+}
+
+struct rpc_interface *crypto_proxy_create(void)
+{
+	struct rpc_interface *crypto_iface = NULL;
+	struct crypto_provider *crypto_provider;
+	struct rpc_caller *crypto_caller;
+
+	crypto_caller = psa_ipc_caller_init(&psa_ipc);
+	if (!crypto_caller)
+		return NULL;
+
+	if (crypto_ipc_backend_init(&psa_ipc.rpc_caller) != PSA_SUCCESS)
+		return NULL;
+
+	crypto_provider = crypto_provider_factory_create();
+	crypto_iface = service_provider_get_rpc_interface(&crypto_provider->base_provider);
+
+	return crypto_iface;
+}
+
+struct rpc_interface *ps_proxy_create(void)
+{
+	static struct secure_storage_provider ps_provider;
+	static struct secure_storage_ipc ps_backend;
+	struct rpc_caller *storage_caller;
+	struct storage_backend *backend;
+
+	storage_caller = psa_ipc_caller_init(&psa_ipc);
+	if (!storage_caller)
+		return NULL;
+	backend = secure_storage_ipc_init(&ps_backend, &psa_ipc.rpc_caller);
+	ps_backend.service_handle = TFM_PROTECTED_STORAGE_SERVICE_HANDLE;
+
+	return secure_storage_provider_init(&ps_provider, backend);
+}
+
+struct rpc_interface *its_proxy_create(void)
+{
+	static struct secure_storage_provider its_provider;
+	static struct secure_storage_ipc its_backend;
+	struct rpc_caller *storage_caller;
+	struct storage_backend *backend;
+
+	storage_caller = psa_ipc_caller_init(&psa_ipc);
+	if (!storage_caller)
+		return NULL;
+	backend = secure_storage_ipc_init(&its_backend, &psa_ipc.rpc_caller);
+	its_backend.service_handle = TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_HANDLE;
+
+	return secure_storage_provider_init(&its_provider, backend);
+}
diff --git a/deployments/se-proxy/se-proxy.cmake b/deployments/se-proxy/se-proxy.cmake
index 9d71381..2643cfb 100644
--- a/deployments/se-proxy/se-proxy.cmake
+++ b/deployments/se-proxy/se-proxy.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -17,6 +17,7 @@
 		"components/service/common/provider"
 		"components/service/discovery/provider"
 		"components/service/discovery/provider/serializer/packed-c"
+		"components/service/crypto/client/psa"
 		"components/service/crypto/include"
 		"components/service/crypto/provider"
 		"components/service/crypto/provider/serializer/protobuf"
diff --git a/external/openamp/libmetal-init-cache.cmake.in b/external/openamp/libmetal-init-cache.cmake.in
new file mode 100644
index 0000000..04c25fb
--- /dev/null
+++ b/external/openamp/libmetal-init-cache.cmake.in
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Linaro. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX "@BUILD_INSTALL_DIR@" CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE "@TS_EXTERNAL_LIB_TOOLCHAIN_FILE@" CACHE STRING "")
+set(BUILD_SHARED_LIBS Off CACHE BOOL "")
+set(BUILD_STATIC_LIBS On CACHE BOOL "")
+
+set(WITH_DOC OFF CACHE BOOL "")
+set(WITH_TESTS OFF CACHE BOOL "")
+set(WITH_EXAMPLES OFF CACHE BOOL "")
+set(WITH_DEFAULT_LOGGER OFF CACHE BOOL "")
+set(MACHINE "template" CACHE STRING "")
+
+@_cmake_fragment@
diff --git a/external/openamp/libmetal.cmake b/external/openamp/libmetal.cmake
new file mode 100644
index 0000000..d06aa12
--- /dev/null
+++ b/external/openamp/libmetal.cmake
@@ -0,0 +1,67 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022 Linaro Limited
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set (LIBMETAL_URL "https://github.com/OpenAMP/libmetal.git"
+		    CACHE STRING "libmetal repository URL")
+set (LIBMETAL_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/libmetal_install"
+		    CACHE DIR "libmetal installation directory")
+set(LIBMETAL_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/libmetal"
+		CACHE DIR "libmetal source-code")
+set (LIBMETAL_PACKAGE_DIR "${LIBMETAL_INSTALL_DIR}/libmetal/cmake"
+			    CACHE DIR "libmetal CMake package directory")
+set (LIBMETAL_TARGET_NAME "libmetal")
+set (LIBMETAL_REFSPEC "f252f0e007fbfb8b3a52b1d5901250ddac96baad"
+			CACHE STRING "The version of libmetal to use")
+set(LIBMETAL_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/libmetal-build")
+
+set(GIT_OPTIONS
+    GIT_REPOSITORY ${LIBMETAL_URL}
+    GIT_TAG ${LIBMETAL_REFSPEC}
+    GIT_SHALLOW FALSE
+)
+
+if(NOT LIBMETAL_DEBUG)
+	set(LIBMETAL_BUILD_TYPE "Release")
+else()
+	set(LIBMETAL_BUILD_TYPE "Debug")
+endif()
+
+include(FetchContent)
+
+# Checking git
+find_program(GIT_COMMAND "git")
+if (NOT GIT_COMMAND)
+	message(FATAL_ERROR "Please install git")
+endif()
+
+# Only pass libc settings to libmetal if needed. For environments where the
+# standard library is not overridden, this is not needed.
+if(TARGET stdlib::c)
+	include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
+
+	# Save libc settings
+	save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
+	# Translate libc settings to cmake code fragment. Will be inserted into
+	# libmetal-init-cache.cmake.in when LazyFetch configures the file.
+	translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+	unset_saved_properties(LIBC)
+endif()
+
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME libmetal
+    FETCH_OPTIONS "${GIT_OPTIONS}"
+    INSTALL_DIR "${LIBMETAL_INSTALL_DIR}"
+    CACHE_FILE "${TS_ROOT}/external/openamp/libmetal-init-cache.cmake.in"
+    SOURCE_DIR "${LIBMETAL_SOURCE_DIR}"
+)
+unset(_cmake_fragment)
+
+#Create an imported target to have clean abstraction in the build-system.
+add_library(libmetal STATIC IMPORTED)
+set_property(TARGET libmetal PROPERTY IMPORTED_LOCATION "${LIBMETAL_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}metal${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set_property(TARGET libmetal PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${LIBMETAL_INSTALL_DIR}/include")
diff --git a/external/openamp/openamp-init-cache.cmake.in b/external/openamp/openamp-init-cache.cmake.in
new file mode 100644
index 0000000..302b805
--- /dev/null
+++ b/external/openamp/openamp-init-cache.cmake.in
@@ -0,0 +1,20 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Linaro. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set(CMAKE_INSTALL_PREFIX "@BUILD_INSTALL_DIR@" CACHE STRING "")
+set(CMAKE_TOOLCHAIN_FILE "@TS_EXTERNAL_LIB_TOOLCHAIN_FILE@" CACHE STRING "")
+set(BUILD_SHARED_LIBS Off CACHE BOOL "")
+set(BUILD_STATIC_LIBS On CACHE BOOL "")
+
+set(LIBMETAL_INCLUDE_DIR "@CMAKE_CURRENT_BINARY_DIR@/libmetal_install/include" CACHE
+    STRING "")
+set(LIBMETAL_LIB "@CMAKE_CURRENT_BINARY_DIR@/libmetal_install/lib" CACHE STRING "")
+set(RPMSG_BUFFER_SIZE "512" CACHE STRING "")
+set(MACHINE "template" CACHE STRING "")
+
+@_cmake_fragment@
diff --git a/external/openamp/openamp.cmake b/external/openamp/openamp.cmake
new file mode 100644
index 0000000..449f35f
--- /dev/null
+++ b/external/openamp/openamp.cmake
@@ -0,0 +1,66 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022 Linaro Limited
+# Copyright (c) 2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+set (OPENAMP_URL "https://github.com/OpenAMP/open-amp.git"
+		    CACHE STRING "OpenAMP repository URL")
+set (OPENAMP_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/openamp_install"
+			    CACHE DIR "OpenAMP installation directory")
+set (OPENAMP_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/openamp"
+			    CACHE DIR "OpenAMP source code directory")
+set (OPENAMP_PACKAGE_DIR "${OPENAMP_INSTALL_DIR}/openamp/cmake"
+			    CACHE DIR "OpenAMP CMake package directory")
+set (OPENAMP_TARGET_NAME "openamp")
+set (OPENAMP_REFSPEC "347397decaa43372fc4d00f965640ebde042966d"
+			CACHE STRING "The version of openamp to use")
+
+set(GIT_OPTIONS
+    GIT_REPOSITORY ${OPENAMP_URL}
+    GIT_TAG ${OPENAMP_REFSPEC}
+    GIT_SHALLOW FALSE
+)
+
+if(NOT OPENAMP_DEBUG)
+	set(OPENAMP_BUILD_TYPE "Release")
+else()
+	set(OPENAMP_BUILD_TYPE "Debug")
+endif()
+
+include(FetchContent)
+
+# Checking git
+find_program(GIT_COMMAND "git")
+if (NOT GIT_COMMAND)
+	message(FATAL_ERROR "Please install git")
+endif()
+
+# Only pass libc settings to openamp if needed. For environments where the
+# standard library is not overridden, this is not needed.
+if(TARGET stdlib::c)
+	include(${TS_ROOT}/tools/cmake/common/PropertyCopy.cmake)
+
+	# Save libc settings
+	save_interface_target_properties(TGT stdlib::c PREFIX LIBC)
+	# Translate libc settings to cmake code fragment. Will be inserted into
+	# libmetal-init-cache.cmake.in when LazyFetch configures the file.
+	translate_interface_target_properties(PREFIX LIBC RES _cmake_fragment)
+	unset_saved_properties(LIBC)
+endif()
+
+include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED)
+LazyFetch_MakeAvailable(DEP_NAME openamp
+    FETCH_OPTIONS "${GIT_OPTIONS}"
+    INSTALL_DIR "${OPENAMP_INSTALL_DIR}"
+    CACHE_FILE "${TS_ROOT}/external/openamp/openamp-init-cache.cmake.in"
+    SOURCE_DIR "${OPENAMP_SOURCE_DIR}"
+)
+unset(_cmake_fragment)
+
+#Create an imported target to have clean abstraction in the build-system.
+add_library(openamp STATIC IMPORTED)
+set_property(TARGET openamp PROPERTY IMPORTED_LOCATION "${OPENAMP_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}open_amp${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set_property(TARGET openamp PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${OPENAMP_INSTALL_DIR}/include")
diff --git a/external/psa_arch_tests/0001-Disable-using-hard-coded-attestation-key.patch b/external/psa_arch_tests/0001-Disable-using-hard-coded-attestation-key.patch
deleted file mode 100644
index 6664961..0000000
--- a/external/psa_arch_tests/0001-Disable-using-hard-coded-attestation-key.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From dbd25f94eb62a9855bf342dd97503a49ea50f83e Mon Sep 17 00:00:00 2001
-From: Gyorgy Szing <Gyorgy.Szing@arm.com>
-Date: Tue, 8 Feb 2022 17:06:37 +0000
-Subject: [PATCH 1/1] Disable using hard-coded attestation key
-
-Modify platform config to disable using a hard-coded attestation
-key.
-
-Signed-off-by: Gyorgy Szing <Gyorgy.Szing@arm.com>
----
- api-tests/platform/targets/tgt_dev_apis_linux/nspe/pal_config.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/api-tests/platform/targets/tgt_dev_apis_linux/nspe/pal_config.h b/api-tests/platform/targets/tgt_dev_apis_linux/nspe/pal_config.h
-index 6112ba7..1cdf581 100755
---- a/api-tests/platform/targets/tgt_dev_apis_linux/nspe/pal_config.h
-+++ b/api-tests/platform/targets/tgt_dev_apis_linux/nspe/pal_config.h
-@@ -60,7 +60,7 @@ typedef uint32_t            cfg_id_t;
- #define CRYPTO_VERSION_BETA3
- 
- /* Use hardcoded public key */
--#define PLATFORM_OVERRIDE_ATTEST_PK
-+//#define PLATFORM_OVERRIDE_ATTEST_PK
- 
- /*
-  * Include of PSA defined Header files
--- 
-2.17.1
-
diff --git a/external/psa_arch_tests/psa_arch_tests.cmake b/external/psa_arch_tests/psa_arch_tests.cmake
index d0a46ac..6c3cf15 100644
--- a/external/psa_arch_tests/psa_arch_tests.cmake
+++ b/external/psa_arch_tests/psa_arch_tests.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -14,10 +14,6 @@
 	GIT_REPOSITORY ${PSA_ARCH_TESTS_URL}
 	GIT_TAG ${PSA_ARCH_TESTS_REFSPEC}
 	GIT_SHALLOW FALSE
-	PATCH_COMMAND git stash
-		COMMAND git tag -f ts-before-am
-		COMMAND git am ${CMAKE_CURRENT_LIST_DIR}/0001-Disable-using-hard-coded-attestation-key.patch
-		COMMAND git reset ts-before-am
 )
 
 # Ensure list of defines is separated correctly
diff --git a/platform/drivers/arm/mhu_driver/component.cmake b/platform/drivers/arm/mhu_driver/component.cmake
new file mode 100644
index 0000000..77a5a50
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/component.cmake
@@ -0,0 +1,12 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+# Add source files for using mhu driver
+target_sources(${TGT}
+	PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/mhu_v2_x.c"
+)
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2.h b/platform/drivers/arm/mhu_driver/mhu_v2.h
new file mode 100644
index 0000000..26b3a5d
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2.h
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2021 Arm Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file mhu_v2_x.h
+ * \brief Driver for Arm MHU v2.0 and v2.1
+ */
+
+#ifndef __MHU_V2_X_H__
+#define __MHU_V2_X_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MHU_2_X_INTR_NR2R_OFF             (0x0u)
+#define MHU_2_X_INTR_R2NR_OFF             (0x1u)
+#define MHU_2_1_INTR_CHCOMB_OFF           (0x2u)
+
+#define MHU_2_X_INTR_NR2R_MASK            (0x1u << MHU_2_X_INTR_NR2R_OFF)
+#define MHU_2_X_INTR_R2NR_MASK            (0x1u << MHU_2_X_INTR_R2NR_OFF)
+#define MHU_2_1_INTR_CHCOMB_MASK          (0x1u << MHU_2_1_INTR_CHCOMB_OFF)
+
+enum mhu_v2_x_frame_t {
+    MHU_V2_X_SENDER_FRAME   = 0x0u,
+    MHU_V2_X_RECEIVER_FRAME = 0x1u,
+};
+
+enum mhu_v2_x_supported_revisions {
+     MHU_REV_READ_FROM_HW = 0,
+     MHU_REV_2_0,
+     MHU_REV_2_1,
+};
+
+struct mhu_v2_x_dev_t {
+    uintptr_t base;
+    enum mhu_v2_x_frame_t frame;
+    uint32_t subversion;    /*!< Hardware subversion: v2.X */
+    bool is_initialized;    /*!< Indicates if the MHU driver
+                             *   is initialized and enabled
+                             */
+};
+
+/**
+ * \brief MHU v2 error enumeration types.
+ */
+enum mhu_v2_x_error_t {
+    MHU_V_2_X_ERR_NONE                =  0,
+    MHU_V_2_X_ERR_NOT_INIT            = -1,
+    MHU_V_2_X_ERR_ALREADY_INIT        = -2,
+    MHU_V_2_X_ERR_UNSUPPORTED_VERSION = -3,
+    MHU_V_2_X_ERR_INVALID_ARG         = -4,
+    MHU_V_2_X_ERR_GENERAL             = -5
+};
+
+/**
+ * \brief Initializes the driver
+ *
+ * \param[in] dev   MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] rev   MHU revision (if can't be identified from HW)
+ *
+ * Reads the MHU hardware version
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note MHU revision only has to be specified when versions can't be read
+ *       from HW (ARCH_MAJOR_REV reg reads as 0x0).
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+     enum mhu_v2_x_supported_revisions rev);
+
+/**
+ * \brief Returns the number of channels implemented.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * Returns the number of channels implemented.
+ *
+ * \return Returns the number of channels implemented.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+uint32_t mhu_v2_x_get_num_channel_implemented(
+         const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Sends the value over a channel.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel     Channel to send the value over.
+ * \param[in] val         Value to send.
+ *
+ * Sends the value over a channel.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+     uint32_t channel, uint32_t val);
+
+/**
+ * \brief Clears the channel after the value is send over it.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel     Channel to clear.
+ *
+ * Clears the channel after the value is send over it.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+     uint32_t channel);
+
+/**
+ * \brief Receives the value over a channel.
+ *
+ * \param[in]  dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in]  channel     Channel to receive the value from.
+ * \param[out] value       Pointer to variable that will store the value.
+ *
+ * Receives the value over a channel.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value);
+
+/**
+ * \brief Sets bits in the Channel Mask.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel     Which channel's mask to set.
+ * \param[in] mask        Mask to be set over a receiver frame.
+ *
+ * Sets bits in the Channel Mask.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * \brief Clears bits in the Channel Mask.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel     Which channel's mask to clear.
+ * \param[in] mask        Mask to be clear over a receiver frame.
+ *
+ * Clears bits in the Channel Mask.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask);
+
+/**
+ * \brief Enables the Channel interrupt.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel     Which channel's interrupt to enable.
+ *
+ * Enables the Channel clear interrupt.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_enable(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel);
+
+/**
+ * \brief Disables the Channel interrupt.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel     Which channel's interrupt to disable.
+ *
+ * Disables the Channel interrupt.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_disable(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel);
+
+/**
+ * \brief Cleares the Channel interrupt.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] channel     Which channel's interrupt to clear.
+ *
+ * Cleares the Channel interrupt.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ * \note This function doesn't check if channel is implemented.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_clear(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel);
+
+/**
+ * \brief Initiates a MHU transfer with the handshake signals.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * Initiates a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+     const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Closes a MHU transfer with the handshake signals.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * Closes a MHU transfer with the handshake signals in a blocking mode.
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(
+     const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Returns the value of access request signal.
+ *
+ * \param[in]  dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[out] val         Pointer to variable that will store the value.
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_get_access_request(
+     const struct mhu_v2_x_dev_t *dev, uint32_t *val);
+
+/**
+ * \brief Sets the value of access request signal to high.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_set_access_request(
+     const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Sets the value of access request signal to low.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_reset_access_request(
+     const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Returns the value of access ready signal.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[out] val        Pointer to variable that will store the value.
+ *
+ * For more information please read the MHU v2 user guide
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_get_access_ready(
+     const struct mhu_v2_x_dev_t *dev, uint32_t *val);
+
+/**
+ * \brief Returns the MHU interrupt status.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ *
+ * \return Interrupt status register value. Masking is needed for individual
+ *         interrupts.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+uint32_t mhu_v2_x_get_interrupt_status(const struct mhu_v2_x_dev_t *dev);
+
+/**
+ * \brief Enables MHU interrupts.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] mask        Bit mask for enabling/disabling interrupts
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_enable(
+     const struct mhu_v2_x_dev_t *dev, uint32_t mask);
+
+/**
+ * \brief Disables MHU interrupts.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] mask        Bit mask for enabling/disabling interrupts
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_disable(
+     const struct mhu_v2_x_dev_t *dev, uint32_t mask);
+
+/**
+ * \brief Clears MHU interrupts.
+ *
+ * \param[in] dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[in] mask        Bit mask for clearing interrupts
+ *
+ * \return Returns mhu_v2_x_error_t error code
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_clear(
+     const struct mhu_v2_x_dev_t *dev, uint32_t mask);
+
+/**
+ * \brief Returns the first channel number whose interrupt bit is high.
+ *
+ * \param[in]  dev         MHU device struct \ref mhu_v2_x_dev_t
+ * \param[out] channel     Pointer to variable that will have the channel value.
+ *
+ * \return Returns the first channel number whose interrupt bit is high.
+ * \return Returns mhu_v2_x_error_t error code.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum mhu_v2_x_error_t mhu_v2_1_get_ch_interrupt_num(
+     const struct mhu_v2_x_dev_t *dev, uint32_t *channel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MHU_V2_X_H__ */
diff --git a/platform/drivers/arm/mhu_driver/mhu_v2_x.c b/platform/drivers/arm/mhu_driver/mhu_v2_x.c
new file mode 100644
index 0000000..d7e70ef
--- /dev/null
+++ b/platform/drivers/arm/mhu_driver/mhu_v2_x.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2021 Arm Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <stdint.h>
+#include <stdbool.h>
+#include "mhu_v2.h"
+
+#define _MHU_V2_X_MAX_CHANNELS    124
+#define _MHU_V2_1_MAX_CHCOMB_INT  4
+#define ENABLE                    0x1
+#define DISABLE                   0x0
+#define CLEAR_INTR                0x1
+#define CH_PER_CH_COMB            0x20
+#define SEND_FRAME(p_mhu)       ((struct _mhu_v2_x_send_frame_t *)p_mhu)
+#define RECV_FRAME(p_mhu)       ((struct _mhu_v2_x_recv_frame_t *)p_mhu)
+
+#define MHU_MAJOR_REV_V2      0x1u
+#define MHU_MINOR_REV_2_0     0x0u
+#define MHU_MINOR_REV_2_1     0x1u
+
+struct _mhu_v2_x_send_ch_window_t {
+    /* Offset: 0x00 (R/ ) Channel Status */
+    volatile uint32_t ch_st;
+    /* Offset: 0x04 (R/ ) Reserved */
+    volatile uint32_t reserved_0;
+    /* Offset: 0x08 (R/ ) Reserved */
+    volatile uint32_t reserved_1;
+    /* Offset: 0x0C ( /W) Channel Set */
+    volatile uint32_t ch_set;
+    /* Offset: 0x10 (R/ ) Channel Interrupt Status (Reserved in 2.0) */
+    volatile uint32_t ch_int_st;
+    /* Offset: 0x14 ( /W) Channel Interrupt Clear  (Reserved in 2.0) */
+    volatile uint32_t ch_int_clr;
+    /* Offset: 0x18 (R/W) Channel Interrupt Enable (Reserved in 2.0) */
+    volatile uint32_t ch_int_en;
+    /* Offset: 0x1C (R/ ) Reserved */
+    volatile uint32_t reserved_2;
+};
+
+struct _mhu_v2_x_send_frame_t {
+    /* Offset: 0x000 ( / ) Sender Channel Window 0 -123 */
+    struct _mhu_v2_x_send_ch_window_t send_ch_window[_MHU_V2_X_MAX_CHANNELS];
+    /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+    volatile uint32_t mhu_cfg;
+    /* Offset: 0xF84 (R/W) Response Configuration */
+    volatile uint32_t resp_cfg;
+    /* Offset: 0xF88 (R/W) Access Request */
+    volatile uint32_t access_request;
+    /* Offset: 0xF8C (R/ ) Access Ready */
+    volatile uint32_t access_ready;
+    /* Offset: 0xF90 (R/ ) Interrupt Status */
+    volatile uint32_t int_st;
+    /* Offset: 0xF94 ( /W) Interrupt Clear */
+    volatile uint32_t int_clr;
+    /* Offset: 0xF98 (R/W) Interrupt Enable */
+    volatile uint32_t int_en;
+    /* Offset: 0xF9C (R/ ) Reserved */
+    volatile uint32_t reserved_0;
+    /* Offset: 0xFA0 (R/W) Channel Combined Interrupt Stat (Reserved in 2.0) */
+    volatile uint32_t ch_comb_int_st[_MHU_V2_1_MAX_CHCOMB_INT];
+    /* Offset: ‭0xFC4‬ (R/ ) Reserved */
+    volatile uint32_t reserved_1[6];
+    /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+    volatile uint32_t iidr;
+    /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+    volatile uint32_t aidr;
+    /* Offset: 0xFD0 (R/ )  */
+    volatile uint32_t pid_1[4];
+    /* Offset: 0xFE0 (R/ )  */
+    volatile uint32_t pid_0[4];
+    /* Offset: 0xFF0 (R/ )  */
+    volatile uint32_t cid[4];
+};
+
+struct _mhu_v2_x_rec_ch_window_t {
+    /* Offset: 0x00 (R/ ) Channel Status */
+    volatile uint32_t ch_st;
+    /* Offset: 0x04 (R/ ) Channel Status Masked */
+    volatile uint32_t ch_st_msk;
+    /* Offset: 0x08 ( /W) Channel Clear */
+    volatile uint32_t ch_clr;
+    /* Offset: 0x0C (R/ ) Reserved */
+    volatile uint32_t reserved_0;
+    /* Offset: 0x10 (R/ ) Channel Mask Status */
+    volatile uint32_t ch_msk_st;
+    /* Offset: 0x14 ( /W) Channel Mask Set */
+    volatile uint32_t ch_msk_set;
+    /* Offset: 0x18 ( /W) Channel Mask Clear */
+    volatile uint32_t ch_msk_clr;
+    /* Offset: 0x1C (R/ ) Reserved */
+    volatile uint32_t reserved_1;
+};
+
+struct _mhu_v2_x_recv_frame_t {
+    /* Offset: 0x000 ( / ) Receiver Channel Window 0 -123 */
+    struct _mhu_v2_x_rec_ch_window_t rec_ch_window[_MHU_V2_X_MAX_CHANNELS];
+    /* Offset: 0xF80 (R/ ) Message Handling Unit Configuration */
+    volatile uint32_t mhu_cfg;
+    /* Offset: 0xF84 (R/ ) Reserved */
+    volatile uint32_t reserved_0[3];
+    /* Offset: 0xF90 (R/ ) Interrupt Status (Reserved in 2.0) */
+    volatile uint32_t int_st;
+    /* Offset: 0xF94 (R/ ) Interrupt Clear  (Reserved in 2.0) */
+    volatile uint32_t int_clr;
+    /* Offset: 0xF98 (R/W) Interrupt Enable (Reserved in 2.0) */
+    volatile uint32_t int_en;
+    /* Offset: 0xF9C (R/ ) Reserved  */
+    volatile uint32_t reserved_1;
+    /* Offset: 0xFA0 (R/ ) Channel Combined Interrupt Stat (Reserved in 2.0) */
+    volatile uint32_t ch_comb_int_st[_MHU_V2_1_MAX_CHCOMB_INT];
+    /* Offset: 0xFB0 (R/ ) Reserved */
+    volatile uint32_t reserved_2[6];
+    /* Offset: 0xFC8 (R/ ) Implementer Identification Register */
+    volatile uint32_t iidr;
+    /* Offset: 0xFCC (R/ ) Architecture Identification Register */
+    volatile uint32_t aidr;
+    /* Offset: 0xFD0 (R/ )  */
+    volatile uint32_t pid_1[4];
+    /* Offset: 0xFE0 (R/ )  */
+    volatile uint32_t pid_0[4];
+    /* Offset: 0xFF0 (R/ )  */
+    volatile uint32_t cid[4];
+};
+
+union _mhu_v2_x_frame_t {
+    struct _mhu_v2_x_send_frame_t send_frame;
+    struct _mhu_v2_x_recv_frame_t recv_frame;
+};
+
+enum mhu_v2_x_error_t mhu_v2_x_driver_init(struct mhu_v2_x_dev_t *dev,
+     enum mhu_v2_x_supported_revisions rev)
+{
+    uint32_t AIDR = 0;
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if (dev->is_initialized) {
+        return MHU_V_2_X_ERR_ALREADY_INIT;
+    }
+
+    if (rev == MHU_REV_READ_FROM_HW) {
+        /* Read revision from HW */
+        if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+            AIDR = p_mhu->recv_frame.aidr;
+        } else {
+            AIDR = p_mhu->send_frame.aidr;
+        }
+
+        /* Get bits 7:4 to read major revision */
+        if ( ((AIDR >> 4) & 0b1111) != MHU_MAJOR_REV_V2) {
+            /* Unsupported MHU version */
+            return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+        } /* No need to save major version, driver only supports MHUv2 */
+
+        /* Get bits 3:0 to read minor revision */
+        dev->subversion = AIDR & 0b1111;
+
+        if (dev->subversion != MHU_MINOR_REV_2_0 &&
+            dev->subversion != MHU_MINOR_REV_2_1) {
+            /* Unsupported subversion */
+            return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+        }
+    } else {
+        /* Revisions were provided by caller */
+        if (rev == MHU_REV_2_0) {
+            dev->subversion = MHU_MINOR_REV_2_0;
+        } else if (rev == MHU_REV_2_1) {
+            dev->subversion = MHU_MINOR_REV_2_1;
+        } else {
+            /* Unsupported subversion */
+            return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+        }/* No need to save major version, driver only supports MHUv2 */
+    }
+
+    dev->is_initialized = true;
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+uint32_t mhu_v2_x_get_num_channel_implemented(const struct mhu_v2_x_dev_t *dev)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+        return (SEND_FRAME(p_mhu))->mhu_cfg;
+    } else {
+        return (RECV_FRAME(p_mhu))->mhu_cfg;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_send(const struct mhu_v2_x_dev_t *dev,
+     uint32_t channel, uint32_t val)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+        (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_set = val;
+        return MHU_V_2_X_ERR_NONE;
+    } else {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_clear(const struct mhu_v2_x_dev_t *dev,
+     uint32_t channel)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+        (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_clr = UINT32_MAX;
+        return MHU_V_2_X_ERR_NONE;
+    } else {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_receive(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t *value)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+        *value = (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_st;
+        return MHU_V_2_X_ERR_NONE;
+    } else {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_set(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+        (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_set = mask;
+        return MHU_V_2_X_ERR_NONE;
+    } else {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_mask_clear(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel, uint32_t mask)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+        (RECV_FRAME(p_mhu))->rec_ch_window[channel].ch_msk_clr = mask;
+        return MHU_V_2_X_ERR_NONE;
+    } else {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_enable(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if (dev->subversion == MHU_MINOR_REV_2_1) {
+        return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+    }
+
+    if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+        (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_int_en = ENABLE;
+        return MHU_V_2_X_ERR_NONE;
+    } else {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_disable(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if (dev->subversion == MHU_MINOR_REV_2_1) {
+        return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+    }
+
+    if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+        (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_int_en = DISABLE;
+        return MHU_V_2_X_ERR_NONE;
+    } else {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_channel_interrupt_clear(
+     const struct mhu_v2_x_dev_t *dev, uint32_t channel)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if (dev->subversion == MHU_MINOR_REV_2_1) {
+        return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+    }
+
+    if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+        (SEND_FRAME(p_mhu))->send_ch_window[channel].ch_int_clr = CLEAR_INTR;
+        return MHU_V_2_X_ERR_NONE;
+    } else {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_initiate_transfer(
+     const struct mhu_v2_x_dev_t *dev)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+
+    (SEND_FRAME(p_mhu))->access_request = ENABLE;
+
+    while ( !((SEND_FRAME(p_mhu))->access_ready) ) {
+        /* Wait in a loop for access ready signal to be high */
+        ;
+    }
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_close_transfer(const struct mhu_v2_x_dev_t *dev)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+
+    (SEND_FRAME(p_mhu))->access_request = DISABLE;
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_get_access_request(
+     const struct mhu_v2_x_dev_t *dev, uint32_t *val)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+
+    *val = (SEND_FRAME(p_mhu))->access_request;
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_set_access_request(
+     const struct mhu_v2_x_dev_t *dev)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+
+    (SEND_FRAME(p_mhu))->access_request = ENABLE;
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_reset_access_request(
+     const struct mhu_v2_x_dev_t *dev)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+
+    (SEND_FRAME(p_mhu))->access_request = DISABLE;
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_get_access_ready(
+     const struct mhu_v2_x_dev_t *dev, uint32_t *val)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame != MHU_V2_X_SENDER_FRAME) {
+        return MHU_V_2_X_ERR_INVALID_ARG;
+    }
+
+    *val = (SEND_FRAME(p_mhu))->access_ready;
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+uint32_t mhu_v2_x_get_interrupt_status(const struct mhu_v2_x_dev_t *dev)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+        return (SEND_FRAME(p_mhu))->int_st;
+    } else {
+        return (RECV_FRAME(p_mhu))->int_st;
+    }
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_enable(
+     const struct mhu_v2_x_dev_t *dev, uint32_t mask)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if (dev->subversion == MHU_MINOR_REV_2_0) {
+        if (mask & MHU_2_1_INTR_CHCOMB_MASK) {
+            /* Combined channel IRQ is not present in v2.0 */
+            return MHU_V_2_X_ERR_INVALID_ARG;
+        }
+
+        if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+            /* Only sender frame has these registers */
+            return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+        }
+    }
+
+    if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+        (SEND_FRAME(p_mhu))->int_en |= mask;
+    } else {
+        (RECV_FRAME(p_mhu))->int_en |= mask;
+    }
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_disable(
+     const struct mhu_v2_x_dev_t *dev, uint32_t mask)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if (dev->subversion == MHU_MINOR_REV_2_0) {
+        if (mask & MHU_2_1_INTR_CHCOMB_MASK) {
+            /* Combined channel IRQ is not present in v2.0 */
+            return MHU_V_2_X_ERR_INVALID_ARG;
+        }
+
+        if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+            /* Only sender frame has these registers */
+            return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+        }
+    }
+
+    if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+        (SEND_FRAME(p_mhu))->int_en &= ~mask;
+    } else {
+        (RECV_FRAME(p_mhu))->int_en &= ~mask;
+    }
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_x_interrupt_clear(
+     const struct mhu_v2_x_dev_t *dev, uint32_t mask)
+{
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if (dev->subversion == MHU_MINOR_REV_2_0) {
+        if (mask & MHU_2_1_INTR_CHCOMB_MASK) {
+            /* Combined channel IRQ is not present in v2.0 */
+            return MHU_V_2_X_ERR_INVALID_ARG;
+        }
+
+        if (dev->frame == MHU_V2_X_RECEIVER_FRAME) {
+            /* Only sender frame has these registers */
+            return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+        }
+    }
+
+    if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+        (SEND_FRAME(p_mhu))->int_clr = mask;
+    } else {
+        (RECV_FRAME(p_mhu))->int_clr = mask;
+    }
+
+    return MHU_V_2_X_ERR_NONE;
+}
+
+enum mhu_v2_x_error_t mhu_v2_1_get_ch_interrupt_num(
+     const struct mhu_v2_x_dev_t *dev, uint32_t *channel)
+{
+    uint32_t i, j, status;
+    union _mhu_v2_x_frame_t *p_mhu = (union _mhu_v2_x_frame_t *)dev->base;
+
+    if ( !(dev->is_initialized) ) {
+        return MHU_V_2_X_ERR_NOT_INIT;
+    }
+
+    if (dev->subversion != MHU_MINOR_REV_2_1) {
+        /* Feature is only supported in MHU v2.1 */
+        return MHU_V_2_X_ERR_UNSUPPORTED_VERSION;
+    }
+
+    for(i = 0; i < _MHU_V2_1_MAX_CHCOMB_INT; i++) {
+        if(dev->frame == MHU_V2_X_SENDER_FRAME) {
+            status = (SEND_FRAME(p_mhu))->ch_comb_int_st[i];
+        } else {
+            status = (RECV_FRAME(p_mhu))->ch_comb_int_st[i];
+        }
+
+        for(j = 0; j < CH_PER_CH_COMB; j++) {
+            if ((status >> (CH_PER_CH_COMB - j - 1)) & (ENABLE)) {
+                *channel = (CH_PER_CH_COMB - j -1) + (i * CH_PER_CH_COMB);
+                return MHU_V_2_X_ERR_NONE;
+            }
+        }
+    }
+
+    return MHU_V_2_X_ERR_GENERAL;
+}
diff --git a/platform/providers/arm/corstone1000/platform.cmake b/platform/providers/arm/corstone1000/platform.cmake
new file mode 100644
index 0000000..dbdf109
--- /dev/null
+++ b/platform/providers/arm/corstone1000/platform.cmake
@@ -0,0 +1,16 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Platform definition for the 'fvp_base_revc-2xaem8a' virtual platform.
+#-------------------------------------------------------------------------------
+
+# include MHU driver
+include(${TS_ROOT}/platform/drivers/arm/mhu_driver/component.cmake)
+
+target_compile_definitions(${TGT} PRIVATE
+	SMM_GATEWAY_NV_STORE_SN="sn:ffa:46bb39d1-b4d9-45b5-88ff-040027dab249:1"
+	SMM_VARIABLE_INDEX_STORAGE_UID=0x787
+	SMM_GATEWAY_MAX_UEFI_VARIABLES=100
+)
diff --git a/tools/b-test/test_data.yaml b/tools/b-test/test_data.yaml
index 86216f5..f94c2ad 100644
--- a/tools/b-test/test_data.yaml
+++ b/tools/b-test/test_data.yaml
@@ -154,6 +154,10 @@
       params:
             - "-GUnix Makefiles"
     - name: "se-proxy-default-opteesp"
+      src: "$TS_ROOT/deployments/se-proxy/config/corstone-1000-opteesp"
+      params:
+            - "-GUnix Makefiles"
+    - name: "se-proxy-default-opteesp"
       src: "$TS_ROOT/deployments/se-proxy/config/default-opteesp"
       params:
             - "-GUnix Makefiles"