tools/testing/selftests/x86/sysret_rip.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
The existing 'sysret_rip' selftest asserts that 'regs->r11 ==
regs->flags'. This check relies on the behavior of the SYSCALL
instruction on legacy x86_64, which saves 'RFLAGS' into 'R11'.
However, on systems with FRED (Flexible Return and Event Delivery)
enabled, instead of using registers, all state is saved onto the stack.
Consequently, 'R11' retains its userspace value, causing the assertion
to fail.
Fix this by detecting FRED support via CPUID (Leaf 0x7, Subleaf 0x1, EAX
bit 17) and skipping the register assertion if FRED is present.
Signed-off-by: Yi Lai <yi1.lai@intel.com>
---
tools/testing/selftests/x86/sysret_rip.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/x86/sysret_rip.c b/tools/testing/selftests/x86/sysret_rip.c
index 2e423a335e1c..0228d6174d5b 100644
--- a/tools/testing/selftests/x86/sysret_rip.c
+++ b/tools/testing/selftests/x86/sysret_rip.c
@@ -21,6 +21,7 @@
#include <sys/user.h>
#include <sys/mman.h>
#include <assert.h>
+#include <cpuid.h>
#include "helpers.h"
@@ -64,9 +65,18 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
ctx->uc_mcontext.gregs[REG_RIP] = rip;
ctx->uc_mcontext.gregs[REG_RCX] = rip;
- /* R11 and EFLAGS should already match. */
- assert(ctx->uc_mcontext.gregs[REG_EFL] ==
- ctx->uc_mcontext.gregs[REG_R11]);
+ /*
+ * SYSCALL works differently on FRED, it does not save RIP and RFLAGS
+ * to RCX and R11.
+ */
+ unsigned int eax, ebx, ecx, edx;
+
+ __cpuid_count(0x7, 0x1, eax, ebx, ecx, edx);
+ if (!(eax & (1 << 17))) {
+ /* R11 and EFLAGS should already match. */
+ assert(ctx->uc_mcontext.gregs[REG_EFL] ==
+ ctx->uc_mcontext.gregs[REG_R11]);
+ }
sethandler(SIGSEGV, sigsegv_for_sigreturn_test, SA_RESETHAND);
}
--
2.43.0
On Fri, 20 Mar 2026 14:33:01 +0800
Yi Lai <yi1.lai@intel.com> wrote:
> The existing 'sysret_rip' selftest asserts that 'regs->r11 ==
> regs->flags'. This check relies on the behavior of the SYSCALL
> instruction on legacy x86_64, which saves 'RFLAGS' into 'R11'.
>
> However, on systems with FRED (Flexible Return and Event Delivery)
> enabled, instead of using registers, all state is saved onto the stack.
> Consequently, 'R11' retains its userspace value, causing the assertion
> to fail.
>
> Fix this by detecting FRED support via CPUID (Leaf 0x7, Subleaf 0x1, EAX
> bit 17) and skipping the register assertion if FRED is present.
For the selftest can't you just allow for R11 being unchanged?
That would be much simpler.
It isn't as though the test is doing much more than checking that
R11 is corrupted by being overwritten by EFLAGS.
David
>
> Signed-off-by: Yi Lai <yi1.lai@intel.com>
> ---
> tools/testing/selftests/x86/sysret_rip.c | 16 +++++++++++++---
> 1 file changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/tools/testing/selftests/x86/sysret_rip.c b/tools/testing/selftests/x86/sysret_rip.c
> index 2e423a335e1c..0228d6174d5b 100644
> --- a/tools/testing/selftests/x86/sysret_rip.c
> +++ b/tools/testing/selftests/x86/sysret_rip.c
> @@ -21,6 +21,7 @@
> #include <sys/user.h>
> #include <sys/mman.h>
> #include <assert.h>
> +#include <cpuid.h>
>
> #include "helpers.h"
>
> @@ -64,9 +65,18 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
> ctx->uc_mcontext.gregs[REG_RIP] = rip;
> ctx->uc_mcontext.gregs[REG_RCX] = rip;
>
> - /* R11 and EFLAGS should already match. */
> - assert(ctx->uc_mcontext.gregs[REG_EFL] ==
> - ctx->uc_mcontext.gregs[REG_R11]);
> + /*
> + * SYSCALL works differently on FRED, it does not save RIP and RFLAGS
> + * to RCX and R11.
> + */
> + unsigned int eax, ebx, ecx, edx;
> +
> + __cpuid_count(0x7, 0x1, eax, ebx, ecx, edx);
> + if (!(eax & (1 << 17))) {
> + /* R11 and EFLAGS should already match. */
> + assert(ctx->uc_mcontext.gregs[REG_EFL] ==
> + ctx->uc_mcontext.gregs[REG_R11]);
> + }
>
> sethandler(SIGSEGV, sigsegv_for_sigreturn_test, SA_RESETHAND);
> }
On March 24, 2026 4:08:56 AM PDT, David Laight <david.laight.linux@gmail.com> wrote:
>On Fri, 20 Mar 2026 14:33:01 +0800
>Yi Lai <yi1.lai@intel.com> wrote:
>
>> The existing 'sysret_rip' selftest asserts that 'regs->r11 ==
>> regs->flags'. This check relies on the behavior of the SYSCALL
>> instruction on legacy x86_64, which saves 'RFLAGS' into 'R11'.
>>
>> However, on systems with FRED (Flexible Return and Event Delivery)
>> enabled, instead of using registers, all state is saved onto the stack.
>> Consequently, 'R11' retains its userspace value, causing the assertion
>> to fail.
>>
>> Fix this by detecting FRED support via CPUID (Leaf 0x7, Subleaf 0x1, EAX
>> bit 17) and skipping the register assertion if FRED is present.
>
>For the selftest can't you just allow for R11 being unchanged?
>That would be much simpler.
>It isn't as though the test is doing much more than checking that
>R11 is corrupted by being overwritten by EFLAGS.
>
> David
>
>>
>> Signed-off-by: Yi Lai <yi1.lai@intel.com>
>> ---
>> tools/testing/selftests/x86/sysret_rip.c | 16 +++++++++++++---
>> 1 file changed, 13 insertions(+), 3 deletions(-)
>>
>> diff --git a/tools/testing/selftests/x86/sysret_rip.c b/tools/testing/selftests/x86/sysret_rip.c
>> index 2e423a335e1c..0228d6174d5b 100644
>> --- a/tools/testing/selftests/x86/sysret_rip.c
>> +++ b/tools/testing/selftests/x86/sysret_rip.c
>> @@ -21,6 +21,7 @@
>> #include <sys/user.h>
>> #include <sys/mman.h>
>> #include <assert.h>
>> +#include <cpuid.h>
>>
>> #include "helpers.h"
>>
>> @@ -64,9 +65,18 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
>> ctx->uc_mcontext.gregs[REG_RIP] = rip;
>> ctx->uc_mcontext.gregs[REG_RCX] = rip;
>>
>> - /* R11 and EFLAGS should already match. */
>> - assert(ctx->uc_mcontext.gregs[REG_EFL] ==
>> - ctx->uc_mcontext.gregs[REG_R11]);
>> + /*
>> + * SYSCALL works differently on FRED, it does not save RIP and RFLAGS
>> + * to RCX and R11.
>> + */
>> + unsigned int eax, ebx, ecx, edx;
>> +
>> + __cpuid_count(0x7, 0x1, eax, ebx, ecx, edx);
>> + if (!(eax & (1 << 17))) {
>> + /* R11 and EFLAGS should already match. */
>> + assert(ctx->uc_mcontext.gregs[REG_EFL] ==
>> + ctx->uc_mcontext.gregs[REG_R11]);
>> + }
>>
>> sethandler(SIGSEGV, sigsegv_for_sigreturn_test, SA_RESETHAND);
>> }
>
I thought we already made it do that a while ago...
On 3/19/26 23:33, Yi Lai wrote:
> + /*
> + * SYSCALL works differently on FRED, it does not save RIP and RFLAGS
> + * to RCX and R11.
> + */
> + unsigned int eax, ebx, ecx, edx;
> +
> + __cpuid_count(0x7, 0x1, eax, ebx, ecx, edx);
> + if (!(eax & (1 << 17))) {
> + /* R11 and EFLAGS should already match. */
> + assert(ctx->uc_mcontext.gregs[REG_EFL] ==
> + ctx->uc_mcontext.gregs[REG_R11]);
> + }
Could of things:
First, CPUID doesn't tell you if FRED is in use. Is it even on by
default yet? There might not be a better way to do this than checking
CPUID, but checking CPUID is imprecise at best. This at _least_ needs to
be commented. Could you check around for other cases like this in the
x86 selftests and see what the existing solutions are?
Second, this is selftests/, but I feel like we can be a bit more
disciplined than doing raw CPUID calls and sprinkling magic numbers all
about. The least that can be done here is giving bit 17 a name and
making the "is FRED supported" into a helper function.
But it does look like something that needs to get fixed either way!
> First, CPUID doesn't tell you if FRED is in use. Is it even on by > default yet? There might not be a better way to do this than checking > CPUID, but checking CPUID is imprecise at best. A reliable way to distinguish IDT and FRED mode is to: 1) Load $3 into %fs (x86_64) or %gs (i386) (i.e. whichever isn't thread local stoage) 2) execute a breakpoint, ignore the signal 3) Look to see whether %fs/%gs holds 3 or 0 IRET has a fun behaviour where it zeroes NULL selectors even if they had a non-zero RPL. ERETU doesn't do this; Andy Luto and I asked for this minor information leak to be removed, and Intel agreed as it served no purpose anyone could identify. As a consequence, you can use it to determine whether the kernel used IRET or ERET to return back to userspace. ~Andrew
On 3/20/26 08:47, Andrew Cooper wrote: >> First, CPUID doesn't tell you if FRED is in use. Is it even on by >> default yet? There might not be a better way to do this than checking >> CPUID, but checking CPUID is imprecise at best. > A reliable way to distinguish IDT and FRED mode is to: > > 1) Load $3 into %fs (x86_64) or %gs (i386) (i.e. whichever isn't thread > local stoage) > 2) execute a breakpoint, ignore the signal > 3) Look to see whether %fs/%gs holds 3 or 0 > > IRET has a fun behaviour where it zeroes NULL selectors even if they had > a non-zero RPL. > > ERETU doesn't do this; Andy Luto and I asked for this minor information > leak to be removed, and Intel agreed as it served no purpose anyone > could identify. > > As a consequence, you can use it to determine whether the kernel used > IRET or ERET to return back to userspace. I was thinking of just grepping /proc/cpuinfo for "fred", but that sounds much more fun! :)
On Fri, Mar 20, 2026 at 08:50:54AM -0700, Dave Hansen wrote:
> On 3/20/26 08:47, Andrew Cooper wrote:
> >> First, CPUID doesn't tell you if FRED is in use. Is it even on by
> >> default yet? There might not be a better way to do this than checking
> >> CPUID, but checking CPUID is imprecise at best.
> > A reliable way to distinguish IDT and FRED mode is to:
> >
> > 1) Load $3 into %fs (x86_64) or %gs (i386) (i.e. whichever isn't thread
> > local stoage)
> > 2) execute a breakpoint, ignore the signal
> > 3) Look to see whether %fs/%gs holds 3 or 0
> >
> > IRET has a fun behaviour where it zeroes NULL selectors even if they had
> > a non-zero RPL.
> >
> > ERETU doesn't do this; Andy Luto and I asked for this minor information
> > leak to be removed, and Intel agreed as it served no purpose anyone
> > could identify.
> >
> > As a consequence, you can use it to determine whether the kernel used
> > IRET or ERET to return back to userspace.
>
> I was thinking of just grepping /proc/cpuinfo for "fred", but that
> sounds much more fun! :)
Thank you both for the review and suggestions. The behavioral difference
between IRET and ERETU is a more robust way to detect FRED activation
than checking CPUID.
How about the following implementation to add a helper function to
determine if FRED is enabled at runtime:
static void empty_handler(int sig, siginfo_t *info, void *ctx_void)
{
}
static bool is_fred_enabled(void)
{
unsigned short gs_val;
sethandler(SIGTRAP, empty_handler, 0);
/*
* Distinguish IDT and FRED mode by loading GS with a non-zero RPL and
* triggering an exception:
* IDT (IRET) clears RPL bits of NULL selectors.
* FRED (ERETU) preserves them.
*
* If GS is loaded with 3 (Index=0, RPL=3), and we trigger an exception:
* Legacy should restore GS as 0.
* FRED should preserve GS as 3.
*/
asm volatile(
"mov $3, %%ax\n\t"
"mov %%ax, %%gs\n\t"
"int3\n\t"
"mov %%gs, %%ax\n\t"
"mov %%ax, %0\n\t"
: "=r" (gs_val)
:
: "ax", "memory"
);
clearhandler(SIGTRAP);
return gs_val == 3;
}
On 23/03/2026 5:55 am, Lai, Yi wrote:
> On Fri, Mar 20, 2026 at 08:50:54AM -0700, Dave Hansen wrote:
>> On 3/20/26 08:47, Andrew Cooper wrote:
>>>> First, CPUID doesn't tell you if FRED is in use. Is it even on by
>>>> default yet? There might not be a better way to do this than checking
>>>> CPUID, but checking CPUID is imprecise at best.
>>> A reliable way to distinguish IDT and FRED mode is to:
>>>
>>> 1) Load $3 into %fs (x86_64) or %gs (i386) (i.e. whichever isn't thread
>>> local stoage)
>>> 2) execute a breakpoint, ignore the signal
>>> 3) Look to see whether %fs/%gs holds 3 or 0
>>>
>>> IRET has a fun behaviour where it zeroes NULL selectors even if they had
>>> a non-zero RPL.
>>>
>>> ERETU doesn't do this; Andy Luto and I asked for this minor information
>>> leak to be removed, and Intel agreed as it served no purpose anyone
>>> could identify.
>>>
>>> As a consequence, you can use it to determine whether the kernel used
>>> IRET or ERET to return back to userspace.
>> I was thinking of just grepping /proc/cpuinfo for "fred", but that
>> sounds much more fun! :)
> Thank you both for the review and suggestions. The behavioral difference
> between IRET and ERETU is a more robust way to detect FRED activation
> than checking CPUID.
>
> How about the following implementation to add a helper function to
> determine if FRED is enabled at runtime:
>
> static void empty_handler(int sig, siginfo_t *info, void *ctx_void)
> {
> }
>
> static bool is_fred_enabled(void)
> {
> unsigned short gs_val;
>
> sethandler(SIGTRAP, empty_handler, 0);
What about setting SIG_IGN instead?
>
> /*
> * Distinguish IDT and FRED mode by loading GS with a non-zero RPL and
> * triggering an exception:
> * IDT (IRET) clears RPL bits of NULL selectors.
> * FRED (ERETU) preserves them.
> *
> * If GS is loaded with 3 (Index=0, RPL=3), and we trigger an exception:
> * Legacy should restore GS as 0.
> * FRED should preserve GS as 3.
> */
> asm volatile(
> "mov $3, %%ax\n\t"
> "mov %%ax, %%gs\n\t"
> "int3\n\t"
> "mov %%gs, %%ax\n\t"
> "mov %%ax, %0\n\t"
> : "=r" (gs_val)
> :
> : "ax", "memory"
> );
asm volatile (
"mov %[rpl3], %%gs\n\t"
"int3\n\t"
"mov %%gs, %[res]"
: [res] "=r" (gs_val)
: [rpl3] "r" (3));
No need for any clobbers. Let the compiler do the hard work for you.
~Andrew
On Mon, Mar 23, 2026 at 04:39:58PM +0000, Andrew Cooper wrote:
> On 23/03/2026 5:55 am, Lai, Yi wrote:
> > On Fri, Mar 20, 2026 at 08:50:54AM -0700, Dave Hansen wrote:
> >> On 3/20/26 08:47, Andrew Cooper wrote:
> >>>> First, CPUID doesn't tell you if FRED is in use. Is it even on by
> >>>> default yet? There might not be a better way to do this than checking
> >>>> CPUID, but checking CPUID is imprecise at best.
> >>> A reliable way to distinguish IDT and FRED mode is to:
> >>>
> >>> 1) Load $3 into %fs (x86_64) or %gs (i386) (i.e. whichever isn't thread
> >>> local stoage)
> >>> 2) execute a breakpoint, ignore the signal
> >>> 3) Look to see whether %fs/%gs holds 3 or 0
> >>>
> >>> IRET has a fun behaviour where it zeroes NULL selectors even if they had
> >>> a non-zero RPL.
> >>>
> >>> ERETU doesn't do this; Andy Luto and I asked for this minor information
> >>> leak to be removed, and Intel agreed as it served no purpose anyone
> >>> could identify.
> >>>
> >>> As a consequence, you can use it to determine whether the kernel used
> >>> IRET or ERET to return back to userspace.
> >> I was thinking of just grepping /proc/cpuinfo for "fred", but that
> >> sounds much more fun! :)
> > Thank you both for the review and suggestions. The behavioral difference
> > between IRET and ERETU is a more robust way to detect FRED activation
> > than checking CPUID.
> >
> > How about the following implementation to add a helper function to
> > determine if FRED is enabled at runtime:
> >
> > static void empty_handler(int sig, siginfo_t *info, void *ctx_void)
> > {
> > }
> >
> > static bool is_fred_enabled(void)
> > {
> > unsigned short gs_val;
> >
> > sethandler(SIGTRAP, empty_handler, 0);
>
> What about setting SIG_IGN instead?
>
I tested setting signal(SIGTRAP, SIG_IGN), but it causes the test to
terminate with a trace/breakpoint trap (core dump) when the 'int3'
instruction initiates the hardware exception. Therefore, I will keep the
empty_handler() implementation to ensure it can safely resume execution.
> >
> > /*
> > * Distinguish IDT and FRED mode by loading GS with a non-zero RPL and
> > * triggering an exception:
> > * IDT (IRET) clears RPL bits of NULL selectors.
> > * FRED (ERETU) preserves them.
> > *
> > * If GS is loaded with 3 (Index=0, RPL=3), and we trigger an exception:
> > * Legacy should restore GS as 0.
> > * FRED should preserve GS as 3.
> > */
> > asm volatile(
> > "mov $3, %%ax\n\t"
> > "mov %%ax, %%gs\n\t"
> > "int3\n\t"
> > "mov %%gs, %%ax\n\t"
> > "mov %%ax, %0\n\t"
> > : "=r" (gs_val)
> > :
> > : "ax", "memory"
> > );
>
> asm volatile (
> "mov %[rpl3], %%gs\n\t"
> "int3\n\t"
> "mov %%gs, %[res]"
> : [res] "=r" (gs_val)
> : [rpl3] "r" (3));
>
> No need for any clobbers. Let the compiler do the hard work for you.
>
Thank you for the improved assembly block and it's indeed cleaner. I
will adopt your suggestion and send out v2.
Regards,
Yi Lai
> ~Andrew
On March 20, 2026 8:50:54 AM PDT, Dave Hansen <dave.hansen@intel.com> wrote: >On 3/20/26 08:47, Andrew Cooper wrote: >>> First, CPUID doesn't tell you if FRED is in use. Is it even on by >>> default yet? There might not be a better way to do this than checking >>> CPUID, but checking CPUID is imprecise at best. >> A reliable way to distinguish IDT and FRED mode is to: >> >> 1) Load $3 into %fs (x86_64) or %gs (i386) (i.e. whichever isn't thread >> local stoage) >> 2) execute a breakpoint, ignore the signal >> 3) Look to see whether %fs/%gs holds 3 or 0 >> >> IRET has a fun behaviour where it zeroes NULL selectors even if they had >> a non-zero RPL. >> >> ERETU doesn't do this; Andy Luto and I asked for this minor information >> leak to be removed, and Intel agreed as it served no purpose anyone >> could identify. >> >> As a consequence, you can use it to determine whether the kernel used >> IRET or ERET to return back to userspace. > >I was thinking of just grepping /proc/cpuinfo for "fred", but that >sounds much more fun! :) This is a great example of why we need the patchset to clear compiled-out flags.
> On Mar 20, 2026, at 8:50 AM, Dave Hansen <dave.hansen@intel.com> wrote: > > On 3/20/26 08:47, Andrew Cooper wrote: >>> First, CPUID doesn't tell you if FRED is in use. Is it even on by >>> default yet? There might not be a better way to do this than checking >>> CPUID, but checking CPUID is imprecise at best. >> A reliable way to distinguish IDT and FRED mode is to: >> >> 1) Load $3 into %fs (x86_64) or %gs (i386) (i.e. whichever isn't thread >> local stoage) >> 2) execute a breakpoint, ignore the signal >> 3) Look to see whether %fs/%gs holds 3 or 0 >> >> IRET has a fun behaviour where it zeroes NULL selectors even if they had >> a non-zero RPL. >> >> ERETU doesn't do this; Andy Luto and I asked for this minor information >> leak to be removed, and Intel agreed as it served no purpose anyone >> could identify. >> >> As a consequence, you can use it to determine whether the kernel used >> IRET or ERET to return back to userspace. > > I was thinking of just grepping /proc/cpuinfo for "fred", but that > sounds much more fun! :) +1 :) This serves as a key architectural differentiator between FRED and the legacy IDT framework. For additional context, here is a fix to user segment selector values: https://lore.kernel.org/all/174069328263.10177.6796873487608898067.tip-bot2@tip-bot2/ It’s worth noting that there was an attempt to fix this bug roughly three years ago: https://lore.kernel.org/lkml/20230220030959.119222-1-ammarfaizi2@gnuweeb.org/
On Sat, Mar 21, 2026 at 11:13:29PM -0700, Xin Li wrote: > > > > On Mar 20, 2026, at 8:50 AM, Dave Hansen <dave.hansen@intel.com> wrote: > > > > On 3/20/26 08:47, Andrew Cooper wrote: > >>> First, CPUID doesn't tell you if FRED is in use. Is it even on by > >>> default yet? There might not be a better way to do this than checking > >>> CPUID, but checking CPUID is imprecise at best. > >> A reliable way to distinguish IDT and FRED mode is to: > >> > >> 1) Load $3 into %fs (x86_64) or %gs (i386) (i.e. whichever isn't thread > >> local stoage) > >> 2) execute a breakpoint, ignore the signal > >> 3) Look to see whether %fs/%gs holds 3 or 0 > >> > >> IRET has a fun behaviour where it zeroes NULL selectors even if they had > >> a non-zero RPL. > >> > >> ERETU doesn't do this; Andy Luto and I asked for this minor information > >> leak to be removed, and Intel agreed as it served no purpose anyone > >> could identify. > >> > >> As a consequence, you can use it to determine whether the kernel used > >> IRET or ERET to return back to userspace. > > > > I was thinking of just grepping /proc/cpuinfo for "fred", but that > > sounds much more fun! :) > > +1 :) > > This serves as a key architectural differentiator between FRED and the legacy > IDT framework. > > For additional context, here is a fix to user segment selector values: > https://lore.kernel.org/all/174069328263.10177.6796873487608898067.tip-bot2@tip-bot2/ > > It’s worth noting that there was an attempt to fix this bug roughly three years > ago: > https://lore.kernel.org/lkml/20230220030959.119222-1-ammarfaizi2@gnuweeb.org/ > Thanks for the context and links, Xin. My patch is a simple, focused fix to unblock current regression in 'sysret_rip'. The goal is just to ensure it doesn't falsely fail on FRED systems by skipping the IDT assertion (R11==RFLAGS). Checking Ammar's patch series, it indeed looks like a more comprehensive solution that not only handles the difference but also adds specific test coverage for consistency. Is there a specific reason it didn't land in the mainline kernel? If you think that is the preferred direction, I would be happy to contribute to that effort collaboratively. > > >
On 2026-03-22 23:06, Lai, Yi wrote:
>
> Thanks for the context and links, Xin.
>
> My patch is a simple, focused fix to unblock current regression in
> 'sysret_rip'. The goal is just to ensure it doesn't falsely fail on FRED
> systems by skipping the IDT assertion (R11==RFLAGS).
>
> Checking Ammar's patch series, it indeed looks like a more comprehensive
> solution that not only handles the difference but also adds specific
> test coverage for consistency. Is there a specific reason it didn't
> land in the mainline kernel? If you think that is the preferred
> direction, I would be happy to contribute to that effort
> collaboratively.
>
So for what it's worth, I have used this sequence to probe for FRED, but it is
basically probing for the effect you are truing to test for here:
#include <inttypes.h>
#include <stdbool.h>
#include <linux/unistd.h>
bool fred_is_on(void)
{
const uint64_t sentinel1 = 0xfeedfacedeadbeef;
const uint64_t sentinel2 = 0xbeeffeeb1ef00d1e;
register uint64_t rax asm("rax") = __NR_getppid;
register uint64_t rcx asm("rcx") = sentinel1;
register uint64_t r11 asm("r11") = sentinel2;
asm volatile("syscall" : "+r" (rax), "+r" (rcx), "+r" (r11));
return !((rcx ^ sentinel1) | (r11 ^ sentinel2));
}
-hpa
On 23/03/2026 7:11 pm, H. Peter Anvin wrote:
> On 2026-03-22 23:06, Lai, Yi wrote:
>> Thanks for the context and links, Xin.
>>
>> My patch is a simple, focused fix to unblock current regression in
>> 'sysret_rip'. The goal is just to ensure it doesn't falsely fail on FRED
>> systems by skipping the IDT assertion (R11==RFLAGS).
>>
>> Checking Ammar's patch series, it indeed looks like a more comprehensive
>> solution that not only handles the difference but also adds specific
>> test coverage for consistency. Is there a specific reason it didn't
>> land in the mainline kernel? If you think that is the preferred
>> direction, I would be happy to contribute to that effort
>> collaboratively.
>>
> So for what it's worth, I have used this sequence to probe for FRED, but it is
> basically probing for the effect you are truing to test for here:
>
> #include <inttypes.h>
> #include <stdbool.h>
> #include <linux/unistd.h>
>
> bool fred_is_on(void)
> {
> const uint64_t sentinel1 = 0xfeedfacedeadbeef;
> const uint64_t sentinel2 = 0xbeeffeeb1ef00d1e;
>
> register uint64_t rax asm("rax") = __NR_getppid;
> register uint64_t rcx asm("rcx") = sentinel1;
> register uint64_t r11 asm("r11") = sentinel2;
>
> asm volatile("syscall" : "+r" (rax), "+r" (rcx), "+r" (r11));
>
> return !((rcx ^ sentinel1) | (r11 ^ sentinel2));
> }
>
> -hpa
This doesn't really test whether FRED is active. It tests whether the
OS is not providing strict backwards compatibility, and I think will
malfunction when there's a hypervisor above Linux providing strict
backwards compatibility.
~Andrew
On 2026-03-23 12:17, Andrew Cooper wrote: > > This doesn't really test whether FRED is active. It tests whether the > OS is not providing strict backwards compatibility, and I think will > malfunction when there's a hypervisor above Linux providing strict > backwards compatibility. > But that applies equally to IRET, no? If the hypervisor clobbers the segment selector like IRET would in the interest of compatibility then you have the same issue. If the guest is running a FRED kernel and the hypervisor goes in and mucks with the state after ERETU behind the kernel's back I think you have a much, much bigger problem. -hpa
On 23/03/2026 8:27 pm, H. Peter Anvin wrote: > On 2026-03-23 12:17, Andrew Cooper wrote: >> This doesn't really test whether FRED is active. It tests whether the >> OS is not providing strict backwards compatibility, and I think will >> malfunction when there's a hypervisor above Linux providing strict >> backwards compatibility. >> > But that applies equally to IRET, no? If the hypervisor clobbers the segment > selector like IRET would in the interest of compatibility then you have the > same issue. I suppose. I for one don't care to provide that level of compatibility. But for SYSCALL, what are Linux's plans for CRIU or RR ? I had to fix SYSCALL legacy behaviour in Xen for the following case: * PV guest issues SYSCALL on FRED system. %rcx/%r11 not clobbered * Migrate to a non-FRED system * Xen uses a real SYSRET instruction to resume execution Here, the guest continues executing at whichever dead variable is in %rcx. CRIU/RR won't be exactly the same, but will suffer the same class of problem when moving between FRED and non-FRED systems. ~Andrew
On March 24, 2026 7:08:14 AM PDT, Andrew Cooper <andrew.cooper3@citrix.com> wrote: >On 23/03/2026 8:27 pm, H. Peter Anvin wrote: >> On 2026-03-23 12:17, Andrew Cooper wrote: >>> This doesn't really test whether FRED is active. It tests whether the >>> OS is not providing strict backwards compatibility, and I think will >>> malfunction when there's a hypervisor above Linux providing strict >>> backwards compatibility. >>> >> But that applies equally to IRET, no? If the hypervisor clobbers the segment >> selector like IRET would in the interest of compatibility then you have the >> same issue. > >I suppose. I for one don't care to provide that level of compatibility. > >But for SYSCALL, what are Linux's plans for CRIU or RR ? I had to fix >SYSCALL legacy behaviour in Xen for the following case: > >* PV guest issues SYSCALL on FRED system. %rcx/%r11 not clobbered >* Migrate to a non-FRED system >* Xen uses a real SYSRET instruction to resume execution > > >Here, the guest continues executing at whichever dead variable is in %rcx. > >CRIU/RR won't be exactly the same, but will suffer the same class of >problem when moving between FRED and non-FRED systems. > >~Andrew "Doctor, it hurts when I PV?"
On 24/03/2026 2:33 pm, H. Peter Anvin wrote: > On March 24, 2026 7:08:14 AM PDT, Andrew Cooper <andrew.cooper3@citrix.com> wrote: >> On 23/03/2026 8:27 pm, H. Peter Anvin wrote: >>> On 2026-03-23 12:17, Andrew Cooper wrote: >>>> This doesn't really test whether FRED is active. It tests whether the >>>> OS is not providing strict backwards compatibility, and I think will >>>> malfunction when there's a hypervisor above Linux providing strict >>>> backwards compatibility. >>>> >>> But that applies equally to IRET, no? If the hypervisor clobbers the segment >>> selector like IRET would in the interest of compatibility then you have the >>> same issue. >> I suppose. I for one don't care to provide that level of compatibility. >> >> But for SYSCALL, what are Linux's plans for CRIU or RR ? I had to fix >> SYSCALL legacy behaviour in Xen for the following case: >> >> * PV guest issues SYSCALL on FRED system. %rcx/%r11 not clobbered >> * Migrate to a non-FRED system >> * Xen uses a real SYSRET instruction to resume execution >> >> >> Here, the guest continues executing at whichever dead variable is in %rcx. >> >> CRIU/RR won't be exactly the same, but will suffer the same class of >> problem when moving between FRED and non-FRED systems. >> >> ~Andrew > "Doctor, it hurts when I PV?" I'm asking straight up, what is Linux doing to fix this same issue for CRIU/RR? ~Andrew P.S. It's rhetorical, seeing as it's taken between Linux 6.9 and now (2 whole years) for anyone to even run the x86 selftests on a FRED system.
On March 24, 2026 7:46:26 AM PDT, Andrew Cooper <andrew.cooper3@citrix.com> wrote: >On 24/03/2026 2:33 pm, H. Peter Anvin wrote: >> On March 24, 2026 7:08:14 AM PDT, Andrew Cooper <andrew.cooper3@citrix.com> wrote: >>> On 23/03/2026 8:27 pm, H. Peter Anvin wrote: >>>> On 2026-03-23 12:17, Andrew Cooper wrote: >>>>> This doesn't really test whether FRED is active. It tests whether the >>>>> OS is not providing strict backwards compatibility, and I think will >>>>> malfunction when there's a hypervisor above Linux providing strict >>>>> backwards compatibility. >>>>> >>>> But that applies equally to IRET, no? If the hypervisor clobbers the segment >>>> selector like IRET would in the interest of compatibility then you have the >>>> same issue. >>> I suppose. I for one don't care to provide that level of compatibility. >>> >>> But for SYSCALL, what are Linux's plans for CRIU or RR ? I had to fix >>> SYSCALL legacy behaviour in Xen for the following case: >>> >>> * PV guest issues SYSCALL on FRED system. %rcx/%r11 not clobbered >>> * Migrate to a non-FRED system >>> * Xen uses a real SYSRET instruction to resume execution >>> >>> >>> Here, the guest continues executing at whichever dead variable is in %rcx. >>> >>> CRIU/RR won't be exactly the same, but will suffer the same class of >>> problem when moving between FRED and non-FRED systems. >>> >>> ~Andrew >> "Doctor, it hurts when I PV?" > >I'm asking straight up, what is Linux doing to fix this same issue for >CRIU/RR? > >~Andrew > >P.S. It's rhetorical, seeing as it's taken between Linux 6.9 and now (2 >whole years) for anyone to even run the x86 selftests on a FRED system. That's not true, and in fact *this exact bug was fixed once already*; apparently someone "fixed the fix?" I'm well and truly confused by it.
> Checking Ammar's patch series, it indeed looks like a more comprehensive > solution that not only handles the difference but also adds specific > test coverage for consistency. Is there a specific reason it didn't > land in the mainline kernel? If you think that is the preferred > direction, I would be happy to contribute to that effort > collaboratively. I prefer the approach Andrew suggested. Ammar disappeared so that patch series landed nowhere.
© 2016 - 2026 Red Hat, Inc.