feat(app/device_assignment): add transition pdev from has_key to ready

Add support in pdev_communicate RMI handler to transition pdev state
from RMI_PDEV_STATE_HAS_KEY to RMI_PDEV_STATE_READY.

If pdev_communicate is called when the state is RMI_PDEV_STATE_HAS_KEY
then it issues SPDM_SECURE_SESSION command to establish a secure
session.

Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I81849fa52671016c8ec95921dbc01af99a6cd512
diff --git a/app/device_assignment/el0_app/src/dev_assign_cmds.c b/app/device_assignment/el0_app/src/dev_assign_cmds.c
index 94f4101..0cb7469 100644
--- a/app/device_assignment/el0_app/src/dev_assign_cmds.c
+++ b/app/device_assignment/el0_app/src/dev_assign_cmds.c
@@ -141,9 +141,70 @@
 	return (int)LIBSPDM_STATUS_SUCCESS;
 }
 
+/* dev_assign_cmd_start_session_main */
+int dev_assign_cmd_start_session_main(struct dev_assign_info *info)
+{
+	uint32_t session_id = 0U;
+	libspdm_return_t status;
+
+	/*
+	 * Call libspdm_challenge() as it helps to validate spdm_cert_chain_hash
+	 * and public key before key_exchange call. Useful for debugging.
+	 */
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+	status = libspdm_challenge(info->libspdm_ctx, NULL, 0,
+			SPDM_CHALLENGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH,
+				NULL, NULL);
+	VERBOSE("libspdm_challenge: 0x%x\n", status);
+	if (status != LIBSPDM_STATUS_SUCCESS) {
+		return DEV_ASSIGN_STATUS_ERROR;
+	}
+#endif
+
+	/*
+	 * Start SPDM session. Set session policy to 0, this terminates the
+	 * session upon device firmware or configuration update.
+	 */
+	status = libspdm_start_session(info->libspdm_ctx,
+				       false, /* use_psk */
+				       NULL, /* psk_hint */
+				       0, /* psk_hint size */
+	       SPDM_REQUEST_NO_MEASUREMENT_SUMMARY_HASH, /* meas hash type */
+				       info->cert_slot_id, /* slot id */
+				       0, /* session policy */
+				       &session_id,
+				       NULL, /* hbeat period */
+				       NULL /* measurement_hash */);
+	if (status == LIBSPDM_STATUS_SUCCESS) {
+		info->session_id = session_id;
+		VERBOSE("SPDM secure session id: 0x%x\n", info->session_id);
+		return DEV_ASSIGN_STATUS_SUCCESS;
+	}
+
+	return DEV_ASSIGN_STATUS_ERROR;
+}
+
 /* dev_assign_cmd_stop_connection_main */
 int dev_assign_cmd_stop_connection_main(struct dev_assign_info *info)
 {
+	int rc = DEV_ASSIGN_STATUS_SUCCESS;
+
+	if (info->session_id != 0U) {
+		/* Terminate the connection. This closes the secure session */
+		libspdm_return_t status = libspdm_stop_session(info->libspdm_ctx,
+							       info->session_id,
+							       0 /* end_session_attributes */);
+
+		if (status != LIBSPDM_STATUS_SUCCESS) {
+			ERROR("SPDM_END_SESSION failed: 0x%x\n", status);
+			rc = DEV_ASSIGN_STATUS_ERROR;
+			/*assert(false);*/
+		} else {
+			INFO("SPDM_END_SESSION completed: 0x%x\n", status);
+			info->session_id = 0U;
+		}
+	}
+
 	/* Send GET_VERSION, this resets the SPDM connection */
 	(void)libspdm_init_connection(info->libspdm_ctx, true);
 
@@ -156,5 +217,5 @@
 	/* Clean up the cma spdm connection state */
 	init_connection_cleanup(info, true);
 
-	return DEV_ASSIGN_STATUS_SUCCESS;
+	return rc;
 }
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
index 5a26820..e48390c 100644
--- a/app/device_assignment/el0_app/src/dev_assign_el0_app.c
+++ b/app/device_assignment/el0_app/src/dev_assign_el0_app.c
@@ -698,6 +698,7 @@
 	}
 	info->spdm_cert_chain_digest_length = 0;
 	info->pk_ctx.initialised = false;
+	info->session_id = 0U;
 
 	info->psa_hash_algo = rmi_to_psa_hash_algo(params->rmi_hash_algo);
 
@@ -869,6 +870,9 @@
 	case DEVICE_ASSIGN_APP_FUNC_ID_CONNECT_INIT:
 		ret = (unsigned long)dev_assign_cmd_init_connection_main(info);
 		break;
+	case DEVICE_ASSIGN_APP_FUNC_ID_SECURE_SESSION:
+		ret = (unsigned long)dev_assign_cmd_start_session_main(info);
+		break;
 	case DEVICE_ASSIGN_APP_FUNC_ID_STOP_CONNECTION:
 		ret = (unsigned long)dev_assign_cmd_stop_connection_main(info);
 		break;
@@ -910,6 +914,7 @@
 			(struct dev_assign_params *)shared);
 	}
 	case DEVICE_ASSIGN_APP_FUNC_ID_CONNECT_INIT:
+	case DEVICE_ASSIGN_APP_FUNC_ID_SECURE_SESSION:
 	case DEVICE_ASSIGN_APP_FUNC_ID_STOP_CONNECTION:
 		return dev_assign_communicate_cmd_cmn(func_id, heap);
 	case DEVICE_ASSIGN_APP_FUNC_SET_PUBLIC_KEY:
diff --git a/app/device_assignment/el0_app/src/dev_assign_private.h b/app/device_assignment/el0_app/src/dev_assign_private.h
index 4afbcb5..2c33ec8 100644
--- a/app/device_assignment/el0_app/src/dev_assign_private.h
+++ b/app/device_assignment/el0_app/src/dev_assign_private.h
@@ -292,6 +292,7 @@
 };
 
 int dev_assign_cmd_init_connection_main(struct dev_assign_info *info);
+int dev_assign_cmd_start_session_main(struct dev_assign_info *info);
 int dev_assign_cmd_stop_connection_main(struct dev_assign_info *info);
 
 void dev_assign_unset_pubkey(struct dev_assign_info *info);
diff --git a/app/device_assignment/rmm_stub/include/dev_assign_structs.h b/app/device_assignment/rmm_stub/include/dev_assign_structs.h
index b46e162..14acd8e 100644
--- a/app/device_assignment/rmm_stub/include/dev_assign_structs.h
+++ b/app/device_assignment/rmm_stub/include/dev_assign_structs.h
@@ -128,6 +128,14 @@
 #define DEVICE_ASSIGN_APP_FUNC_ID_DEINIT		4
 
 /*
+ * App function ID to start a libspdm session
+ *
+ * ret0 == DEV_ASSIGN_STATUS_SUCCESS if the session is started successfully.
+ *         DEV_ASSIGN_STATUS_ERROR if libspdm returned error.
+ */
+#define DEVICE_ASSIGN_APP_FUNC_ID_SECURE_SESSION	11
+
+/*
  * App function ID to stop the libspdm session that is associated with this app
  * instance.
  *
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 5f3d407..8c8673a 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
@@ -59,7 +59,8 @@
 
 	assert((dev_cmd == DEVICE_ASSIGN_APP_FUNC_ID_RESUME) ||
 		(dev_cmd == DEVICE_ASSIGN_APP_FUNC_ID_CONNECT_INIT) ||
-		(dev_cmd == DEVICE_ASSIGN_APP_FUNC_ID_STOP_CONNECTION));
+		(dev_cmd == DEVICE_ASSIGN_APP_FUNC_ID_STOP_CONNECTION) ||
+		(dev_cmd == DEVICE_ASSIGN_APP_FUNC_ID_SECURE_SESSION));
 
 	app_map_shared_page(app_data);
 	shared = app_data->el2_shared_page;
diff --git a/runtime/rmi/pdev.c b/runtime/rmi/pdev.c
index c5dde93..cc20131 100644
--- a/runtime/rmi/pdev.c
+++ b/runtime/rmi/pdev.c
@@ -441,6 +441,10 @@
 		rc = dev_assign_dev_communicate(&pd->da_app_data, enter_args,
 			exit_args, comm_digest_ptr, DEVICE_ASSIGN_APP_FUNC_ID_CONNECT_INIT);
 		break;
+	case RMI_PDEV_STATE_HAS_KEY:
+		rc = dev_assign_dev_communicate(&pd->da_app_data, enter_args,
+			exit_args, comm_digest_ptr, DEVICE_ASSIGN_APP_FUNC_ID_SECURE_SESSION);
+		break;
 	case RMI_PDEV_STATE_STOPPING:
 		rc = dev_assign_dev_communicate(&pd->da_app_data, enter_args,
 			exit_args, comm_digest_ptr, DEVICE_ASSIGN_APP_FUNC_ID_STOP_CONNECTION);
@@ -566,6 +570,8 @@
 	case DEV_COMM_IDLE:
 		if (pd->rmi_state == RMI_PDEV_STATE_NEW) {
 			pd->rmi_state = RMI_PDEV_STATE_NEEDS_KEY;
+		} else if (pd->rmi_state == RMI_PDEV_STATE_HAS_KEY) {
+			pd->rmi_state = RMI_PDEV_STATE_READY;
 		} else if (pd->rmi_state == RMI_PDEV_STATE_STOPPING) {
 			pd->rmi_state = RMI_PDEV_STATE_STOPPED;
 		} else {