summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2017-08-01 07:11:36 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-09-13 14:13:36 -0700
commitebf381be016f3610c483bca561262cd499b04e84 (patch)
tree92e55c6bbeee333fa058010701b8147a5deabff8 /tools
parent0f7dbc4d5bc88432ab1c8639c66628d4f5903ae9 (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.c41
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]);
+ }
}
}