Repository: nrfconnect/sdk-nrf
Pull request #21383: nrf_security: 54h20: ironside SE PSA Crypto support
Author: login: SebastianBoe
Labels: name: changelog-entry-required
description: Update changelog before merge. Remove label if entry is not needed or already added.
Created: 2025-04-03T15:27:53Z | Merged: 2025-04-11T08:21:22Z

Provide support for PSA crypto services based on ironside SE.

Ref: NCSDK-32163


Diff:
diff --git a/include/tfm/ironside/se/ipc_service.h b/include/tfm/ironside/se/ipc_service.h
new file mode 100644
index 000000000000..a474bccef4c3
--- /dev/null
+++ b/include/tfm/ironside/se/ipc_service.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __SDFW_PSA_IPC_SERVICE_H__
+#define __SDFW_PSA_IPC_SERVICE_H__
+
+/*
+ * This header contains symbols that are used by both the IRONside SE client
+ * and the IRONside SE service.
+ */
+enum {
+	IRONSIDE_SE_IPC_INDEX_HANDLE,
+	IRONSIDE_SE_IPC_INDEX_IN_VEC,
+	IRONSIDE_SE_IPC_INDEX_IN_LEN,
+	IRONSIDE_SE_IPC_INDEX_OUT_VEC,
+	IRONSIDE_SE_IPC_INDEX_OUT_LEN,
+	IRONSIDE_SE_IPC_INDEX_STATUS_PTR,
+	/* The last enum value is reserved for the size of the IPC buffer */
+	IRONSIDE_SE_IPC_DATA_LEN
+};
+
+/* We are adding the source files for the TF-M crypto partition to the build.
+ *
+ * The crypto partition will include the file psa_manifest/sid.h and
+ * expect the below three symbols to be there.
+ *
+ * In a TF-M build, the TF-M build system will generate
+ * psa_manifest/sid.h based on each partitions manifest.
+ *
+ * See https://trustedfirmware-m.readthedocs.io/
+ * en/latest/integration_guide/services/tfm_secure_partition_addition.html
+ *
+ * for an example of a partition manifest.
+ */
+#define TFM_CRYPTO_SID	   (0x00000080U)
+#define TFM_CRYPTO_VERSION (1U)
+#define TFM_CRYPTO_HANDLE  (0x40000100U)
+
+#endif /* __SDFW_PSA_IPC_SERVICE_H__ */
diff --git a/samples/crypto/aes_gcm/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf b/samples/crypto/aes_gcm/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
new file mode 100644
index 000000000000..d172f58efb93
--- /dev/null
+++ b/samples/crypto/aes_gcm/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2024 Nordic Semiconductor
+#
+# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+#
+
+# Disable Oberon PSA crypto drivers
+CONFIG_PSA_CRYPTO_DRIVER_OBERON=n
+
+# Enable PSA crypto from SSF client
+CONFIG_PSA_SSF_CRYPTO_CLIENT=y
+CONFIG_SSF_PSA_CRYPTO_SERVICE_ENABLED=y
+
+# Mbedtls configuration
+CONFIG_MBEDTLS_ENABLE_HEAP=y
+CONFIG_MBEDTLS_HEAP_SIZE=8192
diff --git a/samples/crypto/aes_gcm/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay b/samples/crypto/aes_gcm/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
new file mode 100644
index 000000000000..1ca688cf9792
--- /dev/null
+++ b/samples/crypto/aes_gcm/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+&cpusec_cpuapp_ipc {
+	status = "okay";
+};
+
+&cpuapp_ram0x_region {
+	status = "okay";
+};
+
+&cpusec_bellboard {
+	status = "okay";
+};
+
+&cpuapp_bellboard {
+	status = "okay";
+};
diff --git a/samples/crypto/ecdh/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf b/samples/crypto/ecdh/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
new file mode 100644
index 000000000000..d172f58efb93
--- /dev/null
+++ b/samples/crypto/ecdh/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2024 Nordic Semiconductor
+#
+# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+#
+
+# Disable Oberon PSA crypto drivers
+CONFIG_PSA_CRYPTO_DRIVER_OBERON=n
+
+# Enable PSA crypto from SSF client
+CONFIG_PSA_SSF_CRYPTO_CLIENT=y
+CONFIG_SSF_PSA_CRYPTO_SERVICE_ENABLED=y
+
+# Mbedtls configuration
+CONFIG_MBEDTLS_ENABLE_HEAP=y
+CONFIG_MBEDTLS_HEAP_SIZE=8192
diff --git a/samples/crypto/ecdh/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay b/samples/crypto/ecdh/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
new file mode 100644
index 000000000000..1ca688cf9792
--- /dev/null
+++ b/samples/crypto/ecdh/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+&cpusec_cpuapp_ipc {
+	status = "okay";
+};
+
+&cpuapp_ram0x_region {
+	status = "okay";
+};
+
+&cpusec_bellboard {
+	status = "okay";
+};
+
+&cpuapp_bellboard {
+	status = "okay";
+};
diff --git a/samples/crypto/ecdsa/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf b/samples/crypto/ecdsa/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
new file mode 100644
index 000000000000..d172f58efb93
--- /dev/null
+++ b/samples/crypto/ecdsa/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2024 Nordic Semiconductor
+#
+# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+#
+
+# Disable Oberon PSA crypto drivers
+CONFIG_PSA_CRYPTO_DRIVER_OBERON=n
+
+# Enable PSA crypto from SSF client
+CONFIG_PSA_SSF_CRYPTO_CLIENT=y
+CONFIG_SSF_PSA_CRYPTO_SERVICE_ENABLED=y
+
+# Mbedtls configuration
+CONFIG_MBEDTLS_ENABLE_HEAP=y
+CONFIG_MBEDTLS_HEAP_SIZE=8192
diff --git a/samples/crypto/ecdsa/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay b/samples/crypto/ecdsa/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
new file mode 100644
index 000000000000..1ca688cf9792
--- /dev/null
+++ b/samples/crypto/ecdsa/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+&cpusec_cpuapp_ipc {
+	status = "okay";
+};
+
+&cpuapp_ram0x_region {
+	status = "okay";
+};
+
+&cpusec_bellboard {
+	status = "okay";
+};
+
+&cpuapp_bellboard {
+	status = "okay";
+};
diff --git a/samples/crypto/rng/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf b/samples/crypto/rng/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
new file mode 100644
index 000000000000..d172f58efb93
--- /dev/null
+++ b/samples/crypto/rng/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2024 Nordic Semiconductor
+#
+# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+#
+
+# Disable Oberon PSA crypto drivers
+CONFIG_PSA_CRYPTO_DRIVER_OBERON=n
+
+# Enable PSA crypto from SSF client
+CONFIG_PSA_SSF_CRYPTO_CLIENT=y
+CONFIG_SSF_PSA_CRYPTO_SERVICE_ENABLED=y
+
+# Mbedtls configuration
+CONFIG_MBEDTLS_ENABLE_HEAP=y
+CONFIG_MBEDTLS_HEAP_SIZE=8192
diff --git a/samples/crypto/rng/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay b/samples/crypto/rng/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
new file mode 100644
index 000000000000..1ca688cf9792
--- /dev/null
+++ b/samples/crypto/rng/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+&cpusec_cpuapp_ipc {
+	status = "okay";
+};
+
+&cpuapp_ram0x_region {
+	status = "okay";
+};
+
+&cpusec_bellboard {
+	status = "okay";
+};
+
+&cpuapp_bellboard {
+	status = "okay";
+};
diff --git a/samples/crypto/sha256/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf b/samples/crypto/sha256/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
new file mode 100644
index 000000000000..d172f58efb93
--- /dev/null
+++ b/samples/crypto/sha256/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2024 Nordic Semiconductor
+#
+# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+#
+
+# Disable Oberon PSA crypto drivers
+CONFIG_PSA_CRYPTO_DRIVER_OBERON=n
+
+# Enable PSA crypto from SSF client
+CONFIG_PSA_SSF_CRYPTO_CLIENT=y
+CONFIG_SSF_PSA_CRYPTO_SERVICE_ENABLED=y
+
+# Mbedtls configuration
+CONFIG_MBEDTLS_ENABLE_HEAP=y
+CONFIG_MBEDTLS_HEAP_SIZE=8192
diff --git a/samples/crypto/sha256/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay b/samples/crypto/sha256/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
new file mode 100644
index 000000000000..1ca688cf9792
--- /dev/null
+++ b/samples/crypto/sha256/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2024 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+&cpusec_cpuapp_ipc {
+	status = "okay";
+};
+
+&cpuapp_ram0x_region {
+	status = "okay";
+};
+
+&cpusec_bellboard {
+	status = "okay";
+};
+
+&cpuapp_bellboard {
+	status = "okay";
+};
diff --git a/subsys/nrf_security/Kconfig b/subsys/nrf_security/Kconfig
index db616e07b690..2da3f5647fb0 100644
--- a/subsys/nrf_security/Kconfig
+++ b/subsys/nrf_security/Kconfig
@@ -55,6 +55,13 @@ rsource "Kconfig.psa.nordic"
 config PSA_PROMPTLESS
 	bool
 
+config SSF_V_2
+	bool
+	default y if BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON
+	prompt "temporary option until iron and SSFv2 is available"
+	select MBOX
+	select IPC_SERVICE
+
 if NRF_SECURITY
 
 config MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS
diff --git a/subsys/nrf_security/src/ssf_secdom/CMakeLists.txt b/subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
index d13ee5b0c99c..32ad96703db8 100644
--- a/subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
+++ b/subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
@@ -4,8 +4,33 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+  zephyr_library()
+  zephyr_library_sources(
+    # ironside_psa_ns_api.c provides psa_call. psa_call is invoked by
+    # serialized functions from tfm_crypto_api.c and sends a message
+    # over IPC.
+    ${CMAKE_CURRENT_LIST_DIR}/ironside_se_psa_ns_api.c
+    # ironside_se_psa_ns_ipc.c provides an IPC service to ironside_se_psa_ns_api.c
+    ${CMAKE_CURRENT_LIST_DIR}/ironside_se_psa_ns_ipc.c
+    # tfm_crypto_api.c provides and serializes the PSA Crypto API.
+    ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/src/tfm_crypto_api.c
+    )
+
+  zephyr_library_include_directories(
+    ${NRF_DIR}/include/tfm
+    .
+    )
+
+  if(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS)
+    zephyr_library_sources(
+      ${CMAKE_CURRENT_LIST_DIR}/bounce_buffers.c
+      )
+  endif()
+else()
 target_sources(${mbedcrypto_target}
   PRIVATE
     ${CMAKE_CURRENT_LIST_DIR}/ssf_crypto.c
     ${CMAKE_CURRENT_LIST_DIR}/ssf_psa_core_compatibility.c
 )
+endif()
diff --git a/subsys/nrf_security/src/ssf_secdom/Kconfig b/subsys/nrf_security/src/ssf_secdom/Kconfig
index 6c707a909ff7..4355e884e114 100644
--- a/subsys/nrf_security/src/ssf_secdom/Kconfig
+++ b/subsys/nrf_security/src/ssf_secdom/Kconfig
@@ -8,4 +8,33 @@ config PSA_SSF_CRYPTO_CLIENT
 	bool
 	prompt "PSA crypto provided through SSF"
 	default y
-	depends on SSF_CLIENT && SSF_PSA_CRYPTO_SERVICE_ENABLED
+	depends on (SSF_CLIENT || SSF_V_2) && SSF_PSA_CRYPTO_SERVICE_ENABLED
+
+if PSA_SSF_CRYPTO_CLIENT
+
+config PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+	bool "Support PSA crypto with output buffers that are not cache-safe"
+	default y
+	depends on DCACHE
+	help
+	  When this option is enabled, the PSA Crypto service will
+	  allocate bounce buffers for all PSA output vectors that are not
+	  aligned to the DCache DataUnit size. When this option is
+	  disabled, the PSA Crypto service will never use bounce buffers,
+	  and the user of PSA APIs must ensure that the structures are
+	  cache-safe. The structures are cache-safe if there are no writes
+	  locally to any of the DataUnits that contain the structure
+	  getting written from the remote.
+
+if PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+
+config PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE
+	int "Size of the heap used to buffer output from PSA function calls"
+	default 4096
+	help
+	  Size of the heap buffer used for out buffer.
+	  Reducing the size may trigger PSA_ERROR_INSUFFICIENT_MEMORY in PSA calls.
+
+endif # PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+
+endif # PSA_SSF_CRYPTO_CLIENT
diff --git a/subsys/nrf_security/src/ssf_secdom/bounce_buffers.c b/subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
new file mode 100644
index 000000000000..ab5e06ed7b30
--- /dev/null
+++ b/subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+void *bounce_buffers_prepare(void *original_buffer, size_t size)
+{
+	void *out_buffer = NULL;
+
+	if (((IS_ALIGNED(original_buffer, CACHE_DATA_UNIT_SIZE)) &&
+		(IS_ALIGNED(size, CACHE_DATA_UNIT_SIZE))) ||
+	    (size == 0)) {
+		out_buffer = original_buffer;
+	} else {
+		out_buffer = k_heap_alloc(&out_buffer_heap, size, K_NO_WAIT);
+		if (out_buffer != NULL) {
+			memcpy(out_buffer, original_buffer, size);
+		}
+	}
+
+	return out_buffer;
+}
+
+void bounce_buffers_release(void *original_buffer, void *out_buffer, size_t size)
+{
+	if (out_buffer == NULL || out_buffer == original_buffer) {
+		return;
+	}
+
+	memcpy(original_buffer, out_buffer, size);
+	/* Clear buffer before returning it to not leak sensitive data */
+	memset(out_buffer, 0, size);
+	sys_cache_data_flush_range(out_buffer, size);
+	k_heap_free(&out_buffer_heap, out_buffer);
+}
diff --git a/subsys/nrf_security/src/ssf_secdom/bounce_buffers.h b/subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
new file mode 100644
index 000000000000..1c4b57e8c48f
--- /dev/null
+++ b/subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __BOUNCE_BUFFERS_H__
+#define __BOUNCE_BUFFERS_H__
+
+#include <nrfx.h>
+
+#define CACHE_DATA_UNIT_SIZE (DCACHEDATA_DATAWIDTH * 4)
+
+#ifdef CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+
+/**
+ * @brief Prepare an out buffer in case the original buffer is not aligned
+ *
+ * If the original buffer is not aligned, a new buffer is allocated and the data is copied to it.
+ * This is needed to achieve DCache DataUnit alignment.
+ *
+ * @param original_buffer Original buffer
+ * @param size Size of the buffer
+ * @return void* NULL if the buffer could not be allocated, original_buffer if it was aligned, else
+ * a new buffer from the heap
+ *
+ */
+void *bounce_buffers_prepare(void *original_buffer, size_t size);
+
+/**
+ * @brief Release an out buffer if it was allocated
+ *
+ * If the out buffer was allocated, the data is copied back to the original buffer and the out
+ * buffer is first zeroed and then freed.
+ *
+ * @param original_buffer The original buffer
+ * @param out_buffer The buffer to release
+ * @param size Size of the buffer
+ */
+void bounce_buffers_release(void *original_buffer, void *out_buffer, size_t size);
+
+#else /* CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS */
+
+NRF_STATIC_INLINE
+void *bounce_buffers_prepare(void *original_buffer, size_t size)
+{
+	ARG_UNUSED(size);
+
+	return original_buffer;
+}
+
+NRF_STATIC_INLINE
+void bounce_buffers_release(void *original_buffer, void *out_buffer, size_t size)
+{
+	ARG_UNUSED(original_buffer);
+	ARG_UNUSED(out_buffer);
+	ARG_UNUSED(size);
+}
+
+#endif  /* CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS */
+
+#endif /* __BOUNCE_BUFFERS_H__ */
diff --git a/subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_api.c b/subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_api.c
new file mode 100644
index 000000000000..55a6b2d33992
--- /dev/null
+++ b/subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_api.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/ironside/se/ipc_service.h>
+
+#include "ironside_se_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+static psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+						  const psa_invec *in_vec, size_t in_len,
+						  psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = ironside_se_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[IRONSIDE_SE_IPC_DATA_LEN];
+
+	ipc_service_buf[IRONSIDE_SE_IPC_INDEX_HANDLE] =
+		handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
+	ipc_service_buf[IRONSIDE_SE_IPC_INDEX_IN_VEC] = (uint32_t)in_vec;
+	ipc_service_buf[IRONSIDE_SE_IPC_INDEX_IN_LEN] = in_len;
+	ipc_service_buf[IRONSIDE_SE_IPC_INDEX_OUT_VEC] = (uint32_t)out_vec;
+	ipc_service_buf[IRONSIDE_SE_IPC_INDEX_OUT_LEN] = out_len;
+	ipc_service_buf[IRONSIDE_SE_IPC_INDEX_STATUS_PTR] = (uint32_t)&status;
+
+	int32_t ret = ironside_se_psa_ns_ipc_send(ipc_service_buf, sizeof(ipc_service_buf));
+
+	if (ret != sizeof(ipc_service_buf)) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	do {
+		sys_cache_data_flush_and_invd_range((void *)&status, sizeof(status));
+	} while (status == PSA_ERROR_COMMUNICATION_FAILURE);
+
+	return status;
+}
+
+/*
+ * Addresses that the cpusec reads and/or writes must be flushed
+ * before the PSA call.
+ *
+ * After the PSA call, any address that the cpusec may have written to
+ * must be flushed and invalidated.
+ */
+static psa_status_t psa_call_buffered(psa_handle_t handle, int32_t type, const psa_invec *in_vec,
+				      size_t in_len, psa_outvec *out_vec, size_t out_len)
+{
+	for (int i = 0; i < out_len; i++) {
+		sys_cache_data_flush_range((void *)out_vec[i].base, out_vec[i].len);
+	}
+
+	for (int i = 0; i < in_len; i++) {
+		sys_cache_data_flush_range((void *)in_vec[i].base, in_vec[i].len);
+	}
+
+	sys_cache_data_flush_range((void *)in_vec, in_len * sizeof(in_vec[0]));
+	sys_cache_data_flush_range((void *)out_vec, out_len * sizeof(out_vec[0]));
+
+	psa_status_t status =
+		psa_call_buffered_and_flushed(handle, type, in_vec, in_len, out_vec, out_len);
+
+	for (int i = 0; i < out_len; i++) {
+		sys_cache_data_flush_and_invd_range(out_vec[i].base, out_vec[i].len);
+	}
+
+	/* cpusec may write the number of bytes writen to out_vec[i].len */
+	sys_cache_data_flush_and_invd_range((void *)out_vec, out_len * sizeof(out_vec[0]));
+
+	return status;
+}
+
+/*
+ * Both the start address and end address of buffers that the cpusec
+ * writes must be 4-byte aligned. bounce_buffers, when enabled with
+ * PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS, will correct the
+ * alignment by buffering such buffers when necessary.
+ */
+psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
+		      psa_outvec *out_vec, size_t out_len)
+{
+	if (in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) {
+		return PSA_ERROR_PROGRAMMER_ERROR;
+	}
+
+	psa_status_t status;
+
+	psa_outvec out_vec_copy[out_len];
+
+	memcpy(out_vec_copy, out_vec, sizeof(out_vec_copy));
+
+	for (int i = 0; i < out_len; i++) {
+		out_vec_copy[i].base = bounce_buffers_prepare(out_vec[i].base, out_vec[i].len);
+		if (out_vec_copy[i].base == NULL) {
+			status = PSA_ERROR_INSUFFICIENT_MEMORY;
+			goto exit;
+		}
+	}
+
+	status = psa_call_buffered(handle, type, in_vec, in_len, out_vec_copy, out_len);
+
+exit:
+	for (int i = 0; i < out_len; i++) {
+		bounce_buffers_release(out_vec[i].base, out_vec_copy[i].base, out_vec[i].len);
+
+		out_vec[i].len = out_vec_copy[i].len;
+	}
+
+	return status;
+}
diff --git a/subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_ipc.c b/subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_ipc.c
new file mode 100644
index 000000000000..abe1c167515c
--- /dev/null
+++ b/subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_ipc.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/ipc/ipc_service.h>
+
+#include <psa/error.h>
+
+static void ept_bound(void *priv)
+{
+}
+
+static void ept_recv(const void *data, size_t len, void *priv)
+{
+}
+
+static struct ipc_ept_cfg ept_cfg = {
+	.name = "cpusec_cpuapp_ipc_ept",
+	.cb = {
+			.bound = ept_bound,
+			.received = ept_recv,
+		},
+};
+
+static struct ipc_ept ept;
+
+psa_status_t ironside_se_psa_ns_ipc_setup(void)
+{
+	static bool initialized;
+
+	if (initialized) {
+		return PSA_SUCCESS;
+	}
+
+	const struct device *instance = DEVICE_DT_GET(DT_NODELABEL(cpusec_cpuapp_ipc));
+
+	int ret = ipc_service_open_instance(instance);
+
+	if (ret < 0) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	ret = ipc_service_register_endpoint(instance, &ept, &ept_cfg);
+	if (ret < 0) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	initialized = true;
+
+	return PSA_SUCCESS;
+}
+
+int32_t ironside_se_psa_ns_ipc_send(uint32_t *buf, size_t buf_len)
+{
+	return ipc_service_send(&ept, buf, buf_len);
+}
diff --git a/subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_ipc.h b/subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_ipc.h
new file mode 100644
index 000000000000..6c4d788b49c4
--- /dev/null
+++ b/subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_ipc.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __CONFIG_SDFW_PSA_NS_IPC_H__
+#define __CONFIG_SDFW_PSA_NS_IPC_H__
+
+#include <stdint.h>
+
+#include <psa/error.h>
+
+/* Provides IPC services to ironside_se_ps_ns_api.c */
+
+/*
+ * setup must be called before send.
+ *
+ * successive calls to setup will have no effect.
+ */
+psa_status_t ironside_se_psa_ns_ipc_setup(void);
+
+/*
+ * A thin wrapper on top of ipc_service_send.
+ *
+ * See ipc_service_send for return codes etc.
+ */
+int32_t ironside_se_psa_ns_ipc_send(uint32_t *buf, size_t buf_len);
+
+#endif /* __CONFIG_SDFW_PSA_NS_IPC_H__ */
diff --git a/subsys/nrf_security/src/ssf_secdom/psa_manifest/sid.h b/subsys/nrf_security/src/ssf_secdom/psa_manifest/sid.h
new file mode 100644
index 000000000000..5096ce6d1b7d
--- /dev/null
+++ b/subsys/nrf_security/src/ssf_secdom/psa_manifest/sid.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __PSA_MANIFEST_SID_H__
+#define __PSA_MANIFEST_SID_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* sid.h symbols are provided by ironside/se/ipc_service.h  */
+#include <tfm/ironside/se/ipc_service.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_MANIFEST_SID_H__ */
diff --git a/subsys/sdfw_services/Kconfig b/subsys/sdfw_services/Kconfig
index 57b3982c80a7..2db9d1906967 100644
--- a/subsys/sdfw_services/Kconfig
+++ b/subsys/sdfw_services/Kconfig
@@ -7,8 +7,9 @@
 rsource "services/Kconfig"
 
 config SSF_CLIENT
-	def_bool $(dt_nodelabel_enabled_with_compat,cpusec_cpuapp_ipc,$(DT_COMPAT_ZEPHYR_IPC_ICMSG)) \
-	      || $(dt_nodelabel_enabled_with_compat,cpusec_cpurad_ipc,$(DT_COMPAT_ZEPHYR_IPC_ICMSG))
+	bool
+	default (! SSF_V_2) && ($(dt_nodelabel_enabled_with_compat,cpusec_cpuapp_ipc,$(DT_COMPAT_ZEPHYR_IPC_ICMSG)) \
+	      || $(dt_nodelabel_enabled_with_compat,cpusec_cpurad_ipc,$(DT_COMPAT_ZEPHYR_IPC_ICMSG)))
 
 config SDFW_SERVICES_ENABLED
 	bool
diff --git a/subsys/sdfw_services/services/Kconfig.template.service b/subsys/sdfw_services/services/Kconfig.template.service
index 2dbe37cd238b..e27911464e97 100644
--- a/subsys/sdfw_services/services/Kconfig.template.service
+++ b/subsys/sdfw_services/services/Kconfig.template.service
@@ -22,7 +22,7 @@
 menuconfig SSF_$(service_name)_SERVICE_ENABLED
 	bool "$(service_name_str) service"
 	default y if $(service_default_enabled)
-	depends on SDFW_SERVICES_ENABLED
+	depends on SDFW_SERVICES_ENABLED || SSF_V_2
 
 if SSF_$(service_name)_SERVICE_ENABLED
 


Reviews:
user: login: karstenkoenig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T08:59:12Z
user: login: hakonfam
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T11:10:24Z
user: login: karstenkoenig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T11:14:39Z
user: login: karstenkoenig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T11:15:42Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:23:24Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:27:01Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:28:08Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:29:44Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:56:16Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T15:58:33Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:04:53Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:06:45Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:15:56Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:16:25Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:22:36Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:22:49Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:22:54Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:25:52Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:26:23Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:28:38Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:29:39Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:29:51Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T16:30:23Z
user: login: karstenkoenig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T17:48:57Z
user: login: karstenkoenig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T17:51:32Z
user: login: karstenkoenig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T06:30:55Z
user: login: jonathannilsen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T06:33:06Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T06:50:23Z
user: login: jonathannilsen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T06:52:04Z
user: login: hakonfam
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T08:57:00Z
user: login: karstenkoenig
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T09:43:24Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:24:24Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:30:32Z
user: login: jonathannilsen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:33:52Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:41:35Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:43:49Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:44:15Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:44:50Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:45:00Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T14:28:58Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T14:30:42Z
user: login: jonathannilsen
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T14:38:21Z
user: login: hakonfam
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T04:33:54Z
user: login: karstenkoenig
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T07:58:36Z
user: login: nordicjm
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T12:02:39Z
user: login: nordicjm
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T12:03:10Z
user: login: nordicjm
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T12:04:25Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T12:06:59Z
user: login: SebastianBoe
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T12:11:34Z
user: login: nordicjm
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T12:36:59Z
user: login: Vge0rge
body: The nrf_security parts look ok. Only a nit with copyrights which can be addressed later.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T08:19:34Z

Review comments:
diff_hunk: @@ -0,0 +1,58 @@
+/*
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
user: login: karstenkoenig
body: no include guard?
created_at: 2025-04-07T08:45:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_ipc.h
user: login: karstenkoenig
body: missing include guards
created_at: 2025-04-07T08:46:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#pragma once
path: include/tfm/sdfw_psa_ipc_service.h
user: login: karstenkoenig
body: pragma vs regular include guard, I think we usually do ifndef style
created_at: 2025-04-07T08:47:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#pragma once
+
+/*
+ * This header contains symbols that are used by both the SDFW client
+ * and the SDFW service.
+ */
+
+/* Number of uint32_t words in the data sent over ipc_service */
+#define SDFW_PSA_IPC_DATA_LEN 6
+
+/* Usually provided by manifest/sid.h */
path: include/tfm/sdfw_psa_ipc_service.h
user: login: karstenkoenig
body: This isn't a very informative comment, sid.h even includes this file here?
created_at: 2025-04-07T08:51:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
+	ipc_service_buf[1] = (uint32_t)in_vec;
+	ipc_service_buf[2] = in_len;
+	ipc_service_buf[3] = (uint32_t)out_vec;
+	ipc_service_buf[4] = out_len;
+	ipc_service_buf[5] = (uint32_t)&status;
+
+	int32_t ret = sdfw_psa_ns_ipc_send(ipc_service_buf, sizeof(ipc_service_buf));
+
+	if (ret != sizeof(ipc_service_buf)) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	do {
+		sys_cache_data_flush_and_invd_range((void *)&status, sizeof(status));
+	} while (status == PSA_ERROR_COMMUNICATION_FAILURE);
+
+	return status;
+}
+
+/*
+ * Addresses that the cpusec reads and/or writes must be flushed
+ * before the PSA call.
+ *
+ * After the PSA call, any address that the cpusec may have written to
+ * must be flushed and invalidated.
+ */
+psa_status_t psa_call_buffered(psa_handle_t handle, int32_t type, const psa_invec *in_vec,
+			       size_t in_len, psa_outvec *out_vec, size_t out_len)
+{
+	for (int i = 0; i < out_len; i++) {
+		sys_cache_data_flush_range((void *)out_vec[i].base, out_vec[i].len);
+	}
+
+	for (int i = 0; i < in_len; i++) {
+		sys_cache_data_flush_range((void *)in_vec[i].base, in_vec[i].len);
+	}
+
+	sys_cache_data_flush_range((void *)in_vec, in_len * sizeof(in_vec[0]));
+	sys_cache_data_flush_range((void *)out_vec, out_len * sizeof(out_vec[0]));
+
+	psa_status_t status =
+		psa_call_buffered_and_flushed(handle, type, in_vec, in_len, out_vec, out_len);
+
+	for (int i = 0; i < out_len; i++) {
+		sys_cache_data_flush_and_invd_range(out_vec[i].base, out_vec[i].len);
+	}
+
+	/* cpusec may write the number of bytes writen to out_vec[i].len */
+	sys_cache_data_flush_and_invd_range((void *)out_vec, out_len * sizeof(out_vec[0]));
+
+	return status;
+}
+
+/*
+ * Both the start address and end address of buffers that the cpusec
+ * writes must be 4-byte aligned. bounce_buffers, when enabled with
+ * PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS, will correct the
+ * alignment by buffering such buffers when necessary.
+ */
+psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
+		      psa_outvec *out_vec, size_t out_len)
+{
+	if (in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) {
+		return PSA_ERROR_PROGRAMMER_ERROR;
+	}
+
+	psa_status_t status;
+
+	psa_outvec out_vec_copy[out_len];
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: karstenkoenig
body: how does this work? doesn't the declaration need to have a constant size at build time? 
created_at: 2025-04-07T08:53:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: karstenkoenig
body: Could the status be transported inside the ipc call response? I think that'd be cleaner than handing this stack variable over
created_at: 2025-04-07T08:56:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: karstenkoenig
body: wait this is a constant? Isn't this used to have multiple concurrent multi-part operations?
created_at: 2025-04-07T08:58:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
+	ipc_service_buf[1] = (uint32_t)in_vec;
+	ipc_service_buf[2] = in_len;
+	ipc_service_buf[3] = (uint32_t)out_vec;
+	ipc_service_buf[4] = out_len;
+	ipc_service_buf[5] = (uint32_t)&status;
+
+	int32_t ret = sdfw_psa_ns_ipc_send(ipc_service_buf, sizeof(ipc_service_buf));
+
+	if (ret != sizeof(ipc_service_buf)) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	do {
+		sys_cache_data_flush_and_invd_range((void *)&status, sizeof(status));
+	} while (status == PSA_ERROR_COMMUNICATION_FAILURE);
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: karstenkoenig
body: I hope the new ipc layer will provide a more robust waiting mechanism for a blocking call, can you maybe leave a comment about this being removed once there is a blocking call implemented?
created_at: 2025-04-07T08:59:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,20 @@
+/*
path: include/tfm/sdfw_psa_ipc_service.h
user: login: hakonfam
body: Why is this file located under `include/tfm` ?
created_at: 2025-04-07T10:59:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,8 +4,36 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+target_sources(${mbedcrypto_target}
+  PRIVATE
+  # sdfw_psa_ns_api.c provides psa_call. psa_call is invoked by
+  # serialized functions from tfm_crypto_api.c and sends a message
+  # over IPC.
+  ${CMAKE_CURRENT_LIST_DIR}/sdfw_psa_ns_api.c
+  # sdfw_psa_ns_ipc.c provides an IPC service to sdfw_psa_ns_api.c
+  ${CMAKE_CURRENT_LIST_DIR}/sdfw_psa_ns_ipc.c
+  # tfm_crypto_api.c provides and serializes the PSA Crypto API.
+  ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/src/tfm_crypto_api.c
+  )
+
+target_include_directories(${mbedcrypto_target}
+  PRIVATE
+  ${NRF_DIR}/include/tfm
+  .
+  )
+
+if(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS)
+target_sources(${mbedcrypto_target}
path: subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
user: login: hakonfam
body: Missing indentation?
created_at: 2025-04-07T11:00:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,8 +4,36 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+target_sources(${mbedcrypto_target}
path: subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
user: login: hakonfam
body: Missing indentation?

Also, why are we not using `zephyr_` cmake functions for adding sources and include dirs?
created_at: 2025-04-07T11:01:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,4 +8,31 @@ config PSA_SSF_CRYPTO_CLIENT
 	bool
 	prompt "PSA crypto provided through SSF"
 	default y
-	depends on SSF_CLIENT && SSF_PSA_CRYPTO_SERVICE_ENABLED
+	depends on (SSF_CLIENT || SSF_V_2) && SSF_PSA_CRYPTO_SERVICE_ENABLED
+
+if PSA_SSF_CRYPTO_CLIENT
+
+config PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+	bool "Make sure that all output vectors can be written cache-safe from the crypto engine"
+	default y
+	depends on DCACHE
+	help
+		When this option is enabled, the PSA Crypto service will allocate bounce buffers for
path: subsys/nrf_security/src/ssf_secdom/Kconfig
user: login: hakonfam
body: nit: indentation seems off
created_at: 2025-04-07T11:01:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,4 +8,31 @@ config PSA_SSF_CRYPTO_CLIENT
 	bool
 	prompt "PSA crypto provided through SSF"
 	default y
-	depends on SSF_CLIENT && SSF_PSA_CRYPTO_SERVICE_ENABLED
+	depends on (SSF_CLIENT || SSF_V_2) && SSF_PSA_CRYPTO_SERVICE_ENABLED
+
+if PSA_SSF_CRYPTO_CLIENT
+
+config PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+	bool "Make sure that all output vectors can be written cache-safe from the crypto engine"
path: subsys/nrf_security/src/ssf_secdom/Kconfig
user: login: hakonfam
body: Should we even have a prompt here? I guess no users want to manually verify that all of their buffers are aligned sufficiently.
created_at: 2025-04-07T11:02:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <nrf.h>
+#include <nrfx.h>
+
+#define CACHE_DATA_UNIT_SIZE (DCACHEDATA_DATAWIDTH * 4)
+
+#ifdef CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
user: login: hakonfam
body: Do we need this? Wouldn't it suffice to use wrap the invocation of these functions with `IS_ENABLED` on the caller side?
created_at: 2025-04-07T11:04:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: hakonfam
body: Do we need to round up when we have ensured the alignment above? Could this result in spending more memory than the user has configured?
created_at: 2025-04-07T11:05:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+/**
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: hakonfam
body: Public functions are typically documented in the header file, not in the .c file.
created_at: 2025-04-07T11:05:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+/**
+ * @brief Prepare an out buffer in case the original buffer is not aligned
+ *
+ * If the original buffer is not aligned, a new buffer is allocated and the data is copied to it.
+ * This is needed to achieve DCache DataUnit alignment.
+ *
+ * @param original_buffer Original buffer
+ * @param size Size of the buffer
+ * @return void* NULL if the buffer could not be allocated, original_buffer if it was aligned, else
+ * a new buffer from the heap
+ *
+ */
+void *bounce_buffers_prepare(void *original_buffer, size_t size)
+{
+	void *out_buffer;
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: hakonfam
body: Shouldn't this be set explicitly to NULL?
created_at: 2025-04-07T11:07:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: hakonfam
body: Should we move this to the .h file to make the .c file easier to read?
created_at: 2025-04-07T11:09:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
+	ipc_service_buf[1] = (uint32_t)in_vec;
+	ipc_service_buf[2] = in_len;
+	ipc_service_buf[3] = (uint32_t)out_vec;
+	ipc_service_buf[4] = out_len;
+	ipc_service_buf[5] = (uint32_t)&status;
+
+	int32_t ret = sdfw_psa_ns_ipc_send(ipc_service_buf, sizeof(ipc_service_buf));
+
+	if (ret != sizeof(ipc_service_buf)) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	do {
+		sys_cache_data_flush_and_invd_range((void *)&status, sizeof(status));
+	} while (status == PSA_ERROR_COMMUNICATION_FAILURE);
+
+	return status;
+}
+
+/*
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: hakonfam
body: Docs should go to header file.
created_at: 2025-04-07T11:09:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,61 @@
+/*
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_ipc.c
user: login: hakonfam
body: not reviewed
created_at: 2025-04-07T11:10:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,4 +8,31 @@ config PSA_SSF_CRYPTO_CLIENT
 	bool
 	prompt "PSA crypto provided through SSF"
 	default y
-	depends on SSF_CLIENT && SSF_PSA_CRYPTO_SERVICE_ENABLED
+	depends on (SSF_CLIENT || SSF_V_2) && SSF_PSA_CRYPTO_SERVICE_ENABLED
+
+if PSA_SSF_CRYPTO_CLIENT
+
+config PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+	bool "Make sure that all output vectors can be written cache-safe from the crypto engine"
path: subsys/nrf_security/src/ssf_secdom/Kconfig
user: login: karstenkoenig
body: They could also just take the risk tbh, it really is hard to write into the same dataunit (4 bytes) from the client side as the server side. It allows skipping a copy of the data so can significantly reduce overhead, including the 4K extra heap. 
created_at: 2025-04-07T11:14:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: karstenkoenig
body: it's if CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE is not dividable by 4, you run risk of the linker putting something into the 'leftover' space. Unlikely, but for correctness should be done, it'll be max 3 bytes more than configured for a buffer that is probably at least 1K
created_at: 2025-04-07T11:15:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
+	ipc_service_buf[1] = (uint32_t)in_vec;
+	ipc_service_buf[2] = in_len;
+	ipc_service_buf[3] = (uint32_t)out_vec;
+	ipc_service_buf[4] = out_len;
+	ipc_service_buf[5] = (uint32_t)&status;
+
+	int32_t ret = sdfw_psa_ns_ipc_send(ipc_service_buf, sizeof(ipc_service_buf));
+
+	if (ret != sizeof(ipc_service_buf)) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	do {
+		sys_cache_data_flush_and_invd_range((void *)&status, sizeof(status));
+	} while (status == PSA_ERROR_COMMUNICATION_FAILURE);
+
+	return status;
+}
+
+/*
+ * Addresses that the cpusec reads and/or writes must be flushed
+ * before the PSA call.
+ *
+ * After the PSA call, any address that the cpusec may have written to
+ * must be flushed and invalidated.
+ */
+psa_status_t psa_call_buffered(psa_handle_t handle, int32_t type, const psa_invec *in_vec,
+			       size_t in_len, psa_outvec *out_vec, size_t out_len)
+{
+	for (int i = 0; i < out_len; i++) {
+		sys_cache_data_flush_range((void *)out_vec[i].base, out_vec[i].len);
+	}
+
+	for (int i = 0; i < in_len; i++) {
+		sys_cache_data_flush_range((void *)in_vec[i].base, in_vec[i].len);
+	}
+
+	sys_cache_data_flush_range((void *)in_vec, in_len * sizeof(in_vec[0]));
+	sys_cache_data_flush_range((void *)out_vec, out_len * sizeof(out_vec[0]));
+
+	psa_status_t status =
+		psa_call_buffered_and_flushed(handle, type, in_vec, in_len, out_vec, out_len);
+
+	for (int i = 0; i < out_len; i++) {
+		sys_cache_data_flush_and_invd_range(out_vec[i].base, out_vec[i].len);
+	}
+
+	/* cpusec may write the number of bytes writen to out_vec[i].len */
+	sys_cache_data_flush_and_invd_range((void *)out_vec, out_len * sizeof(out_vec[0]));
+
+	return status;
+}
+
+/*
+ * Both the start address and end address of buffers that the cpusec
+ * writes must be 4-byte aligned. bounce_buffers, when enabled with
+ * PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS, will correct the
+ * alignment by buffering such buffers when necessary.
+ */
+psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
+		      psa_outvec *out_vec, size_t out_len)
+{
+	if (in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) {
+		return PSA_ERROR_PROGRAMMER_ERROR;
+	}
+
+	psa_status_t status;
+
+	psa_outvec out_vec_copy[out_len];
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: SebastianBoe
body: I was a bit worried the compiler would put in a malloc here.

But I see that it modifies the stack pointer to have the stack usage be dynamic based on the size of out_len. (See the mov instruction modifying sp (stack pointer)).

In the general case dynamic stack size is scary. But in this case out_len is verified to be small, and sizeof(psa_outvec) is  small so we are only dynamically increasing the stack size a little bit.

![image](https://github.com/user-attachments/assets/05a19463-3fc7-4243-a331-b38289193054)
https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
created_at: 2025-04-07T15:23:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: SebastianBoe
body: I think so, I am looking forward to seeing what IRONcall can do :)
created_at: 2025-04-07T15:27:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: SebastianBoe
body: operation->handle is for multi-part operations.

It is unfortunate that TF-M used the word handle for these two different things.

It will be one value for PSA Crypto, and another value for PSA ITS.
created_at: 2025-04-07T15:28:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
+	ipc_service_buf[1] = (uint32_t)in_vec;
+	ipc_service_buf[2] = in_len;
+	ipc_service_buf[3] = (uint32_t)out_vec;
+	ipc_service_buf[4] = out_len;
+	ipc_service_buf[5] = (uint32_t)&status;
+
+	int32_t ret = sdfw_psa_ns_ipc_send(ipc_service_buf, sizeof(ipc_service_buf));
+
+	if (ret != sizeof(ipc_service_buf)) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	do {
+		sys_cache_data_flush_and_invd_range((void *)&status, sizeof(status));
+	} while (status == PSA_ERROR_COMMUNICATION_FAILURE);
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: SebastianBoe
body: I'm pretty sure this will be completely rewritten when we get the new ipc layer so there is no risk and no need for a comment IMHO.
created_at: 2025-04-07T15:29:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,20 @@
+/*
path: include/tfm/sdfw_psa_ipc_service.h
user: login: SebastianBoe
body: As mentioned in the comment below, this header contains defines that are required by both the server and the client.

The server adds tf-m sources and therefore needs TF-M headers from nrf/include/tfm.

Since the server is already adding this directory, I figured this was a good place to put this header.

Otherwise I would need to add 2 different nrf directories to the server's build.

![image](https://github.com/user-attachments/assets/022953db-0f53-4d84-a3e6-5fa84163d13a)

created_at: 2025-04-07T15:56:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,8 +4,36 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+target_sources(${mbedcrypto_target}
path: subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
user: login: SebastianBoe
body: It's intentionally missing to make the diff smaller when we drop support for SUIT and delete the if(CONFIG_SSF_V_2).

target_sources is used because that is what the existing ssf_secdom build scripts used.

I don't know why they use target_sources.
created_at: 2025-04-07T15:58:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,4 +8,31 @@ config PSA_SSF_CRYPTO_CLIENT
 	bool
 	prompt "PSA crypto provided through SSF"
 	default y
-	depends on SSF_CLIENT && SSF_PSA_CRYPTO_SERVICE_ENABLED
+	depends on (SSF_CLIENT || SSF_V_2) && SSF_PSA_CRYPTO_SERVICE_ENABLED
+
+if PSA_SSF_CRYPTO_CLIENT
+
+config PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+	bool "Make sure that all output vectors can be written cache-safe from the crypto engine"
path: subsys/nrf_security/src/ssf_secdom/Kconfig
user: login: SebastianBoe
body: I agree with Karsten.

I think it will be quite common to try to save the 4kB and the runtime cost of buffering.

I don't think it would be very difficult for a customer to examine every PSA call in their image.
created_at: 2025-04-07T16:04:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <nrf.h>
+#include <nrfx.h>
+
+#define CACHE_DATA_UNIT_SIZE (DCACHEDATA_DATAWIDTH * 4)
+
+#ifdef CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
user: login: SebastianBoe
body: bounce_buffers is very simple.

I'd rather make bounce_buffers a little bit more complicated than to make the users code a little more complicated.

This is also consistent with Karsten's implemenation.
created_at: 2025-04-07T16:06:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: SebastianBoe
body: sdfw_psa_ns_api.c doesn't have a sdfw_psa_ns_api.h as it implements the standardized function psa_call.
created_at: 2025-04-07T16:15:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
+	ipc_service_buf[1] = (uint32_t)in_vec;
+	ipc_service_buf[2] = in_len;
+	ipc_service_buf[3] = (uint32_t)out_vec;
+	ipc_service_buf[4] = out_len;
+	ipc_service_buf[5] = (uint32_t)&status;
+
+	int32_t ret = sdfw_psa_ns_ipc_send(ipc_service_buf, sizeof(ipc_service_buf));
+
+	if (ret != sizeof(ipc_service_buf)) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	do {
+		sys_cache_data_flush_and_invd_range((void *)&status, sizeof(status));
+	} while (status == PSA_ERROR_COMMUNICATION_FAILURE);
+
+	return status;
+}
+
+/*
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: SebastianBoe
body: see https://github.com/nrfconnect/sdk-nrf/pull/21383#discussion_r2031586286
created_at: 2025-04-07T16:16:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+/*
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
user: login: SebastianBoe
body: fixed
created_at: 2025-04-07T16:22:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_ipc.h
user: login: SebastianBoe
body: fixed
created_at: 2025-04-07T16:22:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#pragma once
path: include/tfm/sdfw_psa_ipc_service.h
user: login: SebastianBoe
body: fixed
created_at: 2025-04-07T16:22:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,8 +4,36 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+target_sources(${mbedcrypto_target}
+  PRIVATE
+  # sdfw_psa_ns_api.c provides psa_call. psa_call is invoked by
+  # serialized functions from tfm_crypto_api.c and sends a message
+  # over IPC.
+  ${CMAKE_CURRENT_LIST_DIR}/sdfw_psa_ns_api.c
+  # sdfw_psa_ns_ipc.c provides an IPC service to sdfw_psa_ns_api.c
+  ${CMAKE_CURRENT_LIST_DIR}/sdfw_psa_ns_ipc.c
+  # tfm_crypto_api.c provides and serializes the PSA Crypto API.
+  ${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/src/tfm_crypto_api.c
+  )
+
+target_include_directories(${mbedcrypto_target}
+  PRIVATE
+  ${NRF_DIR}/include/tfm
+  .
+  )
+
+if(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS)
+target_sources(${mbedcrypto_target}
path: subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
user: login: SebastianBoe
body: fixed
created_at: 2025-04-07T16:25:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,4 +8,31 @@ config PSA_SSF_CRYPTO_CLIENT
 	bool
 	prompt "PSA crypto provided through SSF"
 	default y
-	depends on SSF_CLIENT && SSF_PSA_CRYPTO_SERVICE_ENABLED
+	depends on (SSF_CLIENT || SSF_V_2) && SSF_PSA_CRYPTO_SERVICE_ENABLED
+
+if PSA_SSF_CRYPTO_CLIENT
+
+config PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+	bool "Make sure that all output vectors can be written cache-safe from the crypto engine"
+	default y
+	depends on DCACHE
+	help
+		When this option is enabled, the PSA Crypto service will allocate bounce buffers for
path: subsys/nrf_security/src/ssf_secdom/Kconfig
user: login: SebastianBoe
body: fixed
created_at: 2025-04-07T16:26:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <nrf.h>
+#include <nrfx.h>
+
+#define CACHE_DATA_UNIT_SIZE (DCACHEDATA_DATAWIDTH * 4)
+
+#ifdef CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
user: login: SebastianBoe
body: It's also consistent with the Zephyr cache API, which is the "other" API that the caller uses.

So the caller will be more consistent if we deal with this in bounce buffer.

We won't have IS_ENABLED for the bounce_buffers, and nothing for the cache flushing.
created_at: 2025-04-07T16:28:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+/**
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: SebastianBoe
body: Messy messy, sorry.
created_at: 2025-04-07T16:29:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+/**
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: SebastianBoe
body: fixed
created_at: 2025-04-07T16:29:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+/**
+ * @brief Prepare an out buffer in case the original buffer is not aligned
+ *
+ * If the original buffer is not aligned, a new buffer is allocated and the data is copied to it.
+ * This is needed to achieve DCache DataUnit alignment.
+ *
+ * @param original_buffer Original buffer
+ * @param size Size of the buffer
+ * @return void* NULL if the buffer could not be allocated, original_buffer if it was aligned, else
+ * a new buffer from the heap
+ *
+ */
+void *bounce_buffers_prepare(void *original_buffer, size_t size)
+{
+	void *out_buffer;
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: SebastianBoe
body: fixed
created_at: 2025-04-07T16:30:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
+	ipc_service_buf[1] = (uint32_t)in_vec;
+	ipc_service_buf[2] = in_len;
+	ipc_service_buf[3] = (uint32_t)out_vec;
+	ipc_service_buf[4] = out_len;
+	ipc_service_buf[5] = (uint32_t)&status;
+
+	int32_t ret = sdfw_psa_ns_ipc_send(ipc_service_buf, sizeof(ipc_service_buf));
+
+	if (ret != sizeof(ipc_service_buf)) {
+		return PSA_ERROR_COMMUNICATION_FAILURE;
+	}
+
+	do {
+		sys_cache_data_flush_and_invd_range((void *)&status, sizeof(status));
+	} while (status == PSA_ERROR_COMMUNICATION_FAILURE);
+
+	return status;
+}
+
+/*
+ * Addresses that the cpusec reads and/or writes must be flushed
+ * before the PSA call.
+ *
+ * After the PSA call, any address that the cpusec may have written to
+ * must be flushed and invalidated.
+ */
+psa_status_t psa_call_buffered(psa_handle_t handle, int32_t type, const psa_invec *in_vec,
+			       size_t in_len, psa_outvec *out_vec, size_t out_len)
+{
+	for (int i = 0; i < out_len; i++) {
+		sys_cache_data_flush_range((void *)out_vec[i].base, out_vec[i].len);
+	}
+
+	for (int i = 0; i < in_len; i++) {
+		sys_cache_data_flush_range((void *)in_vec[i].base, in_vec[i].len);
+	}
+
+	sys_cache_data_flush_range((void *)in_vec, in_len * sizeof(in_vec[0]));
+	sys_cache_data_flush_range((void *)out_vec, out_len * sizeof(out_vec[0]));
+
+	psa_status_t status =
+		psa_call_buffered_and_flushed(handle, type, in_vec, in_len, out_vec, out_len);
+
+	for (int i = 0; i < out_len; i++) {
+		sys_cache_data_flush_and_invd_range(out_vec[i].base, out_vec[i].len);
+	}
+
+	/* cpusec may write the number of bytes writen to out_vec[i].len */
+	sys_cache_data_flush_and_invd_range((void *)out_vec, out_len * sizeof(out_vec[0]));
+
+	return status;
+}
+
+/*
+ * Both the start address and end address of buffers that the cpusec
+ * writes must be 4-byte aligned. bounce_buffers, when enabled with
+ * PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS, will correct the
+ * alignment by buffering such buffers when necessary.
+ */
+psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
+		      psa_outvec *out_vec, size_t out_len)
+{
+	if (in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) {
+		return PSA_ERROR_PROGRAMMER_ERROR;
+	}
+
+	psa_status_t status;
+
+	psa_outvec out_vec_copy[out_len];
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: karstenkoenig
body: huh neat, good to know!
created_at: 2025-04-07T17:48:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include <psa/client.h>
+#include <psa/error.h>
+
+#include <tfm/sdfw_psa_ipc_service.h>
+
+#include "sdfw_psa_ns_ipc.h"
+#include "bounce_buffers.h"
+
+/* The correctness of the serialization depends on these asserts */
+BUILD_ASSERT(4 == sizeof(psa_handle_t));
+BUILD_ASSERT(4 == sizeof(int32_t));
+BUILD_ASSERT(4 == sizeof(const psa_invec *));
+BUILD_ASSERT(4 == sizeof(size_t));
+BUILD_ASSERT(4 == sizeof(psa_outvec *));
+BUILD_ASSERT(4 == sizeof(psa_status_t *));
+
+psa_status_t psa_call_buffered_and_flushed(psa_handle_t handle, int32_t type,
+					   const psa_invec *in_vec, size_t in_len,
+					   psa_outvec *out_vec, size_t out_len)
+{
+	/* We have no need for this at this time */
+	ARG_UNUSED(type);
+
+	psa_status_t ipc_status = sdfw_psa_ns_ipc_setup();
+
+	if (ipc_status != PSA_SUCCESS) {
+		return ipc_status;
+	}
+
+	/* volatile and flushed because the cpusec core will usually
+	 * modify this variable
+	 */
+	psa_status_t volatile status = PSA_ERROR_COMMUNICATION_FAILURE;
+	sys_cache_data_flush_range((void *)&status, sizeof(status));
+
+	uint32_t ipc_service_buf[SDFW_PSA_IPC_DATA_LEN];
+
+	ipc_service_buf[0] = handle; /* i.e. TFM_CRYPTO_HANDLE defined to 0x40000100U */
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: karstenkoenig
body: ah thanks!
created_at: 2025-04-07T17:51:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __BOUNCE_BUFFERS_H__
+#define __BOUNCE_BUFFERS_H__
+
+#include <nrf.h>
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
user: login: jonathannilsen
body: nit: nrf.h should already be included by nrfx.h, so I don't think this is needed
```suggestion
```
created_at: 2025-04-08T06:21:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __SDFW_PSA_IPC_SERVICE_H__
+#define __SDFW_PSA_IPC_SERVICE_H__
+
+/*
+ * This header contains symbols that are used by both the SDFW client
+ * and the SDFW service.
+ */
+enum {
+	INDEX_HANDLE,
+	INDEX_IN_VEC,
+	INDEX_IN_LEN,
+	INDEX_OUT_VEC,
+	INDEX_OUT_LEN,
+	INDEX_STATUS_PTR,
path: include/tfm/sdfw_psa_ipc_service.h
user: login: jonathannilsen
body: users won't be including this file, right (in which case these should probably be namespaced a bit more)?
created_at: 2025-04-08T06:26:42Z
author_association: CONTRIBUTOR
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: karstenkoenig
body: sdfw and secdom should be ironside
created_at: 2025-04-08T06:29:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __SDFW_PSA_IPC_SERVICE_H__
+#define __SDFW_PSA_IPC_SERVICE_H__
+
+/*
+ * This header contains symbols that are used by both the SDFW client
+ * and the SDFW service.
+ */
+enum {
+	INDEX_HANDLE,
+	INDEX_IN_VEC,
+	INDEX_IN_LEN,
+	INDEX_OUT_VEC,
+	INDEX_OUT_LEN,
+	INDEX_STATUS_PTR,
path: include/tfm/sdfw_psa_ipc_service.h
user: login: SebastianBoe
body: I'm starting to miss the old 0, 1, 2, 3 XD

ipc_service_buf[0]
vs
ipc_service_buf[SDFW_PSA_IPC_SERVICE_INDEX_STATUS_PTR]
created_at: 2025-04-08T06:50:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __SDFW_PSA_IPC_SERVICE_H__
+#define __SDFW_PSA_IPC_SERVICE_H__
+
+/*
+ * This header contains symbols that are used by both the SDFW client
+ * and the SDFW service.
+ */
+enum {
+	INDEX_HANDLE,
+	INDEX_IN_VEC,
+	INDEX_IN_LEN,
+	INDEX_OUT_VEC,
+	INDEX_OUT_LEN,
+	INDEX_STATUS_PTR,
path: include/tfm/sdfw_psa_ipc_service.h
user: login: jonathannilsen
body: I'm fine with either, as long as the use of the magic numbers is clear and centralized to one location (which they are in this case)
created_at: 2025-04-08T06:52:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,8 +4,36 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+target_sources(${mbedcrypto_target}
path: subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
user: login: hakonfam
body: Do we care about a small diff? (not being sarcastic here) In case we don't then you don't see any issues with using `zephyr_` functions?
created_at: 2025-04-08T08:52:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,4 +8,31 @@ config PSA_SSF_CRYPTO_CLIENT
 	bool
 	prompt "PSA crypto provided through SSF"
 	default y
-	depends on SSF_CLIENT && SSF_PSA_CRYPTO_SERVICE_ENABLED
+	depends on (SSF_CLIENT || SSF_V_2) && SSF_PSA_CRYPTO_SERVICE_ENABLED
+
+if PSA_SSF_CRYPTO_CLIENT
+
+config PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+	bool "Make sure that all output vectors can be written cache-safe from the crypto engine"
path: subsys/nrf_security/src/ssf_secdom/Kconfig
user: login: hakonfam
body: Then I guess the prompt needs an update. What about:

"Support PSA crypto with buffers that are not cache-safe" ?
created_at: 2025-04-08T08:54:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+void *bounce_buffers_prepare(void *original_buffer, size_t size)
+{
+	void *out_buffer = NULL;
+
+	if ((IS_ALIGNED(original_buffer, CACHE_DATA_UNIT_SIZE)) &&
+	    (IS_ALIGNED(size, CACHE_DATA_UNIT_SIZE))) {
+		out_buffer = original_buffer;
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: hakonfam
body: should we check if `original_buffer` is NULL here?
created_at: 2025-04-08T08:55:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+void *bounce_buffers_prepare(void *original_buffer, size_t size)
+{
+	void *out_buffer = NULL;
+
+	if ((IS_ALIGNED(original_buffer, CACHE_DATA_UNIT_SIZE)) &&
+	    (IS_ALIGNED(size, CACHE_DATA_UNIT_SIZE))) {
+		out_buffer = original_buffer;
+	} else {
+		out_buffer = k_heap_alloc(&out_buffer_heap, size, K_NO_WAIT);
+		if (out_buffer != NULL) {
+			memcpy(out_buffer, original_buffer, size);
+		}
+	}
+
+	return out_buffer;
+}
+
+void bounce_buffers_release(void *original_buffer, void *out_buffer, size_t size)
+{
+	if (out_buffer == NULL) {
+		return;
+	}
+
+	if (original_buffer == out_buffer) {
+		return;
+	}
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: hakonfam
body: nit
```suggestion
	if (out_buffer == NULL || original_buffer == out_buffer) {
		return;
	}
```
?
created_at: 2025-04-08T08:56:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+void *bounce_buffers_prepare(void *original_buffer, size_t size)
+{
+	void *out_buffer = NULL;
+
+	if ((IS_ALIGNED(original_buffer, CACHE_DATA_UNIT_SIZE)) &&
+	    (IS_ALIGNED(size, CACHE_DATA_UNIT_SIZE))) {
+		out_buffer = original_buffer;
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: karstenkoenig
body: Yea it might be best to just pass through null pointers and leave the dirty work the psa implementation.

Also you do need to check for 0 size, @magnev  just fixed that!
https://github.com/nrfconnect/sdk-nrf/pull/21354
created_at: 2025-04-08T09:43:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+void *bounce_buffers_prepare(void *original_buffer, size_t size)
+{
+	void *out_buffer = NULL;
+
+	if ((IS_ALIGNED(original_buffer, CACHE_DATA_UNIT_SIZE)) &&
+	    (IS_ALIGNED(size, CACHE_DATA_UNIT_SIZE))) {
+		out_buffer = original_buffer;
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: SebastianBoe
body: I looked at what happens if original_buffer is NULL.

There are two code paths.

In the first code path NULL is returned, and then the calling function returns PSA_ERROR_INSUFFICIENT_MEMORY.
I suppose that is reasonable.

In the second code path a memcpy will read from original_buffer, at which point IRONside should give us a memory access error report. Which is more useful than any kind of error handling I can think of.

IMHO this function shouldn't have special handling for NULL.
created_at: 2025-04-08T13:24:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __BOUNCE_BUFFERS_H__
+#define __BOUNCE_BUFFERS_H__
+
+#include <nrf.h>
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
user: login: SebastianBoe
body: Evidently it is not included by nrfx.h.

In any case this header has nrf as a depenency, not nrfx, and it is good practice to include dependencies.

![image](https://github.com/user-attachments/assets/ac580b13-c84d-401e-9c6f-9e1325bf11e5)

created_at: 2025-04-08T13:30:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __BOUNCE_BUFFERS_H__
+#define __BOUNCE_BUFFERS_H__
+
+#include <nrf.h>
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
user: login: jonathannilsen
body: Huh, I thought nrfx.h pulled in all the required MDK headers, nvm then
created_at: 2025-04-08T13:33:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#pragma once
+
+/*
+ * This header contains symbols that are used by both the SDFW client
+ * and the SDFW service.
+ */
+
+/* Number of uint32_t words in the data sent over ipc_service */
+#define SDFW_PSA_IPC_DATA_LEN 6
+
+/* Usually provided by manifest/sid.h */
path: include/tfm/sdfw_psa_ipc_service.h
user: login: SebastianBoe
body: fixed
created_at: 2025-04-08T13:41:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,8 +4,36 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+target_sources(${mbedcrypto_target}
path: subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
user: login: SebastianBoe
body: fixed. I kept the SSFv1 build as-is to avoid obscure regressions.
created_at: 2025-04-08T13:43:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,4 +8,31 @@ config PSA_SSF_CRYPTO_CLIENT
 	bool
 	prompt "PSA crypto provided through SSF"
 	default y
-	depends on SSF_CLIENT && SSF_PSA_CRYPTO_SERVICE_ENABLED
+	depends on (SSF_CLIENT || SSF_V_2) && SSF_PSA_CRYPTO_SERVICE_ENABLED
+
+if PSA_SSF_CRYPTO_CLIENT
+
+config PSA_SSF_CRYPTO_CLIENT_OUT_BOUNCE_BUFFERS
+	bool "Make sure that all output vectors can be written cache-safe from the crypto engine"
path: subsys/nrf_security/src/ssf_secdom/Kconfig
user: login: SebastianBoe
body: fixed
created_at: 2025-04-08T13:44:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __SDFW_PSA_IPC_SERVICE_H__
+#define __SDFW_PSA_IPC_SERVICE_H__
+
+/*
+ * This header contains symbols that are used by both the SDFW client
+ * and the SDFW service.
+ */
+enum {
+	INDEX_HANDLE,
+	INDEX_IN_VEC,
+	INDEX_IN_LEN,
+	INDEX_OUT_VEC,
+	INDEX_OUT_LEN,
+	INDEX_STATUS_PTR,
path: include/tfm/sdfw_psa_ipc_service.h
user: login: SebastianBoe
body: added prefix
created_at: 2025-04-08T13:44:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <zephyr/kernel.h>
+#include <zephyr/cache.h>
+
+#include "bounce_buffers.h"
+
+/* k_heap_alloc allocated memory is aligned on a multiple of pointer sizes. The HW's DataUnit size
+ * must match this Zephyr behaviour.
+ */
+BUILD_ASSERT(CACHE_DATA_UNIT_SIZE == sizeof(uintptr_t));
+
+static K_HEAP_DEFINE(out_buffer_heap,
+		     ROUND_UP(CONFIG_PSA_SSF_CRYPTO_CLIENT_OUT_HEAP_SIZE, CACHE_DATA_UNIT_SIZE));
+
+void *bounce_buffers_prepare(void *original_buffer, size_t size)
+{
+	void *out_buffer = NULL;
+
+	if ((IS_ALIGNED(original_buffer, CACHE_DATA_UNIT_SIZE)) &&
+	    (IS_ALIGNED(size, CACHE_DATA_UNIT_SIZE))) {
+		out_buffer = original_buffer;
+	} else {
+		out_buffer = k_heap_alloc(&out_buffer_heap, size, K_NO_WAIT);
+		if (out_buffer != NULL) {
+			memcpy(out_buffer, original_buffer, size);
+		}
+	}
+
+	return out_buffer;
+}
+
+void bounce_buffers_release(void *original_buffer, void *out_buffer, size_t size)
+{
+	if (out_buffer == NULL) {
+		return;
+	}
+
+	if (original_buffer == out_buffer) {
+		return;
+	}
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.c
user: login: SebastianBoe
body: fixed
created_at: 2025-04-08T13:44:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __BOUNCE_BUFFERS_H__
+#define __BOUNCE_BUFFERS_H__
+
+#include <nrf.h>
path: subsys/nrf_security/src/ssf_secdom/bounce_buffers.h
user: login: SebastianBoe
body: sorry, the error was from something else.

Only including nrfx.h does work.

fixed
created_at: 2025-04-08T14:28:58Z
author_association: CONTRIBUTOR
path: subsys/nrf_security/src/ssf_secdom/sdfw_psa_ns_api.c
user: login: SebastianBoe
body: fixed.

Although I'm keeping ssf_secdom as this code temporarily exists within the ssf_secdom infrastructure until the new SSF layer exists.
created_at: 2025-04-08T14:30:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __SDFW_PSA_IPC_SERVICE_H__
path: include/tfm/ironside/se/ipc_service.h
user: login: hakonfam
body: This should be updated to reflect the naming change.
created_at: 2025-04-09T04:32:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2025 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
+ */
+
+#ifndef __CONFIG_SDFW_PSA_NS_IPC_H__
path: subsys/nrf_security/src/ssf_secdom/ironside_se_psa_ns_ipc.h
user: login: hakonfam
body: sdfw
created_at: 2025-04-09T04:33:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -55,6 +55,13 @@ rsource "Kconfig.psa.nordic"
 config PSA_PROMPTLESS
 	bool
 
+config SSF_V_2
+	bool
+	default y if BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON
+	prompt "temporary option until iron and SSFv2 is available"
path: subsys/nrf_security/Kconfig
user: login: nordicjm
body: why does this have a prompt?
created_at: 2025-04-10T12:02:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,8 +4,33 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+  zephyr_library()
+  zephyr_library_sources(
+	# ironside_psa_ns_api.c provides psa_call. psa_call is invoked by
path: subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
user: login: nordicjm
body: lacks indent, here and below
created_at: 2025-04-10T12:02:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,8 +4,33 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+  zephyr_library()
+  zephyr_library_sources(
+	# ironside_psa_ns_api.c provides psa_call. psa_call is invoked by
path: subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
user: login: nordicjm
body: actually I see the issue between the 2 github editor views, this is using tab, no tab in cmake, use spaces
created_at: 2025-04-10T12:04:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -55,6 +55,13 @@ rsource "Kconfig.psa.nordic"
 config PSA_PROMPTLESS
 	bool
 
+config SSF_V_2
+	bool
+	default y if BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON
+	prompt "temporary option until iron and SSFv2 is available"
path: subsys/nrf_security/Kconfig
user: login: SebastianBoe
body: It is to allow an application that doesn't need any secure services to turn them off.
created_at: 2025-04-10T12:06:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4,8 +4,33 @@
 # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 #
 
+if(CONFIG_SSF_V_2)
+  zephyr_library()
+  zephyr_library_sources(
+	# ironside_psa_ns_api.c provides psa_call. psa_call is invoked by
path: subsys/nrf_security/src/ssf_secdom/CMakeLists.txt
user: login: SebastianBoe
body: fixed
created_at: 2025-04-10T12:11:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,16 @@
+#
+# Copyright (c) 2024 Nordic Semiconductor
path: samples/crypto/aes_gcm/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf
user: login: Vge0rge
body: Multiple conf files have 2024 copyright
created_at: 2025-04-11T08:04:13Z
author_association: CONTRIBUTOR

PR comments:
user: login: NordicBuilder
created_at: 2025-04-03T15:30:56Z
body: ## CI Information

<sup>_To view the history of this post, clich the 'edited' button above_</sup>
Build number: 18
### Inputs:
#### Sources:
sdk-nrf: PR head: [9dab3792f3cf2f145589847bf3a517e8ef31d11e](https://github.com/nrfconnect/sdk-nrf/pull/21383/commits/9dab3792f3cf2f145589847bf3a517e8ef31d11e)
<details><summary> more details</summary>

sdk-nrf:
> PR head: [9dab3792f3cf2f145589847bf3a517e8ef31d11e](https://github.com/nrfconnect/sdk-nrf/pull/21383/commits/9dab3792f3cf2f145589847bf3a517e8ef31d11e)
> merge base: [e531cd9d33c8486abc58e68f9375c73668557c45](https://github.com/nrfconnect/sdk-nrf/commit/e531cd9d33c8486abc58e68f9375c73668557c45)
> target head (main): [28bd02f5c3b95e5db2b43b4dbaf45339383eb81c](https://github.com/nrfconnect/sdk-nrf/commit/28bd02f5c3b95e5db2b43b4dbaf45339383eb81c)
> [Diff](https://github.com/nrfconnect/sdk-nrf/compare/e531cd9d33c8486abc58e68f9375c73668557c45..9dab3792f3cf2f145589847bf3a517e8ef31d11e)</details>

#### Github labels
| Enabled | Name | Description |
| -- | -- | -- |
|| ci-disabled | _Disable the ci execution_ | 
|| ci-all-test | _Run all of ci, no test spec filtering will be done_ | 
|| ci-force-downstream | _Force execution of downstream even if twister fails_ | 
|| ci-run-twister | _Force run twister_ | 
|| ci-run-zephyr-twister | _Force run zephyr twister_ | 

<details><summary> List of changed files detected by CI (22)</summary>

```
include
│  ├── tfm
│  │  ├── ironside
│  │  │  ├── se
│  │  │  │  │ ipc_service.h
samples
│  ├── crypto
│  │  ├── aes_gcm
│  │  │  ├── boards
│  │  │  │  ├── nrf54h20dk_nrf54h20_cpuapp_iron.conf
│  │  │  │  │ nrf54h20dk_nrf54h20_cpuapp_iron.overlay
│  │  ├── ecdh
│  │  │  ├── boards
│  │  │  │  ├── nrf54h20dk_nrf54h20_cpuapp_iron.conf
│  │  │  │  │ nrf54h20dk_nrf54h20_cpuapp_iron.overlay
│  │  ├── ecdsa
│  │  │  ├── boards
│  │  │  │  ├── nrf54h20dk_nrf54h20_cpuapp_iron.conf
│  │  │  │  │ nrf54h20dk_nrf54h20_cpuapp_iron.overlay
│  │  ├── rng
│  │  │  ├── boards
│  │  │  │  ├── nrf54h20dk_nrf54h20_cpuapp_iron.conf
│  │  │  │  │ nrf54h20dk_nrf54h20_cpuapp_iron.overlay
│  │  ├── sha256
│  │  │  ├── boards
│  │  │  │  ├── nrf54h20dk_nrf54h20_cpuapp_iron.conf
│  │  │  │  │ nrf54h20dk_nrf54h20_cpuapp_iron.overlay
subsys
│  ├── nrf_security
│  │  ├── Kconfig
│  │  ├── src
│  │  │  ├── ssf_secdom
│  │  │  │  ├── CMakeLists.txt
│  │  │  │  ├── Kconfig
│  │  │  │  ├── bounce_buffers.c
│  │  │  │  ├── bounce_buffers.h
│  │  │  │  ├── ironside_se_psa_ns_api.c
│  │  │  │  ├── ironside_se_psa_ns_ipc.c
│  │  │  │  ├── ironside_se_psa_ns_ipc.h
│  │  │  │  ├── psa_manifest
│  │  │  │  │  │ sid.h
│  ├── sdfw_services
│  │  ├── Kconfig
│  │  ├── services
│  │  │  │ Kconfig.template.service
```
</details>

### Outputs:

#### Toolchain
Version: 7cbc0036f4
Build docker image: docker-dtr.nordicsemi.no/sw-production/ncs-build:7cbc0036f4_8bf7ca4353

#### Test Spec & Results: :white_check_mark: Success; :x: Failure; :orange_circle: Queued; :yellow_circle: Progress; :white_medium_square: Skipped; :warning: Quarantine
- :white_medium_square: Toolchain - Skipped: existing toolchain is used
- :white_check_mark: Build twister
   - sdk-nrf test count: 1756
- :white_check_mark: Integration tests
   - :white_check_mark: test-fw-nrfconnect-boot
   - :white_check_mark: test_ble_nrf_config
   - :white_check_mark: test-fw-nrfconnect-chip
   - :white_check_mark: test-fw-nrfconnect-nrf-iot_cloud
   - :white_check_mark: test-fw-nrfconnect-nrf_crypto
   - :white_check_mark: test-fw-nrfconnect-rs
   - :white_check_mark: test-fw-nrfconnect-tfm
   - :white_check_mark: test-sdk-find-my
   - :white_check_mark: test-sdk-mcuboot
   - :white_check_mark: test-sdk-dfu

<details><summary>Disabled integration tests</summary>

- 
   - desktop52_verification
   - doc-internal
   - test-fw-nrfconnect-apps
   - test-fw-nrfconnect-ble_mesh
   - test-fw-nrfconnect-ble_samples
   - test-fw-nrfconnect-fem
   - test-fw-nrfconnect-nfc
   - test-fw-nrfconnect-nrf-iot_libmodem-nrf
   - test-fw-nrfconnect-nrf-iot_mosh
   - test-fw-nrfconnect-nrf-iot_positioning
   - test-fw-nrfconnect-nrf-iot_samples
   - test-fw-nrfconnect-nrf-iot_serial_lte_modem
   - test-fw-nrfconnect-nrf-iot_thingy91
   - test-fw-nrfconnect-nrf-iot_zephyr_lwm2m
   - test-fw-nrfconnect-proprietary_esb
   - test-fw-nrfconnect-ps
   - test-fw-nrfconnect-rpc
   - test-fw-nrfconnect-thread
   - test-low-level
   - test-sdk-audio
   - test-sdk-pmic-samples
   - test-sdk-wifi
   - test-secdom-samples-public
</details>



*Note: This message is automatically posted and updated by the CI*
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-03T15:48:39Z
body: You can find the documentation preview for this PR [here](https://ncsdoc.z6.web.core.windows.net/PR-21383/).

author_association: NONE
user: login: SebastianBoe
created_at: 2025-04-10T11:55:23Z
body: This does not need to be backported to 3.0
author_association: CONTRIBUTOR