git: 167d3567c4b9 - main - arm64/vmm: Treat Rt=31 as xzr in reg & instr emul

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Tue, 13 Oct 2026 15:44:57 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=167d3567c4b93650c8bcca86ff294226e6e1a9ce

commit 167d3567c4b93650c8bcca86ff294226e6e1a9ce
Author:     Kajetan Puchalski <kajetan.puchalski@arm.com>
AuthorDate: 2026-09-29 17:02:19 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-10-13 15:44:34 +0000

    arm64/vmm: Treat Rt=31 as xzr in reg & instr emul
    
    For certain instructions like msr, mrs, ldr & str, Rt=31 means the
    operand is the Zero register (XZR) as opposed to the SP, even though the
    two share the encoding of 31 on AArch64.
    
    This is currently ignored in register and instruction emulation, so
    emulated guest operations like "msr <reg>, xzr" will set the value of
    <reg> to the current value of the SP instead of to 0.
    
    Skip set and get operations when Rt=31 to correct the behaviour.
    
    Signed-off-by: Kajetan Puchalski <kajetan.puchalski@arm.com>
    Reviewed by:    andrew
    Sponsored by:   Arm Ltd
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2454
---
 sys/arm64/vmm/vmm_instruction_emul.c | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/sys/arm64/vmm/vmm_instruction_emul.c b/sys/arm64/vmm/vmm_instruction_emul.c
index 3d3326d6eda5..484539e9cc52 100644
--- a/sys/arm64/vmm/vmm_instruction_emul.c
+++ b/sys/arm64/vmm/vmm_instruction_emul.c
@@ -63,11 +63,16 @@ vmm_emulate_instruction(struct vcpu *vcpu, uint64_t gpa, struct vie *vie,
 		error = memread(vcpu, gpa, &val, vie->access_size, memarg);
 		if (error)
 			goto out;
-		error = vm_set_register(vcpu, vie->reg, val);
+		/* Make sure we treat Rt=31 as xzr and not SP */
+		if (vie->reg != 31)
+			error = vm_set_register(vcpu, vie->reg, val);
 	} else {
-		error = vm_get_register(vcpu, vie->reg, &val);
-		if (error)
-			goto out;
+		val = 0;
+		if (vie->reg != 31) {
+			error = vm_get_register(vcpu, vie->reg, &val);
+			if (error)
+				goto out;
+		}
 		/* Mask any unneeded bits from the register */
 		if (vie->access_size < 8)
 			val &= (1ul << (vie->access_size * 8)) - 1;
@@ -89,11 +94,23 @@ vmm_emulate_register(struct vcpu *vcpu, struct vre *vre, reg_read_t regread,
 		error = regread(vcpu, &val, regarg);
 		if (error)
 			goto out;
-		error = vm_set_register(vcpu, vre->reg, val);
+		/*
+		 * vre->reg here comes from msr/mrs Rt, where 31 means "xzr" as
+		 * opposed to "SP". Reading into xzr must not set the register.
+		 */
+		if (vre->reg != 31)
+			error = vm_set_register(vcpu, vre->reg, val);
 	} else {
-		error = vm_get_register(vcpu, vre->reg, &val);
-		if (error)
-			goto out;
+		val = 0;
+		/*
+		 * Writing xzr into a register must write 0, instead of the
+		 * value of SP.
+		 */
+		if (vre->reg != 31) {
+			error = vm_get_register(vcpu, vre->reg, &val);
+			if (error)
+				goto out;
+		}
 		error = regwrite(vcpu, val, regarg);
 	}