feat(runtime/rmi): implement RMI_PDEV_ABORT
Abort device communication associated with a PDEV. The pending device
communication command is resumed and the recv callback handler aborts
the command. This call the CMA SPDM layer to do the CMA SPDM command
specific cleanup.
Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: Ic151ae8af1b13164a59171583e5ed021ef55808d
diff --git a/app/device_assignment/rmm_stub/include/dev_assign_app.h b/app/device_assignment/rmm_stub/include/dev_assign_app.h
index af4fdf5..9714288 100644
--- a/app/device_assignment/rmm_stub/include/dev_assign_app.h
+++ b/app/device_assignment/rmm_stub/include/dev_assign_app.h
@@ -48,4 +48,18 @@
struct rmi_dev_comm_exit *comm_exit_args,
int dev_cmd);
+/*
+ * Aborts the current communication with the device.
+ * Arguments:
+ * app_data - Pointer to app_data_cfg. This is opaque to caller
+ *
+ * This command updates the status field of the struct rmi_dev_comm_enter
+ * is going to be read by spdm_send_message. The value is set to error, and the
+ * app is resumed, which causes the app to abort the operation and return with
+ * error.
+ *
+ * Returns DEV_ASSIGN_STATUS_SUCCESS.
+ */
+int dev_assign_abort_app_operation(struct app_data_cfg *app_data);
+
#endif /* DEV_ASSIGN_APP_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
index 7861b23..9486950 100644
--- a/app/device_assignment/rmm_stub/src/dev_assign_app_stub.c
+++ b/app/device_assignment/rmm_stub/src/dev_assign_app_stub.c
@@ -80,3 +80,23 @@
return rc;
}
+
+int dev_assign_abort_app_operation(struct app_data_cfg *app_data)
+{
+ unsigned long rc __unused;
+ struct rmi_dev_comm_enter *shared;
+
+ /*
+ * The app copies the enter_args from the shared page. So set the status
+ * on the shared page to error, which will result app return
+ * immediately, unwinding its stack, and returning error.
+ */
+ app_map_shared_page(app_data);
+ shared = app_data->el2_shared_page;
+ shared->status = (unsigned char)RMI_DEV_COMM_ENTER_STATUS_ERROR;
+ rc = app_resume(app_data);
+ assert(rc == (unsigned long)DEV_ASSIGN_STATUS_ERROR);
+ app_unmap_shared_page(app_data);
+
+ return DEV_ASSIGN_STATUS_SUCCESS;
+}
diff --git a/runtime/core/handler.c b/runtime/core/handler.c
index 24947e1..140a746 100644
--- a/runtime/core/handler.c
+++ b/runtime/core/handler.c
@@ -161,7 +161,7 @@
HANDLER(RTT_SET_RIPAS, 4, 1, smc_rtt_set_ripas, false, true),
HANDLER(DEV_MEM_MAP, 4, 0, smc_dev_mem_map, false, true),
HANDLER(DEV_MEM_UNMAP, 3, 2, smc_dev_mem_unmap, false, true),
- HANDLER(PDEV_ABORT, 0, 0, NULL, true, true),
+ HANDLER(PDEV_ABORT, 1, 0, smc_pdev_abort, true, true),
HANDLER(PDEV_COMMUNICATE, 2, 0, smc_pdev_communicate, true, true),
HANDLER(PDEV_CREATE, 2, 0, smc_pdev_create, true, true),
HANDLER(PDEV_DESTROY, 1, 0, smc_pdev_destroy, true, true),
diff --git a/runtime/include/smc-handler.h b/runtime/include/smc-handler.h
index fc919ff..75bb669 100644
--- a/runtime/include/smc-handler.h
+++ b/runtime/include/smc-handler.h
@@ -116,6 +116,8 @@
void smc_pdev_get_state(unsigned long pdev_ptr, struct smc_result *res);
+unsigned long smc_pdev_abort(unsigned long pdev_ptr);
+
unsigned long smc_pdev_destroy(unsigned long pdev_ptr);
#endif /* SMC_HANDLER_H */
diff --git a/runtime/rmi/pdev.c b/runtime/rmi/pdev.c
index 210eb76..f2afd06 100644
--- a/runtime/rmi/pdev.c
+++ b/runtime/rmi/pdev.c
@@ -618,6 +618,93 @@
}
/*
+ * Abort device communication associated with a PDEV.
+ *
+ * pdev_ptr - PA of the PDEV
+ */
+unsigned long smc_pdev_abort(unsigned long pdev_ptr)
+{
+ int rc __unused;
+ struct granule *g_pdev;
+ void *aux_mapped_addr;
+ unsigned long smc_rc;
+ struct pdev *pd;
+
+ if (!is_rmi_feat_da_enabled()) {
+ return SMC_NOT_SUPPORTED;
+ }
+
+ if (!GRANULE_ALIGNED(pdev_ptr)) {
+ return RMI_ERROR_INPUT;
+ }
+
+ /* Lock pdev granule and map it */
+ g_pdev = find_lock_granule(pdev_ptr, GRANULE_STATE_PDEV);
+ if (g_pdev == NULL) {
+ return RMI_ERROR_INPUT;
+ }
+
+ pd = buffer_granule_map(g_pdev, SLOT_PDEV);
+ if (pd == NULL) {
+ granule_unlock(g_pdev);
+ return RMI_ERROR_INPUT;
+ }
+
+ if ((pd->rmi_state != RMI_PDEV_STATE_NEW) &&
+ (pd->rmi_state != RMI_PDEV_STATE_HAS_KEY) &&
+ (pd->rmi_state != RMI_PDEV_STATE_COMMUNICATING)) {
+ smc_rc = RMI_ERROR_DEVICE;
+ goto out_pdev_buf_unmap;
+ }
+
+ /*
+ * If there is no active device communication, then mapping aux
+ * granules and cancelling an existing communication is not required.
+ */
+ if (pd->dev_comm_state != DEV_COMM_ACTIVE) {
+ goto pdev_reset_state;
+ }
+
+ /* Map PDEV aux granules */
+ aux_mapped_addr = buffer_pdev_aux_granules_map(pd->g_aux, pd->num_aux);
+ assert(aux_mapped_addr != NULL);
+
+ /*
+ * This will resume the blocked CMA SPDM command and the recv callback
+ * handler will return error and abort the command.
+ */
+ rc = dev_assign_abort_app_operation(&pd->da_app_data);
+ assert(rc == 0);
+
+ /* Unmap all PDEV aux granules */
+ buffer_pdev_aux_unmap(aux_mapped_addr, pd->num_aux);
+
+pdev_reset_state:
+ /*
+ * As the device communication is aborted, if the PDEV is in
+ * communicating state then set the state to READY state.
+ *
+ * For other PDEV states, transition the comm_state to PENDING
+ * indicating RMM has device request which is ready to be sent to the
+ * device.
+ */
+ if (pd->rmi_state == RMI_PDEV_STATE_COMMUNICATING) {
+ pd->rmi_state = RMI_PDEV_STATE_READY;
+ pd->dev_comm_state = DEV_COMM_IDLE;
+ } else {
+ pd->dev_comm_state = DEV_COMM_PENDING;
+ }
+ smc_rc = RMI_SUCCESS;
+
+out_pdev_buf_unmap:
+ buffer_unmap(pd);
+
+ granule_unlock(g_pdev);
+
+ return smc_rc;
+}
+
+/*
* Destroy a PDEV. Host can reclaim PDEV resources when the PDEV state is STOPPED
* using RMI PDEV_DESTROY.
*