feat: turn first SP vcpu off upon physical PE off

For a S-EL1 SP registering the cpu off power management event (upon
receiving the event from the SPMD on PSCI CPU OFF), turn the
corresponding pinned vCPU to off.
The implementation currently limits handling of power management
messages to S-EL1 MP SPs. In a later iteration, the SP vCPU will have to
be resumed and conveyed the power management message prior to the above
action.

Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Change-Id: I3da387c30cabe737a72da600687c9161c7e2c938
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index e29117e..3ee2181 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -358,7 +358,8 @@
 		uint32_t psci_msg_response = PSCI_ERROR_NOT_SUPPORTED;
 		struct vcpu *boot_vcpu = vcpu_get_boot_vcpu();
 		struct vm *vm = boot_vcpu->vm;
-		struct vcpu *vcpu = vm_get_vcpu(vm, vcpu_index(current));
+		struct vcpu *vcpu;
+		struct vcpu_locked vcpu_locked;
 
 		/*
 		 * TODO: the power management event reached the SPMC.
@@ -370,7 +371,18 @@
 			dlog_verbose("cpu%u off notification!\n",
 				     vcpu_index(vcpu));
 
-			cpu_off(vcpu->cpu);
+			if (vm_power_management_cpu_off_requested(vm) == true) {
+				/* Allow only S-EL1 MP SPs to reach here. */
+				CHECK(vm->el0_partition == false);
+				CHECK(vm->vcpu_count > 1);
+
+				vcpu = vm_get_vcpu(vm, vcpu_index(current));
+				vcpu_locked = vcpu_lock(vcpu);
+				vcpu->state = VCPU_STATE_OFF;
+				vcpu_unlock(&vcpu_locked);
+				cpu_off(vcpu->cpu);
+			}
+
 			psci_msg_response = PSCI_RETURN_SUCCESS;
 			break;
 		}