Add support for accessing EL1 debug registers

For now, the primary vm can access all debug registers, whereas secondary vms
cannot.  Debug event exceptions are disabled for secondary vms, so a malicious
primary cannot have active breakpoints or watchpoints for secondary vms.

This code allows us in the future to add debug support to secondary vms, and to
have fine-grained control over which registers are allowed, either by the
primary or secondary, as well as change the behavior for such accesses.

Bug: 132422368
Change-Id: I616454cc12bea6b8dfebbbdb566ac64c0a6625c2
diff --git a/src/arch/aarch64/hypervisor/debug_el1.c b/src/arch/aarch64/hypervisor/debug_el1.c
new file mode 100644
index 0000000..d278349
--- /dev/null
+++ b/src/arch/aarch64/hypervisor/debug_el1.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2019 The Hafnium Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "debug_el1.h"
+
+#include "hf/check.h"
+#include "hf/dlog.h"
+#include "hf/panic.h"
+#include "hf/types.h"
+
+#include "msr.h"
+
+/**
+ * Controls traps for Trace Filter.
+ */
+#define MDCR_EL2_TTRF (1u << 19)
+
+/**
+ * Controls traps for Debug ROM.
+ */
+#define MDCR_EL2_TDRA (1u << 11)
+
+/**
+ * Controls traps for OS-Related Register Access.
+ */
+#define MDCR_EL2_TDOSA (1u << 10)
+
+/**
+ * Controls traps for remaining Debug Registers not trapped by TDRA and TDOSA.
+ */
+#define MDCR_EL2_TDA (1u << 9)
+
+/**
+ * Controls traps for all debug exceptions (e.g., breakpoints).
+ */
+#define MDCR_EL2_TDE (1u << 8)
+
+/**
+ * Controls traps for debug events, i.e., breakpoints, watchpoints, and vector.
+ * catch exceptions.
+ */
+#define MDSCR_EL1_MDE (1u << 15)
+
+/**
+ * System register are identified by op0, op2, op1, crn, crm. The ISS encoding
+ * includes also rt and direction. Exclude them,  @see D13.2.37 (D13-2977).
+ */
+#define ISS_SYSREG_MASK                               \
+	(((1u << 22) - 1u) & /* Select the ISS bits*/ \
+	 ~(0x1fu << 5) &     /* exclude rt */         \
+	 ~1u /* exclude direction */)
+
+#define GET_ISS_SYSREG(esr) (ISS_SYSREG_MASK & (esr))
+
+/**
+ * Op0 from the ISS encoding in the ESR.
+ */
+#define ISS_OP0_MASK 0x300000
+#define ISS_OP0_SHIFT 20
+#define GET_ISS_OP0(esr) ((ISS_OP0_MASK & (esr)) >> ISS_OP0_SHIFT)
+
+/**
+ * Op1 from the ISS encoding in the ESR.
+ */
+#define ISS_OP1_MASK 0x1c000
+#define ISS_OP1_SHIFT 14
+#define GET_ISS_OP1(esr) ((ISS_OP1_MASK & (esr)) >> ISS_OP1_SHIFT)
+
+/**
+ * Direction (i.e., read (1) or write (0), is the first bit in the ISS/ESR.
+ */
+#define ISS_DIRECTION_MASK 1u
+
+/**
+ * Gets the direction of the system register access, read (1) or write (0).
+ */
+#define GET_ISS_DIRECTION(esr) (ISS_DIRECTION_MASK & (esr))
+
+/**
+ * True if the ISS encoded in the esr indicates a read of the system register.
+ */
+#define ISS_IS_READ(esr) (ISS_DIRECTION_MASK & (esr))
+
+/**
+ * Rt, which identifies the general purpose register used for the operation.
+ */
+#define ISS_RT_MASK 0x3e0
+#define ISS_RT_SHIFT 5
+#define GET_ISS_RT(esr) ((ISS_RT_MASK & (esr)) >> ISS_RT_SHIFT)
+
+/**
+ * Definitions of read-only debug registers' ISS signatures.
+ */
+#define EL1_DEBUG_REGISTERS_READ       \
+	X(MDRAR_EL1, 0x200400)         \
+	X(DBGAUTHSTATUS_EL1, 0x2c1c1c) \
+	X(OSLSR_EL1, 0x280402)
+
+/**
+ * Definitions of readable and writeable debug registers' ISS signatures.
+ */
+#define EL1_DEBUG_REGISTERS_READ_WRITE \
+	X(DBGCLAIMCLR_EL1, 0x2c1c12)   \
+	X(DBGCLAIMSET_EL1, 0x2c1c10)   \
+	X(DBGPRCR_EL1, 0x280408)       \
+	X(MDCCINT_EL1, 0x200004)       \
+	X(MDSCR_EL1, 0x240004)         \
+	X(OSDLR_EL1, 0x280406)         \
+	X(OSDTRRX_EL1, 0x240000)       \
+	X(OSDTRTX_EL1, 0x240006)       \
+	X(OSECCR_EL1, 0x24000c)        \
+	X(DBGBCR0_EL1, 0x2a0000)       \
+	X(DBGBCR1_EL1, 0x2a0002)       \
+	X(DBGBCR2_EL1, 0x2a0004)       \
+	X(DBGBCR3_EL1, 0x2a0006)       \
+	X(DBGBCR4_EL1, 0x2a0008)       \
+	X(DBGBCR5_EL1, 0x2a000a)       \
+	X(DBGBCR6_EL1, 0x2a000c)       \
+	X(DBGBCR7_EL1, 0x2a000e)       \
+	X(DBGBCR8_EL1, 0x2a0010)       \
+	X(DBGBCR9_EL1, 0x2a0012)       \
+	X(DBGBCR10_EL1, 0x2a0014)      \
+	X(DBGBCR11_EL1, 0x2a0016)      \
+	X(DBGBCR12_EL1, 0x2a0018)      \
+	X(DBGBCR13_EL1, 0x2a001a)      \
+	X(DBGBCR14_EL1, 0x2a001c)      \
+	X(DBGBCR15_EL1, 0x2a001e)      \
+	X(DBGBVR0_EL1, 0x280000)       \
+	X(DBGBVR1_EL1, 0x280002)       \
+	X(DBGBVR2_EL1, 0x280004)       \
+	X(DBGBVR3_EL1, 0x280006)       \
+	X(DBGBVR4_EL1, 0x280008)       \
+	X(DBGBVR5_EL1, 0x28000a)       \
+	X(DBGBVR6_EL1, 0x28000c)       \
+	X(DBGBVR7_EL1, 0x28000e)       \
+	X(DBGBVR8_EL1, 0x280010)       \
+	X(DBGBVR9_EL1, 0x280012)       \
+	X(DBGBVR10_EL1, 0x280014)      \
+	X(DBGBVR11_EL1, 0x280016)      \
+	X(DBGBVR12_EL1, 0x280018)      \
+	X(DBGBVR13_EL1, 0x28001a)      \
+	X(DBGBVR14_EL1, 0x28001c)      \
+	X(DBGBVR15_EL1, 0x28001e)      \
+	X(DBGWCR0_EL1, 0x2e0000)       \
+	X(DBGWCR1_EL1, 0x2e0002)       \
+	X(DBGWCR2_EL1, 0x2e0004)       \
+	X(DBGWCR3_EL1, 0x2e0006)       \
+	X(DBGWCR4_EL1, 0x2e0008)       \
+	X(DBGWCR5_EL1, 0x2e000a)       \
+	X(DBGWCR6_EL1, 0x2e000c)       \
+	X(DBGWCR7_EL1, 0x2e000e)       \
+	X(DBGWCR8_EL1, 0x2e0010)       \
+	X(DBGWCR9_EL1, 0x2e0012)       \
+	X(DBGWCR10_EL1, 0x2e0014)      \
+	X(DBGWCR11_EL1, 0x2e0016)      \
+	X(DBGWCR12_EL1, 0x2e0018)      \
+	X(DBGWCR13_EL1, 0x2e001a)      \
+	X(DBGWCR14_EL1, 0x2e001c)      \
+	X(DBGWCR15_EL1, 0x2e001e)      \
+	X(DBGWVR0_EL1, 0x2c0000)       \
+	X(DBGWVR1_EL1, 0x2c0002)       \
+	X(DBGWVR2_EL1, 0x2c0004)       \
+	X(DBGWVR3_EL1, 0x2c0006)       \
+	X(DBGWVR4_EL1, 0x2c0008)       \
+	X(DBGWVR5_EL1, 0x2c000a)       \
+	X(DBGWVR6_EL1, 0x2c000c)       \
+	X(DBGWVR7_EL1, 0x2c000e)       \
+	X(DBGWVR8_EL1, 0x2c0010)       \
+	X(DBGWVR9_EL1, 0x2c0012)       \
+	X(DBGWVR10_EL1, 0x2c0014)      \
+	X(DBGWVR11_EL1, 0x2c0016)      \
+	X(DBGWVR12_EL1, 0x2c0018)      \
+	X(DBGWVR13_EL1, 0x2c001a)      \
+	X(DBGWVR14_EL1, 0x2c001c)      \
+	X(DBGWVR15_EL1, 0x2c001e)
+
+/**
+ * Definitions of all debug registers' ISS signatures.
+ */
+#define EL1_DEBUG_REGISTERS      \
+	EL1_DEBUG_REGISTERS_READ \
+	EL1_DEBUG_REGISTERS_READ_WRITE
+
+/**
+ * Returns the value for mdcr_el2 for the particular VM.
+ * For now, the primary VM has one value and all secondary VMs share a value.
+ */
+uintreg_t get_mdcr_el2_value(spci_vm_id_t vm_id)
+{
+	if (vm_id == HF_PRIMARY_VM_ID) {
+		/*
+		 * Trap primary VM accesses to debug registers to have fine
+		 * grained control over system register accesses.
+		 * Do not trap the Primary VM's debug events (!MDCR_EL2_TDE).
+		 */
+		return MDCR_EL2_TTRF | MDCR_EL2_TDRA | MDCR_EL2_TDOSA |
+		       MDCR_EL2_TDA;
+	}
+
+	/*
+	 * Trap all secondary VM debug register accesses as well as debug
+	 * event exceptions.
+	 * Debug event exceptions should be disabled in secondary VMs, but trap
+	 * them for additional security (MDCR_EL2_TDE).
+	 */
+	return MDCR_EL2_TTRF | MDCR_EL2_TDRA | MDCR_EL2_TDOSA | MDCR_EL2_TDA |
+	       MDCR_EL2_TDE;
+}
+
+/**
+ * Returns true if the ESR register shows an access to an EL1 debug register.
+ */
+bool is_debug_el1_register_access(uintreg_t esr_el2)
+{
+	/*
+	 * Architecture Reference Manual D12.2: op0 == 0b10 is for debug and
+	 * trace system registers.  op1 = 0x1 for trace, remaining are debug.
+	 */
+	return GET_ISS_OP0(esr_el2) == 0x2 && GET_ISS_OP1(esr_el2) != 0x1;
+}
+
+/**
+ * Processes an access (msr, mrs) to an EL1 debug register.
+ * Returns true if the access was allowed and performed, false otherwise.
+ */
+bool debug_el1_process_access(struct vcpu *vcpu, spci_vm_id_t vm_id,
+			      uintreg_t esr_el2)
+{
+	/*
+	 * For now, debug registers are not supported by secondary VMs.
+	 * Disallow accesses to them.
+	 */
+	if (vm_id != HF_PRIMARY_VM_ID) {
+		return false;
+	}
+
+	uintreg_t sys_register = GET_ISS_SYSREG(esr_el2);
+	uintreg_t rt_register = GET_ISS_RT(esr_el2);
+	uintreg_t value;
+
+	CHECK(rt_register < NUM_GP_REGS);
+
+	if (ISS_IS_READ(esr_el2)) {
+		switch (sys_register) {
+#define X(reg_name, reg_sig)                \
+	case reg_sig:                       \
+		value = read_msr(reg_name); \
+		break;
+			EL1_DEBUG_REGISTERS
+#undef X
+		default:
+			value = vcpu->regs.r[rt_register];
+			dlog("Unsupported system register read 0x%x\n",
+			     sys_register);
+			break;
+		}
+		vcpu->regs.r[rt_register] = value;
+
+	} else {
+		value = vcpu->regs.r[rt_register];
+		switch (sys_register) {
+#define X(reg_name, reg_sig)                \
+	case reg_sig:                       \
+		write_msr(reg_name, value); \
+		break;
+			EL1_DEBUG_REGISTERS_READ_WRITE
+#undef X
+		default:
+			dlog("Unsupported system register write 0x%x\n",
+			     sys_register);
+			break;
+		}
+	}
+
+	return true;
+}