feat(runtime/rmi): implement RMI_PDEV_CREATE
Define pdev data type and implement RMI_PDEV_CREATE. pdev_create calls
device specific init routine.
This implementation supports off-chip PCIe device with pdev created with
flags SPDM, IDE supported.
This patch adds files to device_assignment app folder to handle
device specific security protocols like CMA SPDM, IDE_KM and TDISP.
Note that this commit will not build but it adds the necessary code
changes for RMI_PDEV_CREATE.
Signed-off-by: Soby Mathew <soby.mathew@arm.com>
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: Ie55666b5bef9e5d797100bb769ae3f4ba51f1974
diff --git a/app/common/framework/include/app.h b/app/common/framework/include/app.h
index eb53fa6..1e3eed1 100644
--- a/app/common/framework/include/app.h
+++ b/app/common/framework/include/app.h
@@ -21,6 +21,7 @@
*/
#define RMM_RANDOM_APP_ID (103U)
#define ATTESTATION_APP_ID (211U)
+#define RMM_DEV_ASSIGN_APP_ID (110U)
#define GRANULE_COUNT(size) (round_up(size, GRANULE_SIZE) / GRANULE_SIZE)
diff --git a/app/device_assignment/CMakeLists.txt b/app/device_assignment/CMakeLists.txt
index 99718fb..5192aec 100644
--- a/app/device_assignment/CMakeLists.txt
+++ b/app/device_assignment/CMakeLists.txt
@@ -4,5 +4,7 @@
#
add_subdirectory("el0_app")
+add_subdirectory("rmm_stub")
set(EL0_APP_BIN_LIST ${EL0_APP_BIN_LIST} PARENT_SCOPE)
+set(RMM_EL2_STUB_LIBRARIES ${RMM_EL2_STUB_LIBRARIES} PARENT_SCOPE)
diff --git a/app/device_assignment/el0_app/mbedtls_da/rmm_mbedtls_config_da.h b/app/device_assignment/el0_app/mbedtls_da/rmm_mbedtls_config_da.h
index 8babcc0..48253f9 100644
--- a/app/device_assignment/el0_app/mbedtls_da/rmm_mbedtls_config_da.h
+++ b/app/device_assignment/el0_app/mbedtls_da/rmm_mbedtls_config_da.h
@@ -33,6 +33,10 @@
/* Enable Mbed TLS's built in allocator */
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
+/* RMM defines its own mbedtls_exit */
+#define MBEDTLS_PLATFORM_EXIT_MACRO mbedtls_exit_panic
+void mbedtls_exit_panic(unsigned int reason);
+
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_CIPHER_C
diff --git a/app/device_assignment/el0_app/src/dev_assign_el0_app.c b/app/device_assignment/el0_app/src/dev_assign_el0_app.c
new file mode 100644
index 0000000..6e09607
--- /dev/null
+++ b/app/device_assignment/el0_app/src/dev_assign_el0_app.c
@@ -0,0 +1,410 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#include <app_common.h>
+#include <debug.h>
+#include <dev_assign_private.h>
+#include <el0_app_helpers.h>
+#include <mbedtls/memory_buffer_alloc.h>
+#include <psa/crypto.h>
+#include <psa/crypto_struct.h>
+#include <string.h>
+
+static libspdm_return_t spdm_send_message(void *spdm_context,
+ size_t request_size,
+ const void *request,
+ uint64_t timeout)
+{
+ (void)spdm_context;
+ (void)request_size;
+ (void)request;
+ (void)timeout;
+ return LIBSPDM_STATUS_SUCCESS;
+}
+
+static libspdm_return_t spdm_receive_message(void *spdm_context,
+ size_t *response_size,
+ void **response,
+ uint64_t timeout)
+{
+ (void)spdm_context;
+ (void)response_size;
+ (void)response;
+ (void)timeout;
+ return LIBSPDM_STATUS_SUCCESS;
+}
+
+static libspdm_return_t
+spdm_transport_encode_message(void *spdm_context, const uint32_t *session_id,
+ bool is_app_message, bool is_request_message,
+ size_t message_size, void *message,
+ size_t *transport_message_size,
+ void **transport_message)
+{
+ (void)spdm_context;
+ (void)session_id;
+ (void)is_app_message;
+ (void)is_request_message;
+ (void)message_size;
+ (void)message;
+ (void)transport_message_size;
+ (void)transport_message;
+ return LIBSPDM_STATUS_SUCCESS;
+}
+
+static libspdm_return_t
+spdm_transport_decode_message(void *spdm_context, uint32_t **session_id,
+ bool *is_app_message, bool is_request_message,
+ size_t transport_message_size,
+ void *transport_message,
+ size_t *message_size, void **message)
+{
+ (void)spdm_context;
+ (void)session_id;
+ (void)is_app_message;
+ (void)is_request_message;
+ (void)transport_message_size;
+ (void)transport_message;
+ (void)message_size;
+ (void)message;
+ return LIBSPDM_STATUS_SUCCESS;
+}
+
+static libspdm_return_t spdm_acquire_sender_buffer(void *spdm_context,
+ void **msg_buf_ptr)
+{
+ struct dev_assign_info *info __unused;
+
+ info = spdm_to_dev_assign_info(spdm_context);
+ *msg_buf_ptr = info->send_recv_buffer;
+
+ return LIBSPDM_STATUS_SUCCESS;
+}
+
+static void spdm_release_sender_buffer(void *spdm_context,
+ const void *msg_buf_ptr)
+{
+ struct dev_assign_info *info __unused;
+
+ (void)msg_buf_ptr;
+ info = spdm_to_dev_assign_info(spdm_context);
+ assert(info->send_recv_buffer == msg_buf_ptr);
+}
+
+static libspdm_return_t spdm_acquire_receiver_buffer(void *spdm_context,
+ void **msg_buf_ptr)
+{
+ struct dev_assign_info *info __unused;
+
+ info = spdm_to_dev_assign_info(spdm_context);
+ *msg_buf_ptr = info->send_recv_buffer;
+
+ return LIBSPDM_STATUS_SUCCESS;
+}
+
+static void spdm_release_receiver_buffer(void *spdm_context,
+ const void *msg_buf_ptr)
+{
+ struct dev_assign_info *info __unused;
+
+ (void)msg_buf_ptr;
+ info = spdm_to_dev_assign_info(spdm_context);
+ assert(info->send_recv_buffer == msg_buf_ptr);
+}
+
+/*
+ * Returns the min heap size. This include libspdm context, libspdm secured
+ * message context, libspdm scratch space, libspdm send recv buffer and
+ * MbedTLS heap.
+ */
+static size_t get_min_heap_size(void)
+{
+ size_t total;
+
+ /*
+ * As libspdm public headers do not export the type of libsdpm_context.
+ * RMM reserves 8192 bytes and check at runtime if the size is enough.
+ */
+ assert(libspdm_get_context_size() <= PRIV_LIBSPDM_CONTEXT_SIZE);
+
+ total = sizeof(struct dev_assign_info) +
+ PRIV_LIBSPDM_SEND_RECV_BUF_SIZE +
+ PRIV_LIBSPDM_CONTEXT_SIZE +
+ PRIV_LIBSPDM_SCRATCH_BUF_SIZE +
+ PRIV_LIBSPDM_MBEDTLS_HEAP_SIZE;
+
+ return total;
+}
+
+static inline psa_algorithm_t rmi_to_psa_hash_algo(uint8_t rmi_hash_algo)
+{
+ if (rmi_hash_algo == RMI_HASH_SHA_256) {
+ return PSA_ALG_SHA_256;
+ } else if (rmi_hash_algo == RMI_HASH_SHA_512) {
+ return PSA_ALG_SHA_512;
+ }
+
+ return PSA_ALG_NONE;
+}
+
+/* coverity[misra_c_2012_rule_5_8_violation:SUPPRESS] */
+void *mbedtls_app_get_heap(void)
+{
+ struct dev_assign_info *info;
+
+ info = heap_start_to_dev_assign_info((uintptr_t)get_heap_start());
+ return &(info->mbedtls_heap_ctx);
+}
+
+/*
+ * Assigns buffers to various objects as mentioned in the below mapping starting
+ * from start of EL0 heap. Note that send_recv_buffer must be first and
+ * libspdm_context must be just before struct dsm as this is assumed in
+ * spdm_to_dev_assign_info() macro.
+ *
+ * --------------------------------
+ * | send_recv_buffer | PRIV_LIBSPDM_SEND_RECV_BUF_SIZE
+ * |--------------------------------|
+ * | libspdm scratch_buffer | PRIV_LIBSPDM_SCRATCH_BUF_SIZE
+ * |--------------------------------|
+ * | MbedTLS heap buffer | PRIV_LIBSPDM_MBEDTLS_HEAP_SIZE
+ * |--------------------------------|
+ * | | libspdm_context | | PRIV_DATA_LIBSPMD_CONTEXT_SIZE
+ * |--| |---|
+ * | | struct dev_assign_info | | sizeof(struct dev_assign_info)
+ * --------------------------------
+ *
+ * Inits libspdm context using libspdm helper routines and registers send/recv
+ * buffer acquire/release routines. Registers device send/recv callback handlers.
+ *
+ * This function suppresses few MISRA rule 10.1 violations, as the macros that
+ * causes these violations are not declared as unsigned type and these macros
+ * are from libspdm header files.
+ */
+static int dev_assign_init(uintptr_t el0_heap, size_t heap_size, struct dev_assign_params *params)
+{
+ libspdm_return_t status __unused;
+ spdm_version_number_t cma_spdm_version;
+ spdm_version_number_t cma_sspdm_version;
+ libspdm_data_parameter_t parameter;
+ struct dev_assign_info *info;
+ void *spdm_ctx;
+ uint32_t data32;
+ uint16_t data16;
+ uint8_t data8;
+ size_t sb_size;
+
+ if (heap_size < get_min_heap_size()) {
+ ERROR("Min heap size 0x%lx expected. Current heap size = 0x%lx\n",
+ get_min_heap_size(), heap_size);
+ return DEV_ASSIGN_STATUS_ERROR;
+ }
+
+ if (params->cert_slot_id >= (uint8_t)SPDM_MAX_SLOT_COUNT) {
+ return DEV_ASSIGN_STATUS_ERROR;
+ }
+
+ info = heap_start_to_dev_assign_info(el0_heap);
+
+ info->send_recv_buffer = (void *)el0_heap;
+ info->scratch_buffer = (void *)((uintptr_t)info->send_recv_buffer +
+ PRIV_LIBSPDM_SEND_RECV_BUF_SIZE);
+ info->mbedtls_heap_buf = (void *)((uintptr_t)info->scratch_buffer +
+ PRIV_LIBSPDM_SCRATCH_BUF_SIZE);
+ info->libspdm_ctx = (void *)((uintptr_t)info->mbedtls_heap_buf +
+ PRIV_LIBSPDM_MBEDTLS_HEAP_SIZE);
+
+ assert((uintptr_t)spdm_to_dev_assign_info(info->libspdm_ctx) == (uintptr_t)info);
+
+ VERBOSE("dev assign send_recv buf: 0x%p\n", info->send_recv_buffer);
+ VERBOSE("dev assign scratch_buffer: 0x%p\n", info->scratch_buffer);
+ VERBOSE("dev assign libspdm_ctx: 0x%p\n", info->libspdm_ctx);
+ VERBOSE("dev assign info: 0x%p\n", (void *)info);
+
+
+ /* Initialize the mbedTLS heap */
+ mbedtls_memory_buffer_alloc_init(info->mbedtls_heap_buf, PRIV_LIBSPDM_MBEDTLS_HEAP_SIZE);
+
+ /* Initialize DSM */
+ info->dev_handle = params->dev_handle;
+ info->cert_slot_id = params->cert_slot_id;
+ info->has_ide = params->has_ide;
+ if (info->has_ide) {
+ info->ecam_addr = params->ecam_addr;
+ info->rp_id = params->rp_id;
+ info->ide_sid = params->ide_sid;
+ }
+
+ info->psa_hash_algo = rmi_to_psa_hash_algo(params->rmi_hash_algo);
+
+ /*
+ * Initialize SPDM and Secure SPDM context. 'spdm_ctx' is a combination
+ * of both SPDM context and secured message context.
+ */
+ spdm_ctx = info->libspdm_ctx;
+ status = libspdm_init_context(spdm_ctx);
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* Register device send/recv handlers */
+ libspdm_register_device_io_func(spdm_ctx, spdm_send_message,
+ spdm_receive_message);
+
+ /*
+ * No transport encodings used as this is handled by NS host. So the
+ * transport_header_size and transport_tail_size are passed as 0.
+ */
+ libspdm_register_transport_layer_func(spdm_ctx,
+ (uint32_t)CMA_MAX_SPDM_MSG_SIZE,
+ 0U, /* transport_header_size */
+ 0U, /* transport_tail_size */
+ spdm_transport_encode_message,
+ spdm_transport_decode_message);
+
+ /* Register send/recv buffer acquire/release functions */
+ libspdm_register_device_buffer_func(spdm_ctx,
+ (uint32_t)CMA_SENDER_BUFFER_SIZE,
+ (uint32_t)CMA_RECEIVER_BUFFER_SIZE,
+ spdm_acquire_sender_buffer,
+ spdm_release_sender_buffer,
+ spdm_acquire_receiver_buffer,
+ spdm_release_receiver_buffer);
+
+ /* Set scratch buffer size */
+ sb_size = libspdm_get_sizeof_required_scratch_buffer(spdm_ctx);
+
+ VERBOSE("libspdm_context_size: 0x%lx\n", libspdm_get_context_size());
+ VERBOSE("libspdm_scratch_buffer_size: 0x%lx\n", sb_size);
+ VERBOSE("struct dev_assign_info size: 0x%lx\n", sizeof(struct dev_assign_info));
+
+ assert(sb_size <= PRIV_LIBSPDM_SCRATCH_BUF_SIZE);
+ libspdm_set_scratch_buffer(spdm_ctx, info->scratch_buffer, sb_size);
+
+ /* Check libspdm context */
+ if (!libspdm_check_context(spdm_ctx)) {
+ assert(false);
+ }
+
+ /* Set SPDM version */
+ (void)memset(¶meter, 0, sizeof(parameter));
+ parameter.location = LIBSPDM_DATA_LOCATION_LOCAL;
+ cma_spdm_version = (spdm_version_number_t)CMA_SPDM_VERSION <<
+ SPDM_VERSION_NUMBER_SHIFT_BIT;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_SPDM_VERSION,
+ ¶meter, &cma_spdm_version,
+ sizeof(cma_spdm_version));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* Set secured message version */
+ (void)memset(¶meter, 0, sizeof(parameter));
+ parameter.location = LIBSPDM_DATA_LOCATION_LOCAL;
+ cma_sspdm_version = (spdm_version_number_t)CMA_SECURED_SPDM_VERSION <<
+ SPDM_VERSION_NUMBER_SHIFT_BIT;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_SECURED_MESSAGE_VERSION,
+ ¶meter, &cma_sspdm_version,
+ sizeof(cma_sspdm_version));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /*
+ * Set GET_CAPABILITY fields
+ * Note: DataTransferSize and MaxSPDMmsgSize is automatically set by
+ * libspdm during init connection based on CMA_SPDM_SENDER_BUFFER_SIZE
+ * and CMA_SPDM_MSG_SIZE_MAX respectivelky.
+ */
+ (void)memset(¶meter, 0, sizeof(parameter));
+ parameter.location = LIBSPDM_DATA_LOCATION_LOCAL;
+ data8 = CMA_SPDM_GET_CAPABILITY_CT_EXPONENT;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT,
+ ¶meter, &data8, sizeof(data8));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ data32 = CMA_SPDM_GET_CAPABILITIES_REQUEST_FLAGS;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_CAPABILITY_FLAGS,
+ ¶meter, &data32, sizeof(data32));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* Set NEGOTIATE_ALGORITHMS fields */
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ data8 = CMA_SPDM_ALGORITHMS_MEASUREMENT_SPEC;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_MEASUREMENT_SPEC,
+ ¶meter, &data8, sizeof(data8));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ data8 = CMA_SPDM_ALGORITHMS_OTHER_PARAMS_SUPPORT;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_OTHER_PARAMS_SUPPORT,
+ ¶meter, &data8, sizeof(data8));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ data32 = CMA_SPDM_ALGORITHMS_BASE_ASYM_ALGOS;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_BASE_ASYM_ALGO,
+ ¶meter, &data32, sizeof(data32));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ data32 = CMA_SPDM_ALGORITHMS_BASE_HASH_ALGOS;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_BASE_HASH_ALGO,
+ ¶meter, &data32, sizeof(data32));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ data16 = CMA_SPDM_ALGORITHMS_DHE_GROUPS;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_DHE_NAME_GROUP,
+ ¶meter, &data16, sizeof(data16));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ data16 = CMA_SPDM_ALGORITHMS_AEAD_CIPHER_SUITES;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_AEAD_CIPHER_SUITE,
+ ¶meter, &data16, sizeof(data16));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ data16 = CMA_SPDM_ALGORITHMS_KEY_SCHEDULE;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_KEY_SCHEDULE,
+ ¶meter, &data16, sizeof(data16));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* coverity[misra_c_2012_rule_10_1_violation:SUPPRESS] */
+ data16 = CMA_SPDM_ALGORITHMS_REQ_BASE_ASYM_ALGOS;
+ status = libspdm_set_data(spdm_ctx, LIBSPDM_DATA_REQ_BASE_ASYM_ALG,
+ ¶meter, &data16, sizeof(data16));
+ assert(status == LIBSPDM_STATUS_SUCCESS);
+
+ /* Assign the shared_buf. This serves as a marker that init is done. */
+ info->shared_buf = (void *)params;
+
+ return DEV_ASSIGN_STATUS_SUCCESS;
+}
+
+
+/* coverity[misra_c_2012_rule_5_8_violation:SUPPRESS] */
+unsigned long el0_app_entry_func(
+ unsigned long func_id,
+ unsigned long arg_0,
+ unsigned long arg_1,
+ unsigned long arg_2,
+ unsigned long arg_3)
+{
+ uintptr_t heap = (uintptr_t)get_heap_start();
+
+ (void)arg_1;
+ (void)arg_2;
+ (void)arg_3;
+
+ switch (func_id) {
+ case DEVICE_ASSIGN_APP_FUNC_ID_INIT:
+ {
+ uintptr_t shared = (uintptr_t)get_shared_mem_start();
+
+ return (unsigned long)dev_assign_init(heap, arg_0,
+ (struct dev_assign_params *)shared);
+ }
+ default:
+ assert(false);
+ return (unsigned long)DEV_ASSIGN_STATUS_ERROR;
+ }
+}
diff --git a/app/device_assignment/el0_app/src/dev_assign_private.h b/app/device_assignment/el0_app/src/dev_assign_private.h
new file mode 100644
index 0000000..cf9dd41
--- /dev/null
+++ b/app/device_assignment/el0_app/src/dev_assign_private.h
@@ -0,0 +1,259 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef DEV_ASSIGN_PRIVATE_H
+#define DEV_ASSIGN_PRIVATE_H
+
+#include <assert.h>
+#include <dev_assign_structs.h>
+#include <industry_standard/spdm.h>
+#include <industry_standard/spdm_secured_message.h>
+#include <library/spdm_requester_lib.h>
+#include <library/spdm_secured_message_lib.h>
+#include <mbedtls/memory_buffer_alloc.h>
+#include <sizes.h>
+#include <utils_def.h>
+
+/*
+ * Requester SPDM version is 1.2. This is the minimum SPDM version required to
+ * support TDISP.
+ *
+ * From PCIe spec: CMA requires SPDM Version 1.0 or above. IDE requires SPDM
+ * Version 1.1 or above. TDISP requires version 1.2 or above.
+ */
+#define CMA_SPDM_VERSION SPDM_MESSAGE_VERSION_12
+
+/*
+ * Secured Messages using SPDM Specification (IDE requires version 1.0 or above)
+ * Set this to 1.1. DSM supports 1.1
+ */
+#define CMA_SECURED_SPDM_VERSION SECURED_SPDM_VERSION_11
+
+/*
+ * Responders must implement a Cryptographic Timeout (CT), as defined by SPDM
+ * specification, of not more than 2^23 μs.
+ */
+#define CMA_SPDM_GET_CAPABILITY_CT_EXPONENT 20
+
+/*
+ * List of capabilities enabled and supported by SPDM requester. These flags are
+ * passed to GET_CAPABILITIES request message. Currently these flags are specific
+ * to PCIe TDI off-chip device.
+ *
+ * CERT_CAP - Supports DIGESTS and CERTIFICATE response messages.
+ * ENCRYPT_CAP - Supports message encryption in a secure session.
+ * KEY_EX_CAP - Support KEY_EXCHANGE request message. Needs ENCRYPT_CAP and
+ * MAC_CAP.
+ * MAC_CAP - Supports message authentication in a secure session.
+ * CHUNK_CAP - Supports large SPDM message transfer mechanism messages.
+ * Note: Add SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP.
+ * CHUNK retrieval is not verified.
+ */
+#define CMA_SPDM_GET_CAPABILITIES_REQUEST_FLAGS ( \
+ SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP | \
+ SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCRYPT_CAP | \
+ SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP | \
+ SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP | \
+ SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)
+
+/*
+ * List of minimum set of capabilities required to be supported by the responder.
+ * These flags are checked against CAPABILITIES response message. Currently these
+ * flags are specific to PCIe TDI off-chip device.
+ */
+#define CMA_SPDM_GET_CAPABILITIES_RESPONSE_FLAGS ( \
+ SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP | \
+ SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP | \
+ SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP | \
+ SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP | \
+ SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP)
+
+/*
+ * Optional set of capabilities that can be supported by the responder. These
+ * flags are checked against CAPABILITIES response message.
+ */
+#define CMA_SPDM_GET_CAPABILITIES_RESPONSE_OPTIONAL_FLAGS ( \
+ SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_FRESH_CAP | \
+ SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)
+
+/*
+ * The measurement specification is used in the MEASUREMENTS response. This is
+ * not explicitly mentioned in PCIe CMA-SPDM.
+ */
+#define CMA_SPDM_ALGORITHMS_MEASUREMENT_SPEC \
+ SPDM_MEASUREMENT_SPECIFICATION_DMTF
+
+/*
+ * OtherParamsSupport: Opaque data format used is DMTF. This is not explicitly
+ * mentioned in PCIe CMA-SPDM.
+ */
+#define CMA_SPDM_ALGORITHMS_OTHER_PARAMS_SUPPORT \
+ SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1
+
+/*
+ * Requesters are required to support responders that implement any of these
+ * choices of BaseAsymAlgo:
+ * TPM_ALG_RSASSA_3072
+ * TPM_ALG_ECDSA_ECC_NIST_P256
+ * TPM_ALG_ECDSA_ECC_NIST_P384
+ */
+#define CMA_SPDM_ALGORITHMS_BASE_ASYM_ALGOS ( \
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072 | \
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256 | \
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384)
+
+/*
+ * Requesters and responders must, for MeasurementHashAlgo, support one or both
+ * of the following:
+ * TPM_ALG_SHA_256
+ * TPM_ALG_SHA_384
+ */
+#define CMA_SPDM_ALGORITHMS_BASE_HASH_ALGOS ( \
+ SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256 | \
+ SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384)
+
+/*
+ * Requester are required to responders that implement any of these DHE groups
+ * SECP_256_R1
+ * SECP_384_R1
+ */
+#define CMA_SPDM_ALGORITHMS_DHE_GROUPS ( \
+ SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_256_R1 | \
+ SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_384_R1)
+
+/*
+ * Requester are required to responders that implement any of these AEAD Cipher
+ * Suite
+ * AES-128-GCM
+ * AES-256-GCM
+ */
+#define CMA_SPDM_ALGORITHMS_AEAD_CIPHER_SUITES ( \
+ SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AES_128_GCM | \
+ SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AES_256_GCM)
+
+/* Requester-supported SPDM-enumerated Key Schedule algorithms. */
+#define CMA_SPDM_ALGORITHMS_KEY_SCHEDULE \
+ SPDM_ALGORITHMS_KEY_SCHEDULE_HMAC_HASH
+
+/*
+ * Requesters supported asym algorithm.
+ * TPM_ALG_RSAPSS_3072
+ * TPM_ALG_RSAPSS_2048
+ * TPM_ALG_RSASSA_3072
+ * TPM_ALG_RSASSA_2048
+ */
+#define CMA_SPDM_ALGORITHMS_REQ_BASE_ASYM_ALGOS ( \
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072 | \
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048 | \
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072 | \
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048)
+
+/*
+ * SPDM GET_CAPABILITIES.DataTransferSize
+ *
+ * This is the size of send/receive buffer that is registered with libspdm to
+ * write device request and read device response. RMM uses the same buffer for
+ * both send and receive as only one device request can be active at a time.
+ *
+ * RMM spec limits the response (recv) length to GRANULE_SIZE. And so the send
+ * buffer size is also limited to GRANULE_SIZE. This value is set as SPDM
+ * requester GET_CAPABILITIES.DataTransferSize as part of connection init.
+ *
+ * Note: Increasing CMA_DATA_TRANSFER_SIZE increases
+ * PRIV_DATA_LIBSPMD_SCRATCH_BUFFER_SIZE.
+ */
+#define CMA_DATA_TRANSFER_SIZE GRANULE_SIZE
+#define CMA_SENDER_BUFFER_SIZE CMA_DATA_TRANSFER_SIZE
+#define CMA_RECEIVER_BUFFER_SIZE CMA_DATA_TRANSFER_SIZE
+
+/*
+ * SPDM GET_CAPABILITIES.MaxSPDMmsgSize
+ *
+ * If the Requester supports the Large SPDM message transfer mechanism this
+ * field shall indicate the maximum size, in bytes, of the internal buffer used
+ * to reassemble a single and complete Large SPDM message.
+ *
+ * Currently this is set as the same value of CMA_DATA_TRANSFER_SIZE. This value
+ * is set as SPDM requester GET_CAPABILITIES.MaxSPDMmsgSize as part of connection
+ * init.
+ *
+ * This could be later incremented once SPDM CHUNK support is enabled and tested.
+ */
+#define CMA_MAX_SPDM_MSG_SIZE CMA_DATA_TRANSFER_SIZE
+
+/*
+ * List of data objects mapped in heap prefixed by PRIV_
+ *
+ * PRIV_LIBSPDM_SEND_RECV_BUF_SIZE:
+ * This is buffer to send and receive SPDM data. Must be allocated first on
+ * heap as this shared with RMM stub and accessed by RMM.
+ *
+ * PRIV_LIBSPDM_CONTEXT_SIZE:
+ * Libspdm public headers do not export the type of libsdpm_context. Reserve
+ * 2*4K pages and check at runtime if context size are within limit using
+ * libspdm_get_context_size() api.
+ *
+ * PRIV_LIBSPDM_SCRATCH_BUF_SIZE:
+ * This is an internal buffer used by libspdm as scratch space. This is
+ * approx 6 times of CMA_DATA_TRANSFER_SIZE. As part of init connection
+ * there is a run time check to verify if enough scratch space is reserved.
+ *
+ * PRIV_LIBSPDM_MBEDTLS_HEAP_SIZE
+ * This is the heap used by Libspdm MbedTLS library.
+ */
+#define PRIV_LIBSPDM_SEND_RECV_BUF_SIZE sizeof(struct dev_assign_spdm_shared)
+#define PRIV_LIBSPDM_CONTEXT_SIZE (2U * SZ_4K)
+#define PRIV_LIBSPDM_SCRATCH_BUF_SIZE (6U * CMA_DATA_TRANSFER_SIZE)
+#define PRIV_LIBSPDM_MBEDTLS_HEAP_SIZE (3U * SZ_4K)
+
+/* Custom libspdm status code. Wait for device response */
+#define LIBSPDM_STATUS_DEV_COMM_BLOCKED ((libspdm_return_t)0x80008000U)
+
+#define spdm_to_dev_assign_info(spdm) \
+ ((struct dev_assign_info *)((unsigned long)(spdm) + \
+ PRIV_LIBSPDM_CONTEXT_SIZE))
+
+#define heap_start_to_dev_assign_info(heap) \
+ ((struct dev_assign_info *)((heap) + \
+ PRIV_LIBSPDM_SEND_RECV_BUF_SIZE + \
+ PRIV_LIBSPDM_SCRATCH_BUF_SIZE + \
+ PRIV_LIBSPDM_MBEDTLS_HEAP_SIZE + \
+ PRIV_LIBSPDM_CONTEXT_SIZE))
+
+struct dev_assign_info {
+ /* RMI device handle */
+ void *dev_handle;
+
+ /* SPDM certificate slot ID */
+ uint8_t cert_slot_id;
+
+ bool has_ide;
+
+ /* Identify the root complex (RC). */
+ uint64_t ecam_addr;
+
+ /* Identify the RP within the RC. RootPort PCI BDF */
+ uint16_t rp_id;
+
+ /* IDE stream ID */
+ uint64_t ide_sid;
+
+ buffer_alloc_ctx mbedtls_heap_ctx;
+
+ /* Exit and Entry args for dev_communicate cmds */
+ struct rmi_dev_comm_enter enter_args;
+ struct rmi_dev_comm_exit exit_args;
+
+ void *send_recv_buffer;
+ void *scratch_buffer;
+ void *mbedtls_heap_buf;
+ void *libspdm_ctx;
+
+ void *shared_buf;
+};
+
+int dev_assign_cmd_init_connection_main(struct dev_assign_info *info);
+
+#endif /* DEV_ASSIGN_PRIVATE_H */
diff --git a/app/device_assignment/rmm_stub/CMakeLists.txt b/app/device_assignment/rmm_stub/CMakeLists.txt
new file mode 100644
index 0000000..d5ad243
--- /dev/null
+++ b/app/device_assignment/rmm_stub/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+#
+
+add_library(rmm-app-dev-assign-stub)
+
+target_link_libraries(rmm-app-dev-assign-stub
+ PRIVATE
+ rmm-el2-stub
+ rmm-lib-arch
+ rmm-lib-common
+ rmm-lib-debug)
+
+target_include_directories(rmm-app-dev-assign-stub
+ PUBLIC "include"
+ PRIVATE "../../common/include")
+
+target_sources(rmm-app-dev-assign-stub
+ PRIVATE "src/dev_assign_app_stub.c")
+
+list(APPEND RMM_EL2_STUB_LIBRARIES "rmm-app-dev-assign-stub")
+set(RMM_EL2_STUB_LIBRARIES ${RMM_EL2_STUB_LIBRARIES} PARENT_SCOPE)
diff --git a/app/device_assignment/rmm_stub/include/dev_assign_app.h b/app/device_assignment/rmm_stub/include/dev_assign_app.h
new file mode 100644
index 0000000..8f124af
--- /dev/null
+++ b/app/device_assignment/rmm_stub/include/dev_assign_app.h
@@ -0,0 +1,29 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef DEV_ASSIGN_APP_H
+#define DEV_ASSIGN_APP_H
+
+#include <dev_assign_structs.h>
+
+
+/*
+ * Initialize an instance of device_assignment app.
+ *
+ * Arguments:
+ * app_data - Pointer to app_data_cfg. This is uninitialized and opaque to caller
+ * granule_pas - Array of contiguous granule addresses to be used for the app.
+ * granule_pa_count - Num of elements in `granule_pas` array.
+ * granule_va_start - Start VA address of the `granule_pas` array.
+ * params - Pointer to the dev_assign_params populated by the caller.
+ *
+ * Returns DEV_ASSIGN_STATUS_SUCCESS on success, DEV_ASSIGN_STATUS_ERROR
+ * on error.
+ */
+int dev_assign_app_init(struct app_data_cfg *app_data, uintptr_t granule_pas[],
+ size_t granule_pa_count, void *granule_va_start,
+ struct dev_assign_params *params);
+
+#endif /* DEV_ASSIGN_APP_H */
diff --git a/app/device_assignment/rmm_stub/include/dev_assign_structs.h b/app/device_assignment/rmm_stub/include/dev_assign_structs.h
new file mode 100644
index 0000000..480b01d
--- /dev/null
+++ b/app/device_assignment/rmm_stub/include/dev_assign_structs.h
@@ -0,0 +1,52 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef DEV_ASSIGN_STRUCTS_H
+#define DEV_ASSIGN_STRUCTS_H
+
+#include <smc-rmi.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define DEV_ASSIGN_STATUS_SUCCESS (0)
+#define DEV_ASSIGN_STATUS_ERROR (-1)
+#define DEV_ASSIGN_STATUS_COMM_BLOCKED (1)
+
+/*
+ * App function for initialization. This needs to be invoked for every
+ * new instance of the app. App uses heap available via tpidrro_el0.
+ *
+ * arg0 == Size of Heap in num of 4K pages.
+ *
+ * Shared app buf == `struct dev_assign_params`
+ *
+ * ret0 == DEV_ASSIGN_STATUS_SUCCESS if initialization is successful.
+ * DEV_ASSIGN_STATUS_ERROR if error on initialization.
+ */
+#define DEVICE_ASSIGN_APP_FUNC_ID_INIT 1
+
+struct dev_assign_params {
+ /* RMI device handle */
+ void *dev_handle;
+ /* Algorithm used to generate device digests. */
+ uint8_t rmi_hash_algo;
+ /* SPDM certificate slot ID */
+ uint8_t cert_slot_id;
+ bool has_ide;
+ /* Identify the root complex (RC). */
+ uint64_t ecam_addr;
+ /* Identify the RP within the RC. RootPort PCI BDF */
+ uint16_t rp_id;
+ /* IDE stream ID */
+ uint64_t ide_sid;
+};
+
+/* Shared structure on the app heap for SPDM comms */
+struct dev_assign_spdm_shared {
+ uint8_t sendrecv_buf[GRANULE_SIZE];
+};
+
+#endif /* DEV_ASSIGN_STRUCTS_H */
diff --git a/app/device_assignment/rmm_stub/src/dev_assign_app_stub.c b/app/device_assignment/rmm_stub/src/dev_assign_app_stub.c
new file mode 100644
index 0000000..fb8a4d0
--- /dev/null
+++ b/app/device_assignment/rmm_stub/src/dev_assign_app_stub.c
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+ #include <app.h>
+ #include <assert.h>
+ #include <dev_assign_app.h>
+ #include <dev_assign_structs.h>
+
+/* Add declaration to prevent static checker error */
+void dev_assign_app_get_bss(uintptr_t *bss_pa, size_t *bss_size);
+
+void dev_assign_app_get_bss(uintptr_t *bss_pa, size_t *bss_size)
+{
+ static char dev_assign_app_bss[GRANULE_SIZE] __aligned(GRANULE_SIZE);
+ *bss_pa = (uintptr_t)dev_assign_app_bss;
+ *bss_size = sizeof(dev_assign_app_bss);
+}
+
+int dev_assign_app_init(struct app_data_cfg *app_data, uintptr_t granule_pas[],
+ size_t granule_pa_count, void *granule_va_start,
+ struct dev_assign_params *params)
+{
+ int rc;
+ struct dev_assign_params *shared;
+
+ rc = app_init_data(app_data,
+ RMM_DEV_ASSIGN_APP_ID,
+ granule_pas,
+ granule_pa_count,
+ granule_va_start);
+ if (rc != 0) {
+ return DEV_ASSIGN_STATUS_ERROR;
+ }
+
+ app_map_shared_page(app_data);
+ shared = app_data->el2_shared_page;
+ (void)memcpy(shared, params, sizeof(*shared));
+
+ rc = (int)app_run(app_data, DEVICE_ASSIGN_APP_FUNC_ID_INIT,
+ app_data->heap_size, 0, 0, 0);
+ app_unmap_shared_page(app_data);
+
+ return rc;
+}
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
index c3f36de..907ff8a 100644
--- a/runtime/CMakeLists.txt
+++ b/runtime/CMakeLists.txt
@@ -84,8 +84,8 @@
"rmi/rec.c"
"rmi/rtt.c"
"rmi/run.c"
- "rmi/version.c")
-
+ "rmi/version.c"
+ "rmi/pdev.c")
if(HOST_VARIANT STREQUAL "host_cbmc")
target_sources(rmm-runtime
diff --git a/runtime/core/handler.c b/runtime/core/handler.c
index 5cda469..3f7594f 100644
--- a/runtime/core/handler.c
+++ b/runtime/core/handler.c
@@ -163,7 +163,7 @@
HANDLER(DEV_MEM_UNMAP, 3, 2, smc_dev_mem_unmap, false, true),
HANDLER(PDEV_ABORT, 0, 0, NULL, true, true),
HANDLER(PDEV_COMMUNICATE, 2, 0, NULL, true, true),
- HANDLER(PDEV_CREATE, 2, 0, NULL, true, true),
+ HANDLER(PDEV_CREATE, 2, 0, smc_pdev_create, true, true),
HANDLER(PDEV_DESTROY, 0, 0, NULL, true, true),
HANDLER(PDEV_GET_STATE, 1, 1, NULL, true, true),
HANDLER(PDEV_IDE_RESET, 0, 0, NULL, true, true),
diff --git a/runtime/include/dev.h b/runtime/include/dev.h
new file mode 100644
index 0000000..61f90ed
--- /dev/null
+++ b/runtime/include/dev.h
@@ -0,0 +1,101 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#ifndef DEV_H
+#define DEV_H
+
+#include <app_fw_structures.h>
+#include <arch.h>
+#include <arch_features.h>
+#include <granule.h>
+#include <sizes.h>
+#include <smc-handler.h>
+#include <smc-rmi.h>
+#include <utils_def.h>
+
+/*
+ * Represents the state of communication between an RMM device object and a
+ * device. The device object could be PDEV or VDEV.
+ */
+#define DEV_COMM_ACTIVE U(0)
+#define DEV_COMM_ERROR U(1)
+#define DEV_COMM_IDLE U(2)
+#define DEV_COMM_PENDING U(3)
+
+/* PCIe device specific details */
+struct pcie_dev {
+ /* Device identifier */
+ uint64_t bdf;
+
+ /* PCIe Segment identifier of the Root Port and endpoint. */
+ uint16_t segment_id;
+
+ /*
+ * Physical PCIe routing identifier of the Root Port to which the
+ * endpoint is connected.
+ */
+ uint16_t root_id;
+
+ /* ECAM base address of the PCIe configuration space */
+ uint64_t ecam_addr;
+
+ /* Certificate slot identifier */
+ uint64_t cert_slot_id;
+
+ /* IDE stream ID */
+ uint64_t ide_sid;
+
+ /*
+ * Base and top of requester ID range (inclusive). The value is in
+ * PCI BDF format.
+ */
+ uint64_t rid_base;
+ uint64_t rid_top;
+
+ /* Device non-coherent address range and its range */
+ struct rmi_address_range
+ ncoh_addr_range[PDEV_PARAM_NCOH_ADDR_RANGE_MAX];
+ uint64_t ncoh_num_addr_range;
+};
+
+/*
+ * PDEV object. Represents a communication channel between the RMM and a
+ * physical device, for example a PCIe device.
+ */
+struct pdev {
+ /* Pointer to this granule */
+ struct granule *g_pdev;
+
+ /* State of this PDEV. RmiPdevState */
+ unsigned long rmi_state;
+
+ /* Flags provided by the Host during PDEV creation. RmiPdevFlags */
+ unsigned long rmi_flags;
+
+ /* Number of VDEVs associated with this PDEV */
+ uint32_t num_vdevs;
+
+ /* Number and addresses of PDEV auxiliary granules */
+ struct granule *g_aux[PDEV_PARAM_AUX_GRANULES_MAX];
+ unsigned int num_aux;
+
+ /*
+ * Algorithm used to generate device digests. This value is returned to
+ * Realm as part of RDEV_GET_INFO call
+ */
+ uint8_t rmi_hash_algo;
+
+ /* Device communiction state */
+ unsigned int dev_comm_state;
+
+ /* The associated device */
+ struct pcie_dev dev;
+
+ /* DA app cfg */
+ struct app_data_cfg da_app_data;
+};
+COMPILER_ASSERT(sizeof(struct pdev) <= GRANULE_SIZE);
+
+#endif /* DEV_H */
diff --git a/runtime/include/smc-handler.h b/runtime/include/smc-handler.h
index c24099b..82508cb 100644
--- a/runtime/include/smc-handler.h
+++ b/runtime/include/smc-handler.h
@@ -106,4 +106,7 @@
unsigned long ulevel,
struct smc_result *res);
+unsigned long smc_pdev_create(unsigned long pdev_ptr,
+ unsigned long pdev_params_ptr);
+
#endif /* SMC_HANDLER_H */
diff --git a/runtime/rmi/pdev.c b/runtime/rmi/pdev.c
new file mode 100644
index 0000000..1e1f4e8
--- /dev/null
+++ b/runtime/rmi/pdev.c
@@ -0,0 +1,279 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
+ */
+
+#include <arch.h>
+#include <arch_features.h>
+#include <buffer.h>
+#include <debug.h>
+#include <dev.h>
+#include <dev_assign_app.h>
+#include <feature.h>
+#include <granule.h>
+#include <sizes.h>
+#include <smc-handler.h>
+#include <smc-rmi.h>
+#include <string.h>
+#include <utils_def.h>
+
+/*
+ * This function will only be invoked when the PDEV create fails or when PDEV is
+ * being destroyed. Hence the PDEV will not be in use when this function is
+ * called and therefore no lock is acquired before its invocation.
+ */
+static void pdev_restore_aux_granules_state(struct granule *pdev_aux[],
+ unsigned int cnt, bool scrub)
+{
+ for (unsigned int i = 0U; i < cnt; i++) {
+ struct granule *g_pdev_aux = pdev_aux[i];
+
+ granule_lock(g_pdev_aux, GRANULE_STATE_PDEV_AUX);
+ if (scrub) {
+ buffer_granule_memzero(g_pdev_aux,
+ (enum buffer_slot)((unsigned int)SLOT_PDEV_AUX0 + i));
+ }
+ granule_unlock_transition(g_pdev_aux, GRANULE_STATE_DELEGATED);
+ }
+}
+
+/*
+ * todo:
+ * Validate device specific PDEV parameters by traversing all previously created
+ * PDEVs and check against current PDEV parameters. This implements
+ * RmiPdevParamsIsValid of RMM specification.
+ */
+static int validate_rmi_pdev_params(struct rmi_pdev_params *pd_params)
+
+{
+ (void)pd_params;
+ /*
+ * Check if device identifier, Root Port identifier, IDE stream
+ * identifier, RID range are valid.
+ */
+
+ /*
+ * Check if device identifier is not equal to the device identifier of
+ * another PDEV
+ */
+
+ /* Whether RID range does not overlap the RID range of another PDEV */
+
+ /*
+ * Every address range falls within an MMIO range permitted by the system
+ */
+
+ /*
+ * None of the address ranges overlaps another address range for this
+ * PDEV
+ */
+
+ return 0;
+}
+
+/*
+ * smc_pdev_create
+ *
+ * pdev_ptr - PA of the PDEV
+ * pdev_params_ptr - PA of PDEV parameters
+ */
+unsigned long smc_pdev_create(unsigned long pdev_ptr,
+ unsigned long pdev_params_ptr)
+{
+ struct granule *g_pdev;
+ struct granule *g_pdev_params;
+ struct pdev *pd;
+ struct rmi_pdev_params pdev_params; /* this consumes 4k of stack */
+ struct granule *pdev_aux_granules[PDEV_PARAM_AUX_GRANULES_MAX];
+ bool ns_access_ok;
+ void *aux_mapped_addr;
+ struct dev_assign_params dparams;
+ unsigned long smc_rc;
+ int rc;
+
+ if (!is_rmi_feat_da_enabled()) {
+ return SMC_NOT_SUPPORTED;
+ }
+
+ if (!GRANULE_ALIGNED(pdev_ptr) ||
+ !GRANULE_ALIGNED(pdev_params_ptr)) {
+ return RMI_ERROR_INPUT;
+ }
+
+ /* Map and copy PDEV parameters */
+ g_pdev_params = find_granule(pdev_params_ptr);
+ if ((g_pdev_params == NULL) ||
+ (granule_unlocked_state(g_pdev_params) != GRANULE_STATE_NS)) {
+ return RMI_ERROR_INPUT;
+ }
+
+ ns_access_ok = ns_buffer_read(SLOT_NS, g_pdev_params, 0U,
+ sizeof(struct rmi_pdev_params),
+ &pdev_params);
+ if (!ns_access_ok) {
+ return RMI_ERROR_INPUT;
+ }
+
+ /*
+ * Validate RmiPdevFlags. RMM supports PCIE off-chip device represented
+ * by flags: SPDM=true, IDE=true, COHERENT=false, P2P= false.
+ */
+ /* coverity[uninit_use:SUPPRESS] */
+ if ((EXTRACT(RMI_PDEV_FLAGS_SPDM, pdev_params.flags) !=
+ RMI_PDEV_SPDM_TRUE) ||
+ (EXTRACT(RMI_PDEV_FLAGS_IDE, pdev_params.flags) !=
+ RMI_PDEV_IDE_TRUE) ||
+ (EXTRACT(RMI_PDEV_FLAGS_COHERENT, pdev_params.flags) !=
+ RMI_PDEV_COHERENT_FALSE) ||
+ (EXTRACT(RMI_PDEV_FLAGS_P2P, pdev_params.flags) !=
+ RMI_PDEV_COHERENT_FALSE)) {
+ return RMI_ERROR_NOT_SUPPORTED;
+ }
+
+ /* Validate PDEV parameters that are not specific to a device class. */
+ /* coverity[uninit_use:SUPPRESS] */
+ if ((pdev_params.num_aux > PDEV_PARAM_AUX_GRANULES_MAX) ||
+ (pdev_params.ncoh_num_addr_range > PDEV_PARAM_NCOH_ADDR_RANGE_MAX)) {
+ return RMI_ERROR_INPUT;
+ }
+
+ /* Validate hash algorithm */
+ /* coverity[uninit_use:SUPPRESS] */
+ if ((pdev_params.hash_algo != RMI_HASH_SHA_256) &&
+ (pdev_params.hash_algo != RMI_HASH_SHA_512)) {
+ return RMI_ERROR_INPUT;
+ }
+
+ /* cppcheck-suppress knownConditionTrueFalse */
+ if (validate_rmi_pdev_params(&pdev_params) != 0) {
+ return RMI_ERROR_INPUT;
+ }
+
+ /* Loop through pdev_aux_granules and transit them */
+ for (unsigned int i = 0U; i < pdev_params.num_aux; i++) {
+ struct granule *g_pdev_aux;
+
+ /* coverity[uninit_use_in_call:SUPPRESS] */
+ g_pdev_aux = find_lock_granule(pdev_params.aux[i],
+ GRANULE_STATE_DELEGATED);
+ if (g_pdev_aux == NULL) {
+ pdev_restore_aux_granules_state(pdev_aux_granules, i,
+ false);
+ return RMI_ERROR_INPUT;
+ }
+ granule_unlock_transition(g_pdev_aux, GRANULE_STATE_PDEV_AUX);
+ pdev_aux_granules[i] = g_pdev_aux;
+ }
+
+ /* Lock pdev granule and map it */
+ g_pdev = find_lock_granule(pdev_ptr, GRANULE_STATE_DELEGATED);
+ if (g_pdev == NULL) {
+ smc_rc = RMI_ERROR_INPUT;
+ goto out_restore_pdev_aux_granule_state;
+ }
+
+ pd = buffer_granule_map(g_pdev, SLOT_PDEV);
+ if (pd == NULL) {
+ smc_rc = RMI_ERROR_INPUT;
+ granule_unlock_transition(g_pdev, GRANULE_STATE_DELEGATED);
+ goto out_restore_pdev_aux_granule_state;
+ }
+
+ /* Map all PDEV aux granules to slot starting SLOT_PDEV_AUX0 */
+ aux_mapped_addr = buffer_pdev_aux_granules_map(pdev_aux_granules,
+ (unsigned int)pdev_params.num_aux);
+ if (aux_mapped_addr == NULL) {
+ smc_rc = RMI_ERROR_INPUT;
+ goto out_unmap_pdev_slot_buffer;
+ }
+
+ /* Call init routine to initialize device class specific state */
+ dparams.dev_handle = (void *)pd;
+ dparams.rmi_hash_algo = pdev_params.hash_algo;
+ dparams.cert_slot_id = (uint8_t)pdev_params.cert_id;
+
+ if (EXTRACT(RMI_PDEV_FLAGS_IDE, pdev_params.flags) ==
+ RMI_PDEV_IDE_TRUE) {
+ dparams.has_ide = true;
+ dparams.ecam_addr = pdev_params.ecam_addr;
+ dparams.rp_id = pdev_params.root_id;
+ dparams.ide_sid = pdev_params.ide_sid;
+ } else {
+ dparams.has_ide = false;
+ }
+ /* Use the PDEV aux pages for the DA app */
+ uintptr_t granule_pas[PDEV_PARAM_AUX_GRANULES_MAX];
+
+ for (unsigned int i = 0; i < pdev_params.num_aux; ++i) {
+ granule_pas[i] = granule_addr(pdev_aux_granules[i]);
+ }
+
+ rc = dev_assign_app_init(&pd->da_app_data,
+ granule_pas,
+ pdev_params.num_aux,
+ aux_mapped_addr, &dparams);
+
+ if (rc == DEV_ASSIGN_STATUS_SUCCESS) {
+ /* Initialize PDEV */
+ pd->g_pdev = g_pdev;
+ pd->rmi_state = RMI_PDEV_STATE_NEW;
+ pd->rmi_flags = pdev_params.flags;
+ pd->num_vdevs = 0;
+ pd->rmi_hash_algo = pdev_params.hash_algo;
+ pd->num_aux = (unsigned int)pdev_params.num_aux;
+ (void)memcpy((void *)pd->g_aux, (void *)pdev_aux_granules, pdev_params.num_aux *
+ sizeof(struct granule *));
+
+ /* Initialize PDEV communication state */
+ pd->dev_comm_state = DEV_COMM_PENDING;
+
+ /* Initialize PDEV pcie device */
+ pd->dev.bdf = pdev_params.pdev_id;
+ pd->dev.segment_id = pdev_params.segment_id;
+ pd->dev.ecam_addr = pdev_params.ecam_addr;
+ pd->dev.root_id = pdev_params.root_id;
+ pd->dev.cert_slot_id = pdev_params.cert_id;
+ pd->dev.ide_sid = pdev_params.ide_sid;
+ pd->dev.rid_base = pdev_params.rid_base;
+ pd->dev.rid_top = pdev_params.rid_top;
+ pd->dev.ncoh_num_addr_range = pdev_params.ncoh_num_addr_range;
+ (void)memcpy(&pd->dev.ncoh_addr_range,
+ &pdev_params.ncoh_addr_range,
+ (sizeof(struct rmi_address_range) *
+ pdev_params.ncoh_num_addr_range));
+
+ smc_rc = RMI_SUCCESS;
+ } else {
+ smc_rc = RMI_ERROR_INPUT;
+ }
+
+ /* Unmap all PDEV aux granules */
+ buffer_pdev_aux_unmap(aux_mapped_addr, (unsigned int)pdev_params.num_aux);
+
+out_unmap_pdev_slot_buffer:
+ /* unmap PDEV buffer from slot PDEV */
+ buffer_unmap(pd);
+
+ /*
+ * On success, unlock and transit the PDEV granule state to
+ * GRANULE_STATE_PDEV else unlock and retain the state at
+ * GRANULE_STATE_DELEGATED.
+ */
+ if (smc_rc == RMI_SUCCESS) {
+ granule_unlock_transition(g_pdev, GRANULE_STATE_PDEV);
+ } else {
+ granule_unlock_transition(g_pdev, GRANULE_STATE_DELEGATED);
+ }
+
+out_restore_pdev_aux_granule_state:
+ if (smc_rc != RMI_SUCCESS) {
+ /*
+ * Transit all PDEV AUX granule state back to
+ * GRANULE_STATE_DELEGATED
+ */
+ pdev_restore_aux_granules_state(pdev_aux_granules,
+ (unsigned int)pdev_params.num_aux, false);
+ }
+
+ return smc_rc;
+}