Get rid of 'fast path' for HVC calls.

It is unlikely to be much faster in practice, and complicates the code.

Bug: 141469322
Change-Id: I3d12edf6096fff5a1a14b4fc5336084b90ff90ac
diff --git a/src/arch/aarch64/hypervisor/exceptions.S b/src/arch/aarch64/hypervisor/exceptions.S
index 1e30fe1..4a89f47 100644
--- a/src/arch/aarch64/hypervisor/exceptions.S
+++ b/src/arch/aarch64/hypervisor/exceptions.S
@@ -18,19 +18,15 @@
 #include "exception_macros.S"
 
 /**
- * Saves the volatile registers into the register buffer of the current vcpu. It
- * allocates space on the stack for x18 and saves it if "also_save_x18" is
- * specified; otherwise the caller is expected to have saved x18 in a similar
- * fashion.
+ * Saves the volatile registers into the register buffer of the current vcpu.
  */
-.macro save_volatile_to_vcpu also_save_x18
-.ifnb \also_save_x18
+.macro save_volatile_to_vcpu
 	/*
 	 * Save x18 since we're about to clobber it. We subtract 16 instead of
 	 * 8 from the stack pointer to keep it 16-byte aligned.
 	 */
 	str x18, [sp, #-16]!
-.endif
+
 	/* Get the current vcpu. */
 	mrs x18, tpidr_el2
 	stp x0, x1, [x18, #VCPU_REGS + 8 * 0]
@@ -63,7 +59,7 @@
  * registers from the new vcpu.
  */
 .macro lower_exception handler:req
-	save_volatile_to_vcpu also_save_x18
+	save_volatile_to_vcpu
 
 	/* Call C handler. */
 	bl \handler
@@ -77,67 +73,29 @@
 .endm
 
 /**
- * This is the handler for a sync exception taken at a lower EL. If the reason
- * for the exception is an HVC call, it calls the faster hvc_handler without
- * saving a lot of the registers, otherwise it goes to slow_sync_lower, which is
- * the slow path where all registers needs to be saved/restored.
+ * This is the handler for a sync exception taken at a lower EL.
  */
 .macro lower_sync_exception
-	/* Save x18 as save_volatile_to_vcpu would have. */
-	str x18, [sp, #-16]!
+	save_volatile_to_vcpu
 
 	/* Extract the exception class (EC) from exception syndrome register. */
 	mrs x18, esr_el2
 	lsr x18, x18, #26
 
-	/* Take the slow path if exception is not due to an HVC instruction. */
-	sub x18, x18, #0x16
-	cbnz x18, slow_sync_lower
+	/* Take the system register path for EC 0x18. */
+	sub x18, x18, #0x18
+	cbz x18, system_register_access
 
-	/*
-	 * Save x4-x17, x29 and x30, which are not saved by the callee, then jump to
-	 * HVC handler.
-	 */
-	stp x4, x5, [sp, #-16]!
-	stp x6, x7, [sp, #-16]!
-	stp x8, x9, [sp, #-16]!
-	stp x10, x11, [sp, #-16]!
-	stp x12, x13, [sp, #-16]!
-	stp x14, x15, [sp, #-16]!
-	stp x16, x17, [sp, #-16]!
-	stp x29, x30, [sp, #-16]!
+	/* Read syndrome register and call C handler. */
+	mrs x0, esr_el2
+	bl sync_lower_exception
 
-	/*
-	 * Make room for hvc_handler_return on stack, and point x8 (the indirect
-	 * result location register in the AAPCS64 standard) to it.
-	 * hvc_handler_return is returned this way according to paragraph
-	 * 5.4.2.B.3 and section 5.5 because it is larger than 16 bytes.
-	 */
-	stp xzr, xzr, [sp, #-16]!
-	stp xzr, xzr, [sp, #-16]!
-	stp xzr, xzr, [sp, #-16]!
-	mov x8, sp
+	/* Switch vcpu if requested by handler. */
+	cbnz x0, vcpu_switch
 
-	bl hvc_handler
-
-	/* Get the hvc_handler_return back off the stack. */
-	ldp x0, x1, [sp], #16
-	ldp x2, x3, [sp], #16
-	ldr x18, [sp], #16
-
-	ldp x29, x30, [sp], #16
-	ldp x16, x17, [sp], #16
-	ldp x14, x15, [sp], #16
-	ldp x12, x13, [sp], #16
-	ldp x10, x11, [sp], #16
-	ldp x8, x9, [sp], #16
-	ldp x6, x7, [sp], #16
-	ldp x4, x5, [sp], #16
-
-	cbnz x18, sync_lower_switch
-	/* Restore x18, which was saved on the stack. */
-	ldr x18, [sp], #16
-	eret
+	/* vcpu is not changing. */
+	mrs x0, tpidr_el2
+	b vcpu_restore_volatile_and_run
 .endm
 
 /**
@@ -212,26 +170,6 @@
 	lower_exception serr_lower
 
 .balign 0x40
-slow_sync_lower:
-	/* The caller must have saved x18, so we don't save it here. */
-	save_volatile_to_vcpu
-
-	/* Extract the exception class (EC) from exception syndrome register. */
-	mrs x18, esr_el2
-	lsr x18, x18, #26
-
-	/* Take the system register path for EC 0x18. */
-	sub x18, x18, #0x18
-	cbz x18, system_register_access
-
-	/* Read syndrome register and call C handler. */
-	mrs x0, esr_el2
-	bl sync_lower_exception
-	cbnz x0, vcpu_switch
-
-	/* vcpu is not changing. */
-	mrs x0, tpidr_el2
-	b vcpu_restore_volatile_and_run
 
 /**
  * Handle accesses to system registers (EC=0x18) and return to original caller.
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index a695938..107f02b 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -49,11 +49,6 @@
  */
 #define GET_NEXT_PC_INC(esr) (((esr) & (1u << 25)) ? 4 : 2)
 
-struct hvc_handler_return {
-	smc_res_t user_ret;
-	struct vcpu *new;
-};
-
 /**
  * Returns a reference to the currently executing vCPU.
  */
@@ -366,89 +361,89 @@
 	return smc_forwarder(vcpu, ret);
 }
 
-struct hvc_handler_return hvc_handler(uintreg_t arg0, uintreg_t arg1,
-				      uintreg_t arg2, uintreg_t arg3)
+struct vcpu *hvc_handler(struct vcpu *vcpu)
 {
-	struct hvc_handler_return ret;
+	uint32_t func = vcpu->regs.r[0];
+	uintreg_t arg1 = vcpu->regs.r[1];
+	uintreg_t arg2 = vcpu->regs.r[2];
+	uintreg_t arg3 = vcpu->regs.r[3];
+	struct vcpu *next = NULL;
 
-	ret.new = NULL;
-
-	if (psci_handler(current(), arg0, arg1, arg2, arg3, &ret.user_ret.res0,
-			 &ret.new)) {
-		return ret;
+	if (psci_handler(vcpu, func, arg1, arg2, arg3, &vcpu->regs.r[0],
+			 &next)) {
+		return next;
 	}
 
-	if (spci_handler(arg0, arg1, arg2, arg3, &ret.user_ret.res0,
-			 &ret.new)) {
-		update_vi(ret.new);
-		return ret;
+	if (spci_handler(func, arg1, arg2, arg3, &vcpu->regs.r[0], &next)) {
+		update_vi(next);
+		return next;
 	}
 
-	switch ((uint32_t)arg0) {
+	switch (func) {
 	case HF_VM_GET_ID:
-		ret.user_ret.res0 = api_vm_get_id(current());
+		vcpu->regs.r[0] = api_vm_get_id(vcpu);
 		break;
 
 	case HF_VM_GET_COUNT:
-		ret.user_ret.res0 = api_vm_get_count();
+		vcpu->regs.r[0] = api_vm_get_count();
 		break;
 
 	case HF_VCPU_GET_COUNT:
-		ret.user_ret.res0 = api_vcpu_get_count(arg1, current());
+		vcpu->regs.r[0] = api_vcpu_get_count(arg1, vcpu);
 		break;
 
 	case HF_VCPU_RUN:
-		ret.user_ret.res0 = hf_vcpu_run_return_encode(
-			api_vcpu_run(arg1, arg2, current(), &ret.new));
+		vcpu->regs.r[0] = hf_vcpu_run_return_encode(
+			api_vcpu_run(arg1, arg2, vcpu, &next));
 		break;
 
 	case HF_VM_CONFIGURE:
-		ret.user_ret.res0 = api_vm_configure(
-			ipa_init(arg1), ipa_init(arg2), current(), &ret.new);
+		vcpu->regs.r[0] = api_vm_configure(ipa_init(arg1),
+						   ipa_init(arg2), vcpu, &next);
 		break;
 
 	case HF_MAILBOX_CLEAR:
-		ret.user_ret.res0 = api_mailbox_clear(current(), &ret.new);
+		vcpu->regs.r[0] = api_mailbox_clear(vcpu, &next);
 		break;
 
 	case HF_MAILBOX_WRITABLE_GET:
-		ret.user_ret.res0 = api_mailbox_writable_get(current());
+		vcpu->regs.r[0] = api_mailbox_writable_get(vcpu);
 		break;
 
 	case HF_MAILBOX_WAITER_GET:
-		ret.user_ret.res0 = api_mailbox_waiter_get(arg1, current());
+		vcpu->regs.r[0] = api_mailbox_waiter_get(arg1, vcpu);
 		break;
 
 	case HF_INTERRUPT_ENABLE:
-		ret.user_ret.res0 = api_interrupt_enable(arg1, arg2, current());
+		vcpu->regs.r[0] = api_interrupt_enable(arg1, arg2, vcpu);
 		break;
 
 	case HF_INTERRUPT_GET:
-		ret.user_ret.res0 = api_interrupt_get(current());
+		vcpu->regs.r[0] = api_interrupt_get(vcpu);
 		break;
 
 	case HF_INTERRUPT_INJECT:
-		ret.user_ret.res0 = api_interrupt_inject(arg1, arg2, arg3,
-							 current(), &ret.new);
+		vcpu->regs.r[0] =
+			api_interrupt_inject(arg1, arg2, arg3, vcpu, &next);
 		break;
 
 	case HF_SHARE_MEMORY:
-		ret.user_ret.res0 =
+		vcpu->regs.r[0] =
 			api_share_memory(arg1 >> 32, ipa_init(arg2), arg3,
-					 arg1 & 0xffffffff, current());
+					 arg1 & 0xffffffff, vcpu);
 		break;
 
 	case HF_DEBUG_LOG:
-		ret.user_ret.res0 = api_debug_log(arg1, current());
+		vcpu->regs.r[0] = api_debug_log(arg1, vcpu);
 		break;
 
 	default:
-		ret.user_ret.res0 = -1;
+		vcpu->regs.r[0] = SMCCC_ERROR_UNKNOWN;
 	}
 
-	update_vi(ret.new);
+	update_vi(next);
 
-	return ret;
+	return next;
 }
 
 struct vcpu *irq_lower(void)
@@ -546,6 +541,9 @@
 		}
 		break;
 
+	case 0x16: /* EC = 010110, HVC instruction */
+		return hvc_handler(vcpu);
+
 	case 0x17: /* EC = 010111, SMC instruction. */ {
 		uintreg_t smc_pc = vcpu->regs.pc;
 		smc_res_t ret;
@@ -554,7 +552,7 @@
 		if (!smc_handler(vcpu, &ret, &next)) {
 			/* TODO(b/132421503): handle SMC forward rejection  */
 			dlog("Unsupported SMC call: %#x\n", vcpu->regs.r[0]);
-			ret.res0 = PSCI_ERROR_NOT_SUPPORTED;
+			ret.res0 = SMCCC_ERROR_UNKNOWN;
 		}
 
 		/* Skip the SMC instruction. */