From: Showta Ishizaki <[email protected]>
A guest that reads MDCCSR_EL0 under hvf is killed. The register has no
case in hvf_sysreg_read(), so it reaches the unhandled path and hvf
injects an undefined instruction:
trace_hvf_unhandled_sysreg_read(env->pc, reg, ...);
hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized(), 1);
The TCG path does not do this. debug_helper.c defines MDCCSR_EL0 as
ARM_CP_CONST with resetvalue 0, and the comment on the neighbouring DCC
registers gives the reason:
However we implement RAZ/WI behaviour with trapping to prevent
spurious SIGILLs if the guest OS does access them as the support
cannot be probed for.
That argument holds for hvf as much as for TCG, so do the same there.
The read only reaches QEMU since 37863fff59 ("hvf: arm: enable vGIC by
default for virt-11.1 and later"). With -M virt,kernel-irqchip=off the
trace point does not fire at all, so before that change the register was
never trapped out.
NetBSD/aarch64 hits this on every boot. vmt(4) probes for the VMware
backdoor, which on arm64 is a read of MDCCSR_EL0 with a magic value in
x7, and the injected undefined instruction is fatal in kernel mode:
[ 1.0000000] cpu0 at acpi0: unknown CPU (ID = 0x610f0000), id 0x0
[ 1.0000000] panic: Trap: fatal Unknown Reason (Illegal Instruction):
pc=ffffc000003fa318 sp=ffffc000010262e0 esr=02000000
[ 1.0000000] fp ffffc000010262f0 vmt_probe() at netbsd:vmt_probe+0x3c
[ 1.0000000] fp ffffc00001026340 vmt_match() at netbsd:vmt_match+0x1c
The pc in the panic is the same pc the trace point reports, and the
encoding it reports is MDCCSR_EL0:
hvf_unhandled_sysreg_read unhandled sysreg read at pc=0xffffc000003fa318:
0x0020c002 (op0=2 op1=3 crn=0 crm=1 op2=0)
With this patch the same image boots to login on -M virt -accel hvf, and
the trace point does not fire.
Cc: [email protected]
Fixes: 37863fff59e0 ("hvf: arm: enable vGIC by default for virt-11.1 and later")
Signed-off-by: Showta Ishizaki <[email protected]>
Reviewed-by: Mohamed Mediouni <[email protected]>
Message-id: [email protected]
Signed-off-by: Peter Maydell <[email protected]>
(cherry picked from commit 99fb8e570e545c932c5c89be1bf0086002a35a33)
Signed-off-by: Michael Tokarev <[email protected]>
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index da3ec521fc7..b00a7e1a845 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -234,6 +234,7 @@ void hvf_arm_init_debug(void)
#define SYSREG_ICC_SRE_EL1 SYSREG(3, 0, 12, 12, 5)
#define SYSREG_MDSCR_EL1 SYSREG(2, 0, 0, 2, 2)
+#define SYSREG_MDCCSR_EL0 SYSREG(2, 3, 0, 1, 0)
#define SYSREG_DBGBVR0_EL1 SYSREG(2, 0, 0, 0, 4)
#define SYSREG_DBGBCR0_EL1 SYSREG(2, 0, 0, 0, 5)
#define SYSREG_DBGWVR0_EL1 SYSREG(2, 0, 0, 0, 6)
@@ -1756,6 +1757,15 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg,
uint64_t *val)
case SYSREG_MDCCINT_EL1:
assert_hvf_ok(hv_vcpu_get_sys_reg(cpu->accel->fd,
HV_SYS_REG_MDCCINT_EL1, val));
return 0;
+ case SYSREG_MDCCSR_EL0:
+ /*
+ * The Debug Communications Channel is not implemented, so RAZ,
+ * which is what the TCG path in debug_helper.c does. A guest
+ * cannot probe for DCC support, so injecting an undefined
+ * instruction here turns a legal read into a fatal trap.
+ */
+ *val = 0;
+ return 0;
case SYSREG_ICC_AP0R0_EL1:
case SYSREG_ICC_AP0R1_EL1:
case SYSREG_ICC_AP0R2_EL1:
--
2.47.3