Fix bug when handling EL1 debug register accesses

Certain registers weren't correctly encoded.  Make the encoding scheme similar
to the tables in the Arm Architecture Reference Manual to make it easier to add
new registers as well as spot incorrectly encoded ones.

Fix bug when handling system register accesses with the zero register (XZR) as
the source or the destination.

Log accesses to unhandled registers before they abort, with details on the
encoding of the unhandled register access.

Separate code that is not strictly related to debug registers to facilitate
adding support for performance monitor registers in the future.

Bug: 141452761
Change-Id: Idf717ec56a66ada69d20c590ec2182845afd84b1
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 107f02b..2406768 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -35,6 +35,7 @@
 #include "psci.h"
 #include "psci_handler.h"
 #include "smc.h"
+#include "sysregs.h"
 
 #define HCR_EL2_VI (1u << 7)
 
@@ -595,23 +596,29 @@
 	struct vcpu *vcpu = current();
 	spci_vm_id_t vm_id = vcpu->vm->id;
 	uintreg_t ec = GET_EC(esr);
+	char *direction_str;
 
 	CHECK(ec == 0x18);
 
 	/*
-	 * Handle accesses to other registers that trap with the same EC.
+	 * Handle accesses to debug registers.
 	 * Abort when encountering unhandled register accesses.
 	 */
-	if (!is_debug_el1_register_access(esr)) {
-		return api_abort(vcpu);
+	if (is_debug_el1_register_access(esr) &&
+	    debug_el1_process_access(vcpu, vm_id, esr)) {
+		/* Instruction was fulfilled. Skip it and run the next one. */
+		vcpu->regs.pc += GET_NEXT_PC_INC(esr);
+		return NULL;
 	}
 
-	/* Abort if unable to fulfill the debug register access. */
-	if (!debug_el1_process_access(vcpu, vm_id, esr)) {
-		return api_abort(vcpu);
-	}
+	direction_str = ISS_IS_READ(esr) ? "read" : "write";
 
-	/* Instruction was fulfilled above. Skip it and run the next one. */
-	vcpu->regs.pc += GET_NEXT_PC_INC(esr);
-	return NULL;
+	dlog("Unhandled system register %s: op0=%d, op1=%d, crn=%d, "
+	     "crm=%d, op2=%d, rt=%d.\n",
+	     direction_str, GET_ISS_OP0(esr), GET_ISS_OP1(esr),
+	     GET_ISS_CRN(esr), GET_ISS_CRM(esr), GET_ISS_OP2(esr),
+	     GET_ISS_RT(esr));
+
+	/* Abort if unable to fulfill the register access. */
+	return api_abort(vcpu);
 }