feat: implement state machine for vCPU state transitions

This patch implements the state machine which tracks the various
legal transitions allowed for a vCPU as defined by the rules in
the FF-A v1.3 ALP2 specification.

Change-Id: I03f2d398b1ffc965e69449277536403605267766
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/src/api.c b/src/api.c
index aff2efa..cf3cd18 100644
--- a/src/api.c
+++ b/src/api.c
@@ -143,7 +143,7 @@
 	arch_regs_set_retval(&next->regs, to_ret);
 
 	/* Set the current vCPU state. */
-	current_locked.vcpu->state = vcpu_state;
+	CHECK(vcpu_state_set(current_locked, vcpu_state));
 
 	return next;
 }
@@ -1319,7 +1319,8 @@
 			vcpu->rt_model = RTM_NONE;
 
 			vcpu_was_init_state = true;
-			vcpu->state = VCPU_STATE_STARTING;
+			CHECK(vcpu_state_set(vcpu_next_locked,
+					     VCPU_STATE_STARTING));
 			break;
 		}
 		*run_ret = ffa_error(FFA_BUSY);
@@ -1487,7 +1488,7 @@
 
 	assert(!vm_id_is_current_world(current->vm->id) ||
 	       next_state == VCPU_STATE_BLOCKED);
-	current->state = VCPU_STATE_BLOCKED;
+	CHECK(vcpu_state_set(current_locked, VCPU_STATE_BLOCKED));
 
 	/*
 	 * Set a placeholder return code to the scheduler. This will be
@@ -2970,7 +2971,8 @@
 				"Receiver VM %#x aborted, cannot run vCPU %u\n",
 				receiver_vcpu->vm->id,
 				vcpu_index(receiver_vcpu));
-			receiver_vcpu->state = VCPU_STATE_ABORTED;
+			CHECK(vcpu_state_set(receiver_vcpu_locked,
+					     VCPU_STATE_ABORTED));
 		}
 	}
 
@@ -3016,7 +3018,7 @@
 
 	assert(!vm_id_is_current_world(current->vm->id) ||
 	       next_state == VCPU_STATE_BLOCKED);
-	current->state = VCPU_STATE_BLOCKED;
+	CHECK(vcpu_state_set(current_locked, VCPU_STATE_BLOCKED));
 
 	ffa_direct_msg_wind_call_chain_ffa_direct_req(
 		current_locked, receiver_vcpu_locked, sender_vm_id);
@@ -3252,6 +3254,9 @@
 	ffa_direct_msg_unwind_call_chain_ffa_direct_resp(current_locked,
 							 next_locked);
 
+	/* Schedule the receiver's vCPU now. */
+	CHECK(vcpu_state_set(next_locked, VCPU_STATE_RUNNING));
+
 	/*
 	 * Check if there is a pending interrupt, and if the partition
 	 * is expects to notify the scheduler or resume straight away.