feat(arch timer): resume SP if deadline expires in NWd

Once a SP's vCPU is scheduled out and execution is returned to normal
world, it is likely that the timer deadline set by the vCPU could
expire in normal world.

It is the responsibility of SPMC to resume the SP's vCPU with expired
timer deadline and inject the timer virtual interrupt. It does so by
maintaining a list of all vcpus with pending timer and tracking the
nearest deadline with host timer whenever exiting to normal world.

When the SP's vCPU is eventually descheduled, SPMC will remove the vCPU
entry from the list if the corresponding arch timer is disabled.

Change-Id: I11d63f89cef320e41980eaf10188f8a72ed84cec
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/src/arch/aarch64/hypervisor/exceptions.S b/src/arch/aarch64/hypervisor/exceptions.S
index f0476e4..753e149 100644
--- a/src/arch/aarch64/hypervisor/exceptions.S
+++ b/src/arch/aarch64/hypervisor/exceptions.S
@@ -651,6 +651,14 @@
 	mov x0, x19
 	bl plat_restore_ns_simd_context
 
+	/*
+	 * A helper utility that serves as a placeholder for SPMC to take
+	 * necessary actions before relinquishing CPU cycles to normal world
+	 * through SMC call.
+	 */
+	mov x0, x19
+	bl spmc_exit_to_nwd
+
 	/* Restore peripheral registers. */
 	add x2, x19, #VCPU_TIMER
 
@@ -658,9 +666,9 @@
 	vhe_support_check x1, vhe_timer_restore
 
 	/*
-	 * SPMC does not allow Secure Partitions to access EL1 Physical timer
-	 * registers. Hence, no need to save or restore them when entering or
-	 * leaving from/to normal world.
+	 * SPMC traps and emulates access to EL1 Physical timer registers from
+	 * Secure Partitions. Hence, no need to save or restore them when
+	 * entering or leaving from/to normal world.
 	 */
 	ldp x24, x25, [x2]
 	msr cntv_cval_el0, x24
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index c4ca2ed..d36f78e 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -406,6 +406,21 @@
 		return true;
 	}
 }
+
+void spmc_exit_to_nwd(struct vcpu *owd_vcpu)
+{
+	struct vcpu *deadline_vcpu =
+		timer_find_vcpu_nearest_deadline(owd_vcpu->cpu);
+
+	/*
+	 * SPMC tracks a vCPU's timer deadline through its host timer such that
+	 * it can bring back execution from normal world to signal the timer
+	 * virtual interrupt to the SP's vCPU.
+	 */
+	if (deadline_vcpu != NULL) {
+		host_timer_track_deadline(&deadline_vcpu->regs.arch_timer);
+	}
+}
 #endif
 
 /**