diff --git a/SUPPORT.md b/SUPPORT.md index 465f6527c9..58f075538f 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -115,6 +115,9 @@ Only the following system registers are security supported: DBGDTR_EL0 DBGDTRTX_EL0 DBGDTRRX_EL0 + DBGDSCRINT + DBGDTRTXINT + DBGDTRRXINT ### ARM Scalable Vector Extension (SVE/SVE2) diff --git a/xen/arch/arm/include/asm/cpregs.h b/xen/arch/arm/include/asm/cpregs.h index 6b083de204..aec9e8f329 100644 --- a/xen/arch/arm/include/asm/cpregs.h +++ b/xen/arch/arm/include/asm/cpregs.h @@ -75,6 +75,8 @@ #define DBGDIDR p14,0,c0,c0,0 /* Debug ID Register */ #define DBGDSCRINT p14,0,c0,c1,0 /* Debug Status and Control Internal */ #define DBGDSCREXT p14,0,c0,c2,2 /* Debug Status and Control External */ +#define DBGDTRRXINT p14,0,c0,c5,0 /* Debug Data Transfer Register, Receive */ +#define DBGDTRTXINT p14,0,c0,c5,0 /* Debug Data Transfer Register, Transmit */ #define DBGVCR p14,0,c0,c7,0 /* Vector Catch */ #define DBGBVR0 p14,0,c0,c0,4 /* Breakpoint Value 0 */ #define DBGBCR0 p14,0,c0,c0,5 /* Breakpoint Control 0 */ diff --git a/xen/arch/arm/vcpreg.c b/xen/arch/arm/vcpreg.c index 019cf34f00..0b336875a4 100644 --- a/xen/arch/arm/vcpreg.c +++ b/xen/arch/arm/vcpreg.c @@ -494,11 +494,12 @@ void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr) * ARMv8 (DDI 0487A.d): D1-1509 Table D1-58 * * Unhandled: - * DBGOSLSR * DBGPRCR */ case HSR_CPREG32(DBGOSLAR): return handle_wo_wi(regs, regidx, cp32.read, hsr, 1); + case HSR_CPREG32(DBGOSLSR): + return handle_ro_read_val(regs, regidx, cp32.read, hsr, 1, 1U << 3); case HSR_CPREG32(DBGOSDLR): return handle_raz_wi(regs, regidx, cp32.read, hsr, 1); @@ -510,8 +511,6 @@ void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr) * * Unhandled: * DBGDCCINT - * DBGDTRRXint - * DBGDTRTXint * DBGWFAR * DBGDTRTXext * DBGDTRRXext, @@ -549,12 +548,27 @@ void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr) break; } + /* + * 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_CPREG32(DBGDSCRINT): /* - * Read-only register. Accessible by EL0 if DBGDSCRext.UDCCdis - * is set to 0, which we emulated below. + * 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 DBGDSCRext.UDCCdis is set to 0. We emulate + * this as RAZ/WI in the next case. So RO at both EL0 and EL1. */ - return handle_ro_raz(regs, regidx, cp32.read, hsr, 1); + return handle_ro_read_val(regs, regidx, cp32.read, hsr, 0, + partial_emulation ? (1U << 29) : 0); case HSR_CPREG32(DBGDSCREXT): /* @@ -563,6 +577,18 @@ void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr) */ return handle_raz_wi(regs, regidx, cp32.read, hsr, 1); + /* DBGDTR[TR]XINT share the same encoding */ + case HSR_CPREG32(DBGDTRTXINT): + /* + * Emulate as RAZ/WI (only if partial emulation is enabled) to prevent + * injecting undefined exception. + * Accessible at EL0 only if DBGDSCREXT is set to 0. We emulate that + * register as RAZ/WI. + */ + if ( !partial_emulation ) + goto fail; + return handle_raz_wi(regs, regidx, cp32.read, hsr, 0); + case HSR_CPREG32(DBGVCR): case HSR_CPREG32(DBGBVR0): case HSR_CPREG32(DBGBCR0): @@ -592,17 +618,20 @@ void do_cp14_32(struct cpu_user_regs *regs, const union hsr hsr) * And all other unknown registers. */ default: - gdprintk(XENLOG_ERR, - "%s p14, %d, r%d, cr%d, cr%d, %d @ 0x%"PRIregister"\n", - cp32.read ? "mrc" : "mcr", - cp32.op1, cp32.reg, cp32.crn, cp32.crm, cp32.op2, regs->pc); - gdprintk(XENLOG_ERR, "unhandled 32-bit cp14 access %#"PRIregister"\n", - hsr.bits & HSR_CP32_REGS_MASK); - inject_undef_exception(regs, hsr); - return; + goto fail; } advance_pc(regs, hsr); + return; + + fail: + gdprintk(XENLOG_ERR, + "%s p14, %d, r%d, cr%d, cr%d, %d @ 0x%"PRIregister"\n", + cp32.read ? "mrc" : "mcr", + cp32.op1, cp32.reg, cp32.crn, cp32.crm, cp32.op2, regs->pc); + gdprintk(XENLOG_ERR, "unhandled 32-bit cp14 access %#"PRIregister"\n", + hsr.bits & HSR_CP32_REGS_MASK); + inject_undef_exception(regs, hsr); } void do_cp14_64(struct cpu_user_regs *regs, const union hsr hsr) @@ -660,10 +689,7 @@ void do_cp14_dbg(struct cpu_user_regs *regs, const union hsr hsr) * ARMv8 (DDI 0487A.d): D1-1509 Table D1-58 * * Unhandled: - * DBGDTRTXint - * DBGDTRRXint - * - * And all other unknown registers. + * All unknown registers. */ gdprintk(XENLOG_ERR, "%s p14, %d, r%d, r%d, cr%d @ 0x%"PRIregister"\n",