/* * Copyright 2019 The Hafnium Authors. * * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file or at * https://opensource.org/licenses/BSD-3-Clause. */ #include "debug_el1.h" #include "hf/check.h" #include "hf/dlog.h" #include "hf/types.h" #include "msr.h" #include "sysregs.h" /* clang-format off */ /** * Definitions of read-only debug registers' encodings. * See Arm Architecture Reference Manual Armv8-A, D12.2. * NAME, op0, op1, crn, crm, op2 */ #define EL1_DEBUG_REGISTERS_READ \ X(MDRAR_EL1 , 2, 0, 1, 0, 0) \ X(OSLSR_EL1 , 2, 0, 1, 1, 4) \ X(DBGAUTHSTATUS_EL1 , 2, 0, 7, 14, 6) \ /** * Definitions of write-only debug registers' encodings. * See Arm Architecture Reference Manual Armv8-A, D12.2. * NAME, op0, op1, crn, crm, op2 */ #define EL1_DEBUG_REGISTERS_WRITE \ X(OSLAR_EL1 , 2, 0, 1, 0, 4) \ /** * Definitions of readable and writeable debug registers' encodings. * See Arm Architecture Reference Manual Armv8-A, D12.2. * NAME, op0, op1, crn, crm, op2 */ #define EL1_DEBUG_REGISTERS_READ_WRITE \ X(OSDTRRX_EL1 , 2, 0, 0, 0, 2) \ X(MDCCINT_EL1 , 2, 0, 0, 2, 0) \ X(MDSCR_EL1 , 2, 0, 0, 2, 2) \ X(OSDTRTX_EL1 , 2, 0, 0, 3, 2) \ X(OSECCR_EL1 , 2, 0, 0, 6, 2) \ X(DBGBVR0_EL1 , 2, 0, 0, 0, 4) \ X(DBGBVR1_EL1 , 2, 0, 0, 1, 4) \ X(DBGBVR2_EL1 , 2, 0, 0, 2, 4) \ X(DBGBVR3_EL1 , 2, 0, 0, 3, 4) \ X(DBGBVR4_EL1 , 2, 0, 0, 4, 4) \ X(DBGBVR5_EL1 , 2, 0, 0, 5, 4) \ X(DBGBVR6_EL1 , 2, 0, 0, 6, 4) \ X(DBGBVR7_EL1 , 2, 0, 0, 7, 4) \ X(DBGBVR8_EL1 , 2, 0, 0, 8, 4) \ X(DBGBVR9_EL1 , 2, 0, 0, 9, 4) \ X(DBGBVR10_EL1 , 2, 0, 0, 10, 4) \ X(DBGBVR11_EL1 , 2, 0, 0, 11, 4) \ X(DBGBVR12_EL1 , 2, 0, 0, 12, 4) \ X(DBGBVR13_EL1 , 2, 0, 0, 13, 4) \ X(DBGBVR14_EL1 , 2, 0, 0, 14, 4) \ X(DBGBVR15_EL1 , 2, 0, 0, 15, 4) \ X(DBGBCR0_EL1 , 2, 0, 0, 0, 5) \ X(DBGBCR1_EL1 , 2, 0, 0, 1, 5) \ X(DBGBCR2_EL1 , 2, 0, 0, 2, 5) \ X(DBGBCR3_EL1 , 2, 0, 0, 3, 5) \ X(DBGBCR4_EL1 , 2, 0, 0, 4, 5) \ X(DBGBCR5_EL1 , 2, 0, 0, 5, 5) \ X(DBGBCR6_EL1 , 2, 0, 0, 6, 5) \ X(DBGBCR7_EL1 , 2, 0, 0, 7, 5) \ X(DBGBCR8_EL1 , 2, 0, 0, 8, 5) \ X(DBGBCR9_EL1 , 2, 0, 0, 9, 5) \ X(DBGBCR10_EL1 , 2, 0, 0, 10, 5) \ X(DBGBCR11_EL1 , 2, 0, 0, 11, 5) \ X(DBGBCR12_EL1 , 2, 0, 0, 12, 5) \ X(DBGBCR13_EL1 , 2, 0, 0, 13, 5) \ X(DBGBCR14_EL1 , 2, 0, 0, 14, 5) \ X(DBGBCR15_EL1 , 2, 0, 0, 15, 5) \ X(DBGWVR0_EL1 , 2, 0, 0, 0, 6) \ X(DBGWVR1_EL1 , 2, 0, 0, 1, 6) \ X(DBGWVR2_EL1 , 2, 0, 0, 2, 6) \ X(DBGWVR3_EL1 , 2, 0, 0, 3, 6) \ X(DBGWVR4_EL1 , 2, 0, 0, 4, 6) \ X(DBGWVR5_EL1 , 2, 0, 0, 5, 6) \ X(DBGWVR6_EL1 , 2, 0, 0, 6, 6) \ X(DBGWVR7_EL1 , 2, 0, 0, 7, 6) \ X(DBGWVR8_EL1 , 2, 0, 0, 8, 6) \ X(DBGWVR9_EL1 , 2, 0, 0, 9, 6) \ X(DBGWVR10_EL1 , 2, 0, 0, 10, 6) \ X(DBGWVR11_EL1 , 2, 0, 0, 11, 6) \ X(DBGWVR12_EL1 , 2, 0, 0, 12, 6) \ X(DBGWVR13_EL1 , 2, 0, 0, 13, 6) \ X(DBGWVR14_EL1 , 2, 0, 0, 14, 6) \ X(DBGWVR15_EL1 , 2, 0, 0, 15, 6) \ X(DBGWCR0_EL1 , 2, 0, 0, 0, 7) \ X(DBGWCR1_EL1 , 2, 0, 0, 1, 7) \ X(DBGWCR2_EL1 , 2, 0, 0, 2, 7) \ X(DBGWCR3_EL1 , 2, 0, 0, 3, 7) \ X(DBGWCR4_EL1 , 2, 0, 0, 4, 7) \ X(DBGWCR5_EL1 , 2, 0, 0, 5, 7) \ X(DBGWCR6_EL1 , 2, 0, 0, 6, 7) \ X(DBGWCR7_EL1 , 2, 0, 0, 7, 7) \ X(DBGWCR8_EL1 , 2, 0, 0, 8, 7) \ X(DBGWCR9_EL1 , 2, 0, 0, 9, 7) \ X(DBGWCR10_EL1 , 2, 0, 0, 10, 7) \ X(DBGWCR11_EL1 , 2, 0, 0, 11, 7) \ X(DBGWCR12_EL1 , 2, 0, 0, 12, 7) \ X(DBGWCR13_EL1 , 2, 0, 0, 13, 7) \ X(DBGWCR14_EL1 , 2, 0, 0, 14, 7) \ X(DBGWCR15_EL1 , 2, 0, 0, 15, 7) \ X(OSDLR_EL1 , 2, 0, 1, 3, 4) \ X(DBGPRCR_EL1 , 2, 0, 1, 4, 4) \ X(DBGCLAIMSET_EL1 , 2, 0, 7, 8, 6) \ X(DBGCLAIMCLR_EL1 , 2, 0, 7, 9, 6) /* clang-format on */ /** * Returns true if the ESR register shows an access to an EL1 debug register. */ bool debug_el1_is_register_access(uintreg_t esr) { /* * Architecture Reference Manual D12.2: op0 == 2 is for debug and trace * system registers, op1 == 1 for trace, remaining are debug. */ return GET_ISS_OP0(esr) == 2 && GET_ISS_OP1(esr) != 1; } /** * 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, ffa_vm_id_t vm_id, uintreg_t esr) { /* * 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); uintreg_t rt_register = GET_ISS_RT(esr); uintreg_t value; /* +1 because Rt can access register XZR */ CHECK(rt_register < NUM_GP_REGS + 1); if (ISS_IS_READ(esr)) { switch (sys_register) { #define X(reg_name, op0, op1, crn, crm, op2) \ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \ value = read_msr(reg_name); \ break; EL1_DEBUG_REGISTERS_READ EL1_DEBUG_REGISTERS_READ_WRITE #undef X default: value = vcpu->regs.r[rt_register]; dlog_notice( "Unsupported debug system register read: " "op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, " "rt=%d.\n", GET_ISS_OP0(esr), GET_ISS_OP1(esr), GET_ISS_CRN(esr), GET_ISS_CRM(esr), GET_ISS_OP2(esr), GET_ISS_RT(esr)); break; } if (rt_register != RT_REG_XZR) { vcpu->regs.r[rt_register] = value; } } else { if (rt_register != RT_REG_XZR) { value = vcpu->regs.r[rt_register]; } else { value = 0; } switch (sys_register) { #define X(reg_name, op0, op1, crn, crm, op2) \ case (GET_ISS_ENCODING(op0, op1, crn, crm, op2)): \ write_msr(reg_name, value); \ break; EL1_DEBUG_REGISTERS_WRITE EL1_DEBUG_REGISTERS_READ_WRITE #undef X default: dlog_notice( "Unsupported debug system register write: " "op0=%d, op1=%d, crn=%d, crm=%d, op2=%d, " "rt=%d.\n", GET_ISS_OP0(esr), GET_ISS_OP1(esr), GET_ISS_CRN(esr), GET_ISS_CRM(esr), GET_ISS_OP2(esr), GET_ISS_RT(esr)); break; } } return true; }