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 <[email protected]>
---
 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


Reply via email to