x86/pv: Provide better SYSCALL backwards compatibility in FRED mode

In FRED mode, the SYSCALL instruction does not modify %rcx/%r11.  All current
software using SYSCALL expects the pre-FRED behaviour and spills %rcx/%r11
around the invocation, which is why FRED not doing this goes largely
unnoticed.

However, consider the following migration scenario:

 * VM suspends.  Hypercall, so SYSCALL, %rcx/%r11 left unmodified
 * VM moves to a non-FRED system
 * Xen resumes the VM with a real SYSRET instruction

Instead of resuming at the instruction following the SYSCALL instruction, the
VM is resumed at whatever dead value was in %rcx.

In FRED mode, manually adjust %rcx/%r11 when SYSCALL is used and when SYSRET
would have been used.

Regarding the choice of instructions in eretu_exit_to_guest(), a branch would
be a context dependent 50/50 split (i.e. increased chance of mispredict), and
only saves one instruction.  The CMOVs read the same cacheline that ERETU is
about to process, so are as close to free as we can reasonably get.

Fixes: 76193ef47d ("x86/pv: System call handling in FRED mode")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Andrew Cooper committed 2026-05-28 16:19:16 +01:00
1 parent 941fdfc03e
commit c5a4b9125b
2 files changed
+13 -1

No files matched your search

+2
View File
@@ -2411,6 +2411,8 @@ void asmlinkage entry_from_pv(struct cpu_user_regs *regs)
regs->ssx = l ? FLAT_KERNEL_SS : FLAT_USER_SS32;
regs->csx = l ? FLAT_KERNEL_CS64 : FLAT_USER_CS32;
regs->rcx = regs->rip;
regs->r11 = regs->rflags;
if ( guest_kernel_mode(curr, regs) )
pv_hypercall(regs);
+11 -1
View File
@@ -4,6 +4,7 @@
#include <asm/asm_defns.h>
#include <asm/page.h>
#include <asm/processor.h>
.section .text.entry, "ax", @progbits
@@ -26,7 +27,16 @@ FUNC(entry_FRED_R3, 4096)
END(entry_FRED_R3)
FUNC(eretu_exit_to_guest)
POP_GPRS
/*
* PV guests aren't aware of FRED. If Xen in IDT mode would have used
* a SYSRET instruction, preserve the legacy behaviour for %rcx/%r11
*/
testb $TRAP_syscall >> 8, UREGS_entry_vector + 1(%rsp)
POP_GPRS /* Preserves flags */
cmovnz EFRAME_rip(%rsp), %rcx
cmovnz EFRAME_eflags(%rsp), %r11
/*
* Exceptions here are handled by redirecting either to
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.