[PATCH v2] x86/pv: Provide better SYSCALL backwards compatibility in FRED mode

Andrew Cooper posted 1 patch 1 day, 13 hours ago
Patches applied successfully (tree, apply log)
git fetch https://gitlab.com/xen-project/patchew/xen tags/patchew/20260331082142.13254-1-andrew.cooper3@citrix.com
xen/arch/x86/traps.c             |  9 +++++----
xen/arch/x86/x86_64/entry-fred.S | 12 +++++++++++-
2 files changed, 16 insertions(+), 5 deletions(-)
[PATCH v2] x86/pv: Provide better SYSCALL backwards compatibility in FRED mode
Posted by Andrew Cooper 1 day, 13 hours ago
In FRED mode, the SYSCALL instruction does not modify %rcx/%r11.  Software
using SYSCALL spills %rcx/%r11 around the invocation, which is why FRED not
doing this goes largely unnoticed.

Nevertheless, there is a difference in the guest immediately following cases
where Xen would use SYSRET in non-FRED mode.  These are:

 * HYPERCALL_iret with VGCF_in_syscall set.
 * Delivery to a registered entrypoint.  In the PV ABI this is always SYSRET'd
   to, with %rcx/%r11 provided on the stack.

Debugging or snapshotting activities will observe the stale contents of
%rcx/%r11 in FRED mode, rather than the %rip/eflags value they'd have in
IDT mode.  Manually adjust them 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: 76193ef47d91 ("x86/pv: System call handling in FRED mode")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>

v2:
 * Rewrite the commit message.
 * Set TRAP_syscall in the SYSCALL path.
---
 xen/arch/x86/traps.c             |  9 +++++----
 xen/arch/x86/x86_64/entry-fred.S | 12 +++++++++++-
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 8aa1e4181bd1..656ad337ab90 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -2392,10 +2392,6 @@ void asmlinkage entry_from_pv(struct cpu_user_regs *regs)
              * The guest isn't aware of FRED, so recreate the legacy
              * behaviour.
              *
-             * The non-FRED SYSCALL path sets TRAP_syscall in entry_vector to
-             * signal that SYSRET can be used, but this isn't relevant in FRED
-             * mode.
-             *
              * When setting the selectors, clear all upper metadata again for
              * backwards compatibility.  In particular fred_ss.swint becomes
              * pend_DB on ERETx, and nothing else in the pv_hypercall() would
@@ -2411,9 +2407,14 @@ 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) )
+            {
+                regs->entry_vector |= TRAP_syscall;
                 pv_hypercall(regs);
+            }
             else if ( (l ? curr->arch.pv.syscall_callback_eip
                          : curr->arch.pv.syscall32_callback_eip) == 0 )
             {
diff --git a/xen/arch/x86/x86_64/entry-fred.S b/xen/arch/x86/x86_64/entry-fred.S
index 2fa57beb930c..e9c84423dacd 100644
--- a/xen/arch/x86/x86_64/entry-fred.S
+++ b/xen/arch/x86/x86_64/entry-fred.S
@@ -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
-- 
2.34.1


Re: [PATCH v2] x86/pv: Provide better SYSCALL backwards compatibility in FRED mode
Posted by Jan Beulich 1 day, 13 hours ago
On 31.03.2026 10:21, Andrew Cooper wrote:
> In FRED mode, the SYSCALL instruction does not modify %rcx/%r11.  Software
> using SYSCALL spills %rcx/%r11 around the invocation, which is why FRED not
> doing this goes largely unnoticed.
> 
> Nevertheless, there is a difference in the guest immediately following cases
> where Xen would use SYSRET in non-FRED mode.  These are:
> 
>  * HYPERCALL_iret with VGCF_in_syscall set.
>  * Delivery to a registered entrypoint.  In the PV ABI this is always SYSRET'd
>    to, with %rcx/%r11 provided on the stack.
> 
> Debugging or snapshotting activities will observe the stale contents of
> %rcx/%r11 in FRED mode, rather than the %rip/eflags value they'd have in
> IDT mode.  Manually adjust them 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: 76193ef47d91 ("x86/pv: System call handling in FRED mode")
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>

Reviewed-by: Jan Beulich <jbeulich@suse.com>