Skip to content

Commit 2467b23

Browse files
laifryieeopsiff
authored andcommitted
selftests/x86: Fix sysret_rip assertion failure on FRED systems
maillist inclusion category: other 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 if FRED is enabled and skipping the register assertion in that case. The detection is done by checking if the RPL bits of the GS selector are preserved after a hardware exception. IDT (via IRET) clears the RPL bits of NULL selectors, while FRED (via ERETU) preserves them. Suggested-by: Andrew Cooper <andrew.cooper3@citrix.com> Signed-off-by: Yi Lai <yi1.lai@intel.com> Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
1 parent 0281371 commit 2467b23

1 file changed

Lines changed: 42 additions & 3 deletions

File tree

tools/testing/selftests/x86/sysret_rip.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,39 @@ extern const char test_page[];
3333

3434
static const void *current_test_page_addr = test_page;
3535

36+
static void empty_handler(int sig, siginfo_t *info, void *ctx_void)
37+
{
38+
}
39+
40+
static bool is_fred_enabled(void)
41+
{
42+
unsigned short gs_val;
43+
44+
sethandler(SIGTRAP, empty_handler, 0);
45+
46+
/*
47+
* Distinguish IDT and FRED mode by loading GS with a non-zero RPL and
48+
* triggering an exception:
49+
* IDT (IRET) clears RPL bits of NULL selectors.
50+
* FRED (ERETU) preserves them.
51+
*
52+
* If GS is loaded with 3 (Index=0, RPL=3), trigger an exception:
53+
* IDT should restore GS as 0.
54+
* FRED should preserve GS as 3.
55+
*/
56+
asm volatile (
57+
"mov %[rpl3], %%gs\n\t"
58+
"int3\n\t"
59+
"mov %%gs, %[res]"
60+
: [res] "=r" (gs_val)
61+
: [rpl3] "r" (3)
62+
);
63+
64+
clearhandler(SIGTRAP);
65+
66+
return gs_val == 3;
67+
}
68+
3669
/* State used by our signal handlers. */
3770
static gregset_t initial_regs;
3871

@@ -64,9 +97,15 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
6497
ctx->uc_mcontext.gregs[REG_RIP] = rip;
6598
ctx->uc_mcontext.gregs[REG_RCX] = rip;
6699

67-
/* R11 and EFLAGS should already match. */
68-
assert(ctx->uc_mcontext.gregs[REG_EFL] ==
69-
ctx->uc_mcontext.gregs[REG_R11]);
100+
/*
101+
* SYSCALL works differently on FRED, it does not save RIP and RFLAGS
102+
* to RCX and R11.
103+
*/
104+
if (!is_fred_enabled()) {
105+
/* R11 and EFLAGS should already match. */
106+
assert(ctx->uc_mcontext.gregs[REG_EFL] ==
107+
ctx->uc_mcontext.gregs[REG_R11]);
108+
}
70109

71110
sethandler(SIGSEGV, sigsegv_for_sigreturn_test, SA_RESETHAND);
72111
}

0 commit comments

Comments
 (0)