selftests/x86/fsgsbase: Test selectors 1, 2, and 3
Those are funny cases. Make sure they work. (Something is screwy with signal handling if a selector is 1, 2, or 3. Anyone who wants to dive into that rabbit hole is welcome to do so.) Signed-off-by: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Borislav Petkov <bpetkov@suse.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Chang Seok <chang.seok.bae@intel.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: stable@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
9584d98bed
commit
23d98c2043
@ -285,9 +285,12 @@ static void *threadproc(void *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
|
||||
static void set_gs_and_switch_to(unsigned long local,
|
||||
unsigned short force_sel,
|
||||
unsigned long remote)
|
||||
{
|
||||
unsigned long base;
|
||||
unsigned short sel_pre_sched, sel_post_sched;
|
||||
|
||||
bool hard_zero = false;
|
||||
if (local == HARD_ZERO) {
|
||||
@ -297,6 +300,8 @@ static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
|
||||
|
||||
printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n",
|
||||
local, hard_zero ? " and clear gs" : "", remote);
|
||||
if (force_sel)
|
||||
printf("\tBefore schedule, set selector to 0x%hx\n", force_sel);
|
||||
if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0)
|
||||
err(1, "ARCH_SET_GS");
|
||||
if (hard_zero)
|
||||
@ -307,18 +312,35 @@ static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
|
||||
printf("[FAIL]\tGSBASE wasn't set as expected\n");
|
||||
}
|
||||
|
||||
if (force_sel) {
|
||||
asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
|
||||
sel_pre_sched = force_sel;
|
||||
local = read_base(GS);
|
||||
|
||||
/*
|
||||
* Signal delivery seems to mess up weird selectors. Put it
|
||||
* back.
|
||||
*/
|
||||
asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
|
||||
} else {
|
||||
asm volatile ("mov %%gs, %0" : "=rm" (sel_pre_sched));
|
||||
}
|
||||
|
||||
remote_base = remote;
|
||||
ftx = 1;
|
||||
syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
|
||||
while (ftx != 0)
|
||||
syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
|
||||
|
||||
asm volatile ("mov %%gs, %0" : "=rm" (sel_post_sched));
|
||||
base = read_base(GS);
|
||||
if (base == local) {
|
||||
printf("[OK]\tGSBASE remained 0x%lx\n", local);
|
||||
if (base == local && sel_pre_sched == sel_post_sched) {
|
||||
printf("[OK]\tGS/BASE remained 0x%hx/0x%lx\n",
|
||||
sel_pre_sched, local);
|
||||
} else {
|
||||
nerrs++;
|
||||
printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
|
||||
printf("[FAIL]\tGS/BASE changed from 0x%hx/0x%lx to 0x%hx/0x%lx\n",
|
||||
sel_pre_sched, local, sel_post_sched, base);
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,8 +403,15 @@ int main()
|
||||
|
||||
for (int local = 0; local < 4; local++) {
|
||||
for (int remote = 0; remote < 4; remote++) {
|
||||
set_gs_and_switch_to(bases_with_hard_zero[local],
|
||||
bases_with_hard_zero[remote]);
|
||||
for (unsigned short s = 0; s < 5; s++) {
|
||||
unsigned short sel = s;
|
||||
if (s == 4)
|
||||
asm ("mov %%ss, %0" : "=rm" (sel));
|
||||
set_gs_and_switch_to(
|
||||
bases_with_hard_zero[local],
|
||||
sel,
|
||||
bases_with_hard_zero[remote]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user