Using the full 64-bit register values is wrong in this case; especially soon after a mode switch from long mode to 32-bit one upper halves of registers may continue to be non-zero.
Fixes: 09fce8016596 ("Nested VMX: Emulation of guest VMXON/OFF instruction") Signed-off-by: Jan Beulich <jbeul...@suse.com> --- Note that the affected VMX insns are invalid to use from compatibility mode, and hence the more expensive vmx_guest_x86_mode() doesn't need using here. (VMCALL and VMFUNC, which are permitted in compatibility mode, aren't taking this path. In fact both aren't dealt with at all [explicitly] in vvmx.c.) --- v2: Add code comment. --- a/xen/arch/x86/hvm/vmx/vvmx.c +++ b/xen/arch/x86/hvm/vmx/vvmx.c @@ -360,7 +360,18 @@ enum vmx_insn_errno set_vvmcs_real_safe( static unsigned long reg_read(struct cpu_user_regs *regs, unsigned int index) { - return *decode_gpr(regs, index); + unsigned long val = *decode_gpr(regs, index); + + /* + * Outside of 64-bit mode, zero-extend the result from 32 bits, like + * hardware would. + * NB: A long-mode check is sufficient here, as insns this logic is used + * for will #UD in compatibility mode (and hence not make it here). + */ + if ( !hvm_long_mode_active(current) ) + val = (uint32_t)val; + + return val; } static void reg_write(struct cpu_user_regs *regs,