diff --git a/SUPPORT.md b/SUPPORT.md index ad74f5a329..465f6527c9 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -111,6 +111,11 @@ that would normally trigger a fault injection. Only the following system registers are security supported: + MDCCSR_EL0 + DBGDTR_EL0 + DBGDTRTX_EL0 + DBGDTRRX_EL0 + ### ARM Scalable Vector Extension (SVE/SVE2) Arm64 domains can use Scalable Vector Extension (SVE/SVE2). diff --git a/xen/arch/arm/arm64/vsysreg.c b/xen/arch/arm/arm64/vsysreg.c index b5d54c569b..c73b2c95ce 100644 --- a/xen/arch/arm/arm64/vsysreg.c +++ b/xen/arch/arm/arm64/vsysreg.c @@ -82,6 +82,7 @@ TVM_REG(CONTEXTIDR_EL1) void do_sysreg(struct cpu_user_regs *regs, const union hsr hsr) { + const struct hsr_sysreg sysreg = hsr.sysreg; int regidx = hsr.sysreg.reg; struct vcpu *v = current; @@ -159,9 +160,6 @@ void do_sysreg(struct cpu_user_regs *regs, * * Unhandled: * MDCCINT_EL1 - * DBGDTR_EL0 - * DBGDTRRX_EL0 - * DBGDTRTX_EL0 * OSDTRRX_EL1 * OSDTRTX_EL1 * OSECCR_EL1 @@ -171,12 +169,42 @@ void do_sysreg(struct cpu_user_regs *regs, */ case HSR_SYSREG_MDSCR_EL1: return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1); + + /* + * Xen doesn't expose a real (or emulated) Debug Communications Channel + * (DCC) to a domain. Yet the Arm ARM implies this is not an optional + * feature. So some domains may start to probe it. For instance, the + * HVC_DCC driver in Linux (since f377775dc083 and at least up to v6.7), + * will try to write some characters and check if the transmit buffer + * has emptied. + */ case HSR_SYSREG_MDCCSR_EL0: /* + * By setting TX status bit (only if partial emulation is enabled) to + * indicate the transmit buffer is full, we would hint the OS that the + * DCC is probably not working. + * + * Bit 29: TX full + * * Accessible at EL0 only if MDSCR_EL1.TDCC is set to 0. We emulate that * register as RAZ/WI above. So RO at both EL0 and EL1. */ - return handle_ro_raz(regs, regidx, hsr.sysreg.read, hsr, 0); + return handle_ro_read_val(regs, regidx, hsr.sysreg.read, hsr, 0, + partial_emulation ? (1U << 29) : 0); + + case HSR_SYSREG_DBGDTR_EL0: + /* DBGDTR[TR]X_EL0 share the same encoding */ + case HSR_SYSREG_DBGDTRTX_EL0: + /* + * Emulate as RAZ/WI (only if partial emulation is enabled) to prevent + * injecting undefined exception. + * Accessible at EL0 only if MDSCR_EL1.TDCC is set to 0. We emulate that + * register as RAZ/WI. + */ + if ( !partial_emulation ) + goto fail; + return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 0); + HSR_SYSREG_DBG_CASES(DBGBVR): HSR_SYSREG_DBG_CASES(DBGBCR): HSR_SYSREG_DBG_CASES(DBGWVR): @@ -394,26 +422,25 @@ void do_sysreg(struct cpu_user_regs *regs, * And all other unknown registers. */ default: - { - const struct hsr_sysreg sysreg = hsr.sysreg; - - gdprintk(XENLOG_ERR, - "%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n", - sysreg.read ? "mrs" : "msr", - sysreg.op0, sysreg.op1, - sysreg.crn, sysreg.crm, - sysreg.op2, - sysreg.read ? "=>" : "<=", - sysreg.reg, regs->pc); - gdprintk(XENLOG_ERR, - "unhandled 64-bit sysreg access %#"PRIregister"\n", - hsr.bits & HSR_SYSREG_REGS_MASK); - inject_undef_exception(regs, hsr); - return; - } + goto fail; } regs->pc += 4; + return; + + fail: + gdprintk(XENLOG_ERR, + "%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n", + sysreg.read ? "mrs" : "msr", + sysreg.op0, sysreg.op1, + sysreg.crn, sysreg.crm, + sysreg.op2, + sysreg.read ? "=>" : "<=", + sysreg.reg, regs->pc); + gdprintk(XENLOG_ERR, + "unhandled 64-bit sysreg access %#"PRIregister"\n", + hsr.bits & HSR_SYSREG_REGS_MASK); + inject_undef_exception(regs, hsr); } /* diff --git a/xen/arch/arm/include/asm/arm64/hsr.h b/xen/arch/arm/include/asm/arm64/hsr.h index e691d41c17..1495ccddea 100644 --- a/xen/arch/arm/include/asm/arm64/hsr.h +++ b/xen/arch/arm/include/asm/arm64/hsr.h @@ -47,6 +47,9 @@ #define HSR_SYSREG_OSDLR_EL1 HSR_SYSREG(2,0,c1,c3,4) #define HSR_SYSREG_DBGPRCR_EL1 HSR_SYSREG(2,0,c1,c4,4) #define HSR_SYSREG_MDCCSR_EL0 HSR_SYSREG(2,3,c0,c1,0) +#define HSR_SYSREG_DBGDTR_EL0 HSR_SYSREG(2,3,c0,c4,0) +#define HSR_SYSREG_DBGDTRTX_EL0 HSR_SYSREG(2,3,c0,c5,0) +#define HSR_SYSREG_DBGDTRRX_EL0 HSR_SYSREG(2,3,c0,c5,0) #define HSR_SYSREG_DBGBVRn_EL1(n) HSR_SYSREG(2,0,c0,c##n,4) #define HSR_SYSREG_DBGBCRn_EL1(n) HSR_SYSREG(2,0,c0,c##n,5)