xen/arm: arm32: Add emulation of Debug Data Transfer Registers

When user enables HVC_DCC config option in Linux, it invokes access to debug
transfer register (i.e. DBGDTRTXINT). As this register is not emulated, Xen
injects an undefined exception to the guest and Linux crashes.

To prevent this crash, introduce a partial emulation of DBGDTR[TR]XINT (these
registers share the same encoding) as RAZ/WI and DBGDSCRINT as TXfull.

Refer ARM DDI 0487J.a ID042523, G8.3.19, DBGDTRTXint:
"If TXfull is set to 1, set DTRTX to UNKNOWN".

As a pre-requisite, DBGOSLSR should be emulated in the same way as its AArch64
variant (i.e. OSLSR_EL1). This is to ensure that DBGOSLSR.OSLK is 0, which
allows us to skip the emulation of DBGDSCREXT (TXfull is treated as UNK/SBZP)
and focus on DBGDSCRINT. DBGOSLSR.OSLM[1] is set to 1 to mantain consistency
with Arm64.

Take the opportunity to fix the minimum EL for DBGDSCRINT, which should be 0.

Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
Acked-by: Julien Grall <jgrall@amazon.com>
This commit is contained in:
Ayan Kumar Halder authored and Julien Grall committed 2024-03-14 13:04:25 +00:00
1 parent 43c416d0d8
commit 77c39a53cf
3 files changed
+49 -18

No files matched your search

+3
View File
@@ -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)
+2
View File
@@ -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 */
+44 -18
View File
@@ -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",
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.