diff options
author | Andy Lutomirski <luto@kernel.org> | 2017-08-01 07:11:36 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-09-13 14:13:36 -0700 |
commit | ebf381be016f3610c483bca561262cd499b04e84 (patch) | |
tree | 92e55c6bbeee333fa058010701b8147a5deabff8 /tools | |
parent | 0f7dbc4d5bc88432ab1c8639c66628d4f5903ae9 (diff) |
selftests/x86/fsgsbase: Test selectors 1, 2, and 3
commit 23d98c204386a98d9ef9f9e744f41443ece4929f upstream.
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>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/testing/selftests/x86/fsgsbase.c | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/tools/testing/selftests/x86/fsgsbase.c b/tools/testing/selftests/x86/fsgsbase.c index 5b2b4b3c634c..9b4610c6d3fb 100644 --- a/tools/testing/selftests/x86/fsgsbase.c +++ b/tools/testing/selftests/x86/fsgsbase.c @@ -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]); + } } } |