From db1231dcdb4dc6cdcbdef0babe641a9162c0dc98 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 9 Dec 2015 20:11:47 +1100 Subject: powerpc: Fix DSCR inheritance over fork() Two DSCR tests have a hack in them: /* * XXX: Force a context switch out so that DSCR * current value is copied into the thread struct * which is required for the child to inherit the * changed value. */ sleep(1); We should not be working around this in the testcase, it is a kernel bug. Fix it by copying the current DSCR to the child, instead of what we had in the thread struct at last context switch. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c | 8 -------- tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c | 8 -------- 2 files changed, 16 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c index 8265504de571..08a8b95e3bc1 100644 --- a/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c +++ b/tools/testing/selftests/powerpc/dscr/dscr_inherit_exec_test.c @@ -60,14 +60,6 @@ int dscr_inherit_exec(void) else set_dscr(dscr); - /* - * XXX: Force a context switch out so that DSCR - * current value is copied into the thread struct - * which is required for the child to inherit the - * changed value. - */ - sleep(1); - pid = fork(); if (pid == -1) { perror("fork() failed"); diff --git a/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c b/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c index 4e414caf7f40..3e5a6d195e9a 100644 --- a/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c +++ b/tools/testing/selftests/powerpc/dscr/dscr_inherit_test.c @@ -40,14 +40,6 @@ int dscr_inherit(void) else set_dscr(dscr); - /* - * XXX: Force a context switch out so that DSCR - * current value is copied into the thread struct - * which is required for the child to inherit the - * changed value. - */ - sleep(1); - pid = fork(); if (pid == -1) { perror("fork() failed"); -- cgit v1.2.3-59-g8ed1b From fcb45ec074725baeb3aaa1b1854b9f44c3eebacf Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 24 Nov 2015 13:05:38 +1100 Subject: selftests/powerpc: Move get_auxv_entry() into utils.c This doesn't really belong in harness.c, it's a helper function. So move it into utils.c. Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/harness.c | 43 ------------------ tools/testing/selftests/powerpc/pmu/Makefile | 2 + tools/testing/selftests/powerpc/pmu/ebb/Makefile | 3 +- tools/testing/selftests/powerpc/tm/Makefile | 2 +- tools/testing/selftests/powerpc/utils.c | 58 ++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 45 deletions(-) create mode 100644 tools/testing/selftests/powerpc/utils.c (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c index f7997affd143..52f9be7f61f0 100644 --- a/tools/testing/selftests/powerpc/harness.c +++ b/tools/testing/selftests/powerpc/harness.c @@ -116,46 +116,3 @@ int test_harness(int (test_function)(void), char *name) return rc; } - -static char auxv[4096]; - -void *get_auxv_entry(int type) -{ - ElfW(auxv_t) *p; - void *result; - ssize_t num; - int fd; - - fd = open("/proc/self/auxv", O_RDONLY); - if (fd == -1) { - perror("open"); - return NULL; - } - - result = NULL; - - num = read(fd, auxv, sizeof(auxv)); - if (num < 0) { - perror("read"); - goto out; - } - - if (num > sizeof(auxv)) { - printf("Overflowed auxv buffer\n"); - goto out; - } - - p = (ElfW(auxv_t) *)auxv; - - while (p->a_type != AT_NULL) { - if (p->a_type == type) { - result = (void *)p->a_un.a_val; - break; - } - - p++; - } -out: - close(fd); - return result; -} diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile index a9099d9f8f39..50326cbb372d 100644 --- a/tools/testing/selftests/powerpc/pmu/Makefile +++ b/tools/testing/selftests/powerpc/pmu/Makefile @@ -12,6 +12,8 @@ $(TEST_PROGS): $(EXTRA_SOURCES) count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES) $(CC) $(CFLAGS) -m64 -o $@ $^ +per_event_excludes: ../utils.c + include ../../lib.mk DEFAULT_RUN_TESTS := $(RUN_TESTS) diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile index 5cdc9dbf2b27..8d2279c4bb4b 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile +++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile @@ -18,7 +18,8 @@ TEST_PROGS := reg_access_test event_attributes_test cycles_test \ all: $(TEST_PROGS) -$(TEST_PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S +$(TEST_PROGS): ../../harness.c ../../utils.c ../event.c ../lib.c \ + ebb.c ebb_handler.S trace.c busy_loop.S instruction_count_test: ../loop.S diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 4bea62a319dc..e7b9be7947c8 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -4,7 +4,7 @@ all: $(TEST_PROGS) $(TEST_PROGS): ../harness.c -tm-syscall: tm-syscall-asm.S +tm-syscall: tm-syscall-asm.S ../utils.c tm-syscall: CFLAGS += -mhtm -I../../../../../usr/include include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c new file mode 100644 index 000000000000..536113add380 --- /dev/null +++ b/tools/testing/selftests/powerpc/utils.c @@ -0,0 +1,58 @@ +/* + * Copyright 2013-2015, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +static char auxv[4096]; + +void *get_auxv_entry(int type) +{ + ElfW(auxv_t) *p; + void *result; + ssize_t num; + int fd; + + fd = open("/proc/self/auxv", O_RDONLY); + if (fd == -1) { + perror("open"); + return NULL; + } + + result = NULL; + + num = read(fd, auxv, sizeof(auxv)); + if (num < 0) { + perror("read"); + goto out; + } + + if (num > sizeof(auxv)) { + printf("Overflowed auxv buffer\n"); + goto out; + } + + p = (ElfW(auxv_t) *)auxv; + + while (p->a_type != AT_NULL) { + if (p->a_type == type) { + result = (void *)p->a_un.a_val; + break; + } + + p++; + } +out: + close(fd); + return result; +} -- cgit v1.2.3-59-g8ed1b From ede8ef3f824ea6e853a5e4b27467f583cdaa314e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 24 Nov 2015 13:05:39 +1100 Subject: selftests/powerpc: Add have_hwcap2() helper We already do this twice and want to add another so add a helper. Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/pmu/ebb/ebb.c | 3 +-- tools/testing/selftests/powerpc/tm/tm-syscall.c | 3 +-- tools/testing/selftests/powerpc/utils.h | 6 ++++++ 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c index 9729d9f90218..e67452f1bcff 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c +++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c @@ -13,7 +13,6 @@ #include #include #include -#include #include "trace.h" #include "reg.h" @@ -324,7 +323,7 @@ bool ebb_is_supported(void) { #ifdef PPC_FEATURE2_EBB /* EBB requires at least POWER8 */ - return ((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_EBB); + return have_hwcap2(PPC_FEATURE2_EBB); #else return false; #endif diff --git a/tools/testing/selftests/powerpc/tm/tm-syscall.c b/tools/testing/selftests/powerpc/tm/tm-syscall.c index e835bf7ec7ae..d7256b79ec4c 100644 --- a/tools/testing/selftests/powerpc/tm/tm-syscall.c +++ b/tools/testing/selftests/powerpc/tm/tm-syscall.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -80,7 +79,7 @@ pid_t getppid_tm(bool suspend) static inline bool have_htm_nosc(void) { #ifdef PPC_FEATURE2_HTM_NOSC - return ((long)get_auxv_entry(AT_HWCAP2) & PPC_FEATURE2_HTM_NOSC); + return have_hwcap2(PPC_FEATURE2_HTM_NOSC); #else printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n"); return false; diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h index b7d41086bb0a..fbf2bf530e50 100644 --- a/tools/testing/selftests/powerpc/utils.h +++ b/tools/testing/selftests/powerpc/utils.h @@ -8,6 +8,7 @@ #include #include +#include /* Avoid headaches with PRI?64 - just use %ll? always */ typedef unsigned long long u64; @@ -22,6 +23,11 @@ typedef uint8_t u8; int test_harness(int (test_function)(void), char *name); extern void *get_auxv_entry(int type); +static inline bool have_hwcap2(unsigned long ftr2) +{ + return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2; +} + /* Yes, this is evil */ #define FAIL_IF(x) \ do { \ -- cgit v1.2.3-59-g8ed1b From 34dc8b279dc5dd3ce863298056989bdd7f4979c8 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 24 Nov 2015 13:05:40 +1100 Subject: selftests/powerpc: Move TM helpers into tm.h Move have_htm_nosc() into a new tm.h, and add a new helper, have_htm() which we'll use in the next patch. Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/tm-syscall.c | 12 +-------- tools/testing/selftests/powerpc/tm/tm.h | 34 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm.h (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/tm/tm-syscall.c b/tools/testing/selftests/powerpc/tm/tm-syscall.c index d7256b79ec4c..60560cb20e38 100644 --- a/tools/testing/selftests/powerpc/tm/tm-syscall.c +++ b/tools/testing/selftests/powerpc/tm/tm-syscall.c @@ -13,11 +13,11 @@ #include #include #include -#include #include #include #include "utils.h" +#include "tm.h" extern int getppid_tm_active(void); extern int getppid_tm_suspended(void); @@ -76,16 +76,6 @@ pid_t getppid_tm(bool suspend) exit(-1); } -static inline bool have_htm_nosc(void) -{ -#ifdef PPC_FEATURE2_HTM_NOSC - return have_hwcap2(PPC_FEATURE2_HTM_NOSC); -#else - printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n"); - return false; -#endif -} - int tm_syscall(void) { unsigned count = 0; diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h new file mode 100644 index 000000000000..24144b25772c --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm.h @@ -0,0 +1,34 @@ +/* + * Copyright 2015, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#ifndef _SELFTESTS_POWERPC_TM_TM_H +#define _SELFTESTS_POWERPC_TM_TM_H + +#include +#include + +#include "../utils.h" + +static inline bool have_htm(void) +{ +#ifdef PPC_FEATURE2_HTM + return have_hwcap2(PPC_FEATURE2_HTM); +#else + printf("PPC_FEATURE2_HTM not defined, can't check AT_HWCAP2\n"); + return false; +#endif +} + +static inline bool have_htm_nosc(void) +{ +#ifdef PPC_FEATURE2_HTM_NOSC + return have_hwcap2(PPC_FEATURE2_HTM_NOSC); +#else + printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n"); + return false; +#endif +} + +#endif /* _SELFTESTS_POWERPC_TM_TM_H */ -- cgit v1.2.3-59-g8ed1b From b319ee8445961c5f7b2fd199c0ef99c418ee2d4a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 2 Dec 2015 16:00:04 +1100 Subject: selftests/powerpc: Skip tm-resched-dscr if we don't have TM Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/Makefile | 4 ++-- tools/testing/selftests/powerpc/tm/tm-resched-dscr.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index e7b9be7947c8..63b55d01da35 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -2,9 +2,9 @@ TEST_PROGS := tm-resched-dscr tm-syscall all: $(TEST_PROGS) -$(TEST_PROGS): ../harness.c +$(TEST_PROGS): ../harness.c ../utils.c -tm-syscall: tm-syscall-asm.S ../utils.c +tm-syscall: tm-syscall-asm.S tm-syscall: CFLAGS += -mhtm -I../../../../../usr/include include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c index 42d4c8caad81..8fde93d6021f 100644 --- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c +++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c @@ -29,6 +29,7 @@ #include #include "utils.h" +#include "tm.h" #define TBEGIN ".long 0x7C00051D ;" #define TEND ".long 0x7C00055D ;" @@ -42,6 +43,8 @@ int test_body(void) { uint64_t rv, dscr1 = 1, dscr2, texasr; + SKIP_IF(!have_htm()); + printf("Check DSCR TM context switch: "); fflush(stdout); for (;;) { -- cgit v1.2.3-59-g8ed1b From 25007a69e852389985ee98235e76d740d4821c6c Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 20 Nov 2015 15:15:33 +1100 Subject: selftests/powerpc: Add TM signal return test Test the kernel's signal return code to ensure that it doesn't crash when both the transactional and suspend MSR bits are set in the signal context. Signed-off-by: Michael Neuling Tested-by: Anshuman Khandual [mpe: Skip if we don't have TM] Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/.gitignore | 1 + tools/testing/selftests/powerpc/tm/Makefile | 2 +- .../selftests/powerpc/tm/tm-signal-msr-resv.c | 74 ++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 2699635d2cd9..61c318fdace4 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore @@ -1,2 +1,3 @@ tm-resched-dscr tm-syscall +tm-signal-msr-resv diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 63b55d01da35..c6b4ca8b2812 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -1,4 +1,4 @@ -TEST_PROGS := tm-resched-dscr tm-syscall +TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv all: $(TEST_PROGS) diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c new file mode 100644 index 000000000000..d86653f282b1 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-msr-resv.c @@ -0,0 +1,74 @@ +/* + * Copyright 2015, Michael Neuling, IBM Corp. + * Licensed under GPLv2. + * + * Test the kernel's signal return code to ensure that it doesn't + * crash when both the transactional and suspend MSR bits are set in + * the signal context. + * + * For this test, we send ourselves a SIGUSR1. In the SIGUSR1 handler + * we modify the signal context to set both MSR TM S and T bits (which + * is "reserved" by the PowerISA). When we return from the signal + * handler (implicit sigreturn), the kernel should detect reserved MSR + * value and send us with a SIGSEGV. + */ + +#include +#include +#include +#include + +#include "utils.h" +#include "tm.h" + +int segv_expected = 0; + +void signal_segv(int signum) +{ + if (segv_expected && (signum == SIGSEGV)) + _exit(0); + _exit(1); +} + +void signal_usr1(int signum, siginfo_t *info, void *uc) +{ + ucontext_t *ucp = uc; + + /* Link tm checkpointed context to normal context */ + ucp->uc_link = ucp; + /* Set all TM bits so that the context is now invalid */ +#ifdef __powerpc64__ + ucp->uc_mcontext.gp_regs[PT_MSR] |= (7ULL << 32); +#else + ucp->uc_mcontext.regs->gpr[PT_MSR] |= (7ULL); +#endif + /* Should segv on return becuase of invalid context */ + segv_expected = 1; +} + +int tm_signal_msr_resv() +{ + struct sigaction act; + + SKIP_IF(!have_htm()); + + act.sa_sigaction = signal_usr1; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + if (sigaction(SIGUSR1, &act, NULL) < 0) { + perror("sigaction sigusr1"); + exit(1); + } + if (signal(SIGSEGV, signal_segv) == SIG_ERR) + exit(1); + + raise(SIGUSR1); + + /* We shouldn't get here as we exit in the segv handler */ + return 1; +} + +int main(void) +{ + return test_harness(tm_signal_msr_resv, "tm_signal_msr_resv"); +} -- cgit v1.2.3-59-g8ed1b From a26f415bf71640f0141e5e946384444675206b6a Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Fri, 20 Nov 2015 15:15:34 +1100 Subject: selftests/powerpc: Add TM signal with invalid stack test Test the kernels signal generation code to ensure it can handle an invalid stack pointer when transactional. Signed-off-by: Michael Neuling Tested-by: Anshuman Khandual [mpe: Skip if we don't have TM] Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/.gitignore | 1 + tools/testing/selftests/powerpc/tm/Makefile | 2 +- .../testing/selftests/powerpc/tm/tm-signal-stack.c | 76 ++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm-signal-stack.c (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index 61c318fdace4..e6668217ccd0 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore @@ -1,3 +1,4 @@ tm-resched-dscr tm-syscall tm-signal-msr-resv +tm-signal-stack diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index c6b4ca8b2812..e7ceff809fa0 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -1,4 +1,4 @@ -TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv +TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack all: $(TEST_PROGS) diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-stack.c b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c new file mode 100644 index 000000000000..e44a238c1d77 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-stack.c @@ -0,0 +1,76 @@ +/* + * Copyright 2015, Michael Neuling, IBM Corp. + * Licensed under GPLv2. + * + * Test the kernel's signal delievery code to ensure that we don't + * trelaim twice in the kernel signal delivery code. This can happen + * if we trigger a signal when in a transaction and the stack pointer + * is bogus. + * + * This test case registers a SEGV handler, sets the stack pointer + * (r1) to NULL, starts a transaction and then generates a SEGV. The + * SEGV should be handled but we exit here as the stack pointer is + * invalid and hance we can't sigreturn. We only need to check that + * this flow doesn't crash the kernel. + */ + +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "tm.h" + +void signal_segv(int signum) +{ + /* This should never actually run since stack is foobar */ + exit(1); +} + +int tm_signal_stack() +{ + int pid; + + SKIP_IF(!have_htm()); + + pid = fork(); + if (pid < 0) + exit(1); + + if (pid) { /* Parent */ + /* + * It's likely the whole machine will crash here so if + * the child ever exits, we are good. + */ + wait(NULL); + return 0; + } + + /* + * The flow here is: + * 1) register a signal handler (so signal delievery occurs) + * 2) make stack pointer (r1) = NULL + * 3) start transaction + * 4) cause segv + */ + if (signal(SIGSEGV, signal_segv) == SIG_ERR) + exit(1); + asm volatile("li 1, 0 ;" /* stack ptr == NULL */ + "1:" + ".long 0x7C00051D ;" /* tbegin */ + "beq 1b ;" /* retry forever */ + ".long 0x7C0005DD ; ;" /* tsuspend */ + "ld 2, 0(1) ;" /* trigger segv" */ + : : : "memory"); + + /* This should never get here due to above segv */ + return 1; +} + +int main(void) +{ + return test_harness(tm_signal_stack, "tm_signal_stack"); +} -- cgit v1.2.3-59-g8ed1b From 5f337e3e5b04b32793fd51adab438d46df99c933 Mon Sep 17 00:00:00 2001 From: Rashmica Gupta Date: Thu, 10 Dec 2015 20:49:33 +1100 Subject: selftests/powerpc: Add test to check if VSRs are corrupted When a transaction is aborted, VSR values should rollback to the checkpointed values before the transaction began. VSRs used elsewhere in the kernel during a transaction, or while the transaction is suspended should not affect the checkpointed values. Prior to the bug fix in commit d31626f70b61 ("powerpc: Don't corrupt transactional state when using FP/VMX in kernel") when VMX was requested by the kernel the .vr_state (which held the checkpointed state of VSRs before the transaction) was overwritten with the current state from outside the transation. Thus if the transaction did not complete, the VSR values would be "rolled back" to potentially incorrect values. Signed-off-by: Rashmica Gupta Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/.gitignore | 1 + tools/testing/selftests/powerpc/tm/Makefile | 2 +- tools/testing/selftests/powerpc/tm/tm-vmxcopy.c | 103 ++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm-vmxcopy.c (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/tm/.gitignore b/tools/testing/selftests/powerpc/tm/.gitignore index e6668217ccd0..7d0f14b8cb2e 100644 --- a/tools/testing/selftests/powerpc/tm/.gitignore +++ b/tools/testing/selftests/powerpc/tm/.gitignore @@ -2,3 +2,4 @@ tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack +tm-vmxcopy diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index e7ceff809fa0..737f72c964e6 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -1,4 +1,4 @@ -TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack +TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack tm-vmxcopy all: $(TEST_PROGS) diff --git a/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c new file mode 100644 index 000000000000..0274de7b11f3 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-vmxcopy.c @@ -0,0 +1,103 @@ +/* + * Copyright 2015, Michael Neuling, IBM Corp. + * Licensed under GPLv2. + * + * Original: Michael Neuling 4/12/2013 + * Edited: Rashmica Gupta 4/12/2015 + * + * See if the altivec state is leaked out of an aborted transaction due to + * kernel vmx copy loops. + * + * When the transaction aborts, VSR values should rollback to the values + * they held before the transaction commenced. Using VSRs while transaction + * is suspended should not affect the checkpointed values. + * + * (1) write A to a VSR + * (2) start transaction + * (3) suspend transaction + * (4) change the VSR to B + * (5) trigger kernel vmx copy loop + * (6) abort transaction + * (7) check that the VSR value is A + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "tm.h" +#include "utils.h" + +int test_vmxcopy() +{ + long double vecin = 1.3; + long double vecout; + unsigned long pgsize = getpagesize(); + int i; + int fd; + int size = pgsize*16; + char tmpfile[] = "/tmp/page_faultXXXXXX"; + char buf[pgsize]; + char *a; + uint64_t aborted = 0; + + SKIP_IF(!have_htm()); + + fd = mkstemp(tmpfile); + assert(fd >= 0); + + memset(buf, 0, pgsize); + for (i = 0; i < size; i += pgsize) + assert(write(fd, buf, pgsize) == pgsize); + + unlink(tmpfile); + + a = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + assert(a != MAP_FAILED); + + asm __volatile__( + "lxvd2x 40,0,%[vecinptr];" /* set 40 to initial value*/ + "tbegin.;" + "beq 3f;" + "tsuspend.;" + "xxlxor 40,40,40;" /* set 40 to 0 */ + "std 5, 0(%[map]);" /* cause kernel vmx copy page */ + "tabort. 0;" + "tresume.;" + "tend.;" + "li %[res], 0;" + "b 5f;" + + /* Abort handler */ + "3:;" + "li %[res], 1;" + + "5:;" + "stxvd2x 40,0,%[vecoutptr];" + : [res]"=r"(aborted) + : [vecinptr]"r"(&vecin), + [vecoutptr]"r"(&vecout), + [map]"r"(a) + : "memory", "r0", "r3", "r4", "r5", "r6", "r7"); + + if (aborted && (vecin != vecout)){ + printf("FAILED: vector state leaked on abort %f != %f\n", + (double)vecin, (double)vecout); + return 1; + } + + munmap(a, size); + + close(fd); + + return 0; +} + +int main(void) +{ + return test_harness(test_vmxcopy, "tm_vmxcopy"); +} -- cgit v1.2.3-59-g8ed1b From d1301afd71bd38b1610b391e50debf766faa84be Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 16 Dec 2015 18:59:31 +1100 Subject: selftests/powerpc: Move pick_online_cpu() up into utils.c We want to use this in another test, so make it available at the top of the powerpc selftests tree. Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/pmu/Makefile | 2 +- tools/testing/selftests/powerpc/pmu/lib.c | 26 ------------------------- tools/testing/selftests/powerpc/pmu/lib.h | 1 - tools/testing/selftests/powerpc/utils.c | 29 ++++++++++++++++++++++++++++ tools/testing/selftests/powerpc/utils.h | 1 + 5 files changed, 31 insertions(+), 28 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile index 50326cbb372d..ac41a7177f2e 100644 --- a/tools/testing/selftests/powerpc/pmu/Makefile +++ b/tools/testing/selftests/powerpc/pmu/Makefile @@ -2,7 +2,7 @@ noarg: $(MAKE) -C ../ TEST_PROGS := count_instructions l3_bank_test per_event_excludes -EXTRA_SOURCES := ../harness.c event.c lib.c +EXTRA_SOURCES := ../harness.c event.c lib.c ../utils.c all: $(TEST_PROGS) ebb diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c index a07104c2afe6..a361ad3334ce 100644 --- a/tools/testing/selftests/powerpc/pmu/lib.c +++ b/tools/testing/selftests/powerpc/pmu/lib.c @@ -15,32 +15,6 @@ #include "lib.h" -int pick_online_cpu(void) -{ - cpu_set_t mask; - int cpu; - - CPU_ZERO(&mask); - - if (sched_getaffinity(0, sizeof(mask), &mask)) { - perror("sched_getaffinity"); - return -1; - } - - /* We prefer a primary thread, but skip 0 */ - for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8) - if (CPU_ISSET(cpu, &mask)) - return cpu; - - /* Search for anything, but in reverse */ - for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--) - if (CPU_ISSET(cpu, &mask)) - return cpu; - - printf("No cpus in affinity mask?!\n"); - return -1; -} - int bind_to_cpu(int cpu) { cpu_set_t mask; diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h index ca5d72ae3be6..0213af4ff332 100644 --- a/tools/testing/selftests/powerpc/pmu/lib.h +++ b/tools/testing/selftests/powerpc/pmu/lib.h @@ -19,7 +19,6 @@ union pipe { int fds[2]; }; -extern int pick_online_cpu(void); extern int bind_to_cpu(int cpu); extern int kill_child_and_wait(pid_t child_pid); extern int wait_for_child(pid_t child_pid); diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c index 536113add380..dcf74184bfd0 100644 --- a/tools/testing/selftests/powerpc/utils.c +++ b/tools/testing/selftests/powerpc/utils.c @@ -3,10 +3,13 @@ * Licensed under GPLv2. */ +#define _GNU_SOURCE /* For CPU_ZERO etc. */ + #include #include #include #include +#include #include #include #include @@ -56,3 +59,29 @@ out: close(fd); return result; } + +int pick_online_cpu(void) +{ + cpu_set_t mask; + int cpu; + + CPU_ZERO(&mask); + + if (sched_getaffinity(0, sizeof(mask), &mask)) { + perror("sched_getaffinity"); + return -1; + } + + /* We prefer a primary thread, but skip 0 */ + for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8) + if (CPU_ISSET(cpu, &mask)) + return cpu; + + /* Search for anything, but in reverse */ + for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--) + if (CPU_ISSET(cpu, &mask)) + return cpu; + + printf("No cpus in affinity mask?!\n"); + return -1; +} diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h index fbf2bf530e50..175ac6ad10dd 100644 --- a/tools/testing/selftests/powerpc/utils.h +++ b/tools/testing/selftests/powerpc/utils.h @@ -22,6 +22,7 @@ typedef uint8_t u8; int test_harness(int (test_function)(void), char *name); extern void *get_auxv_entry(int type); +int pick_online_cpu(void); static inline bool have_hwcap2(unsigned long ftr2) { -- cgit v1.2.3-59-g8ed1b From 00b7ec5c9cf338902faea2e40801573a384e45be Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 2 Dec 2015 20:44:09 +1100 Subject: selftests/powerpc: Import Anton's context_switch2 benchmark This gets referred to a lot in commit messages, so let's pull it into the selftests. Almost vanilla from: http://ozlabs.org/~anton/junkcode/context_switch2.c Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Acked-by: Anton Blanchard --- .../selftests/powerpc/benchmarks/.gitignore | 1 + .../testing/selftests/powerpc/benchmarks/Makefile | 4 +- .../selftests/powerpc/benchmarks/context_switch.c | 452 +++++++++++++++++++++ 3 files changed, 456 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/benchmarks/context_switch.c (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/benchmarks/.gitignore b/tools/testing/selftests/powerpc/benchmarks/.gitignore index b4709ea588c1..6fa673316ac2 100644 --- a/tools/testing/selftests/powerpc/benchmarks/.gitignore +++ b/tools/testing/selftests/powerpc/benchmarks/.gitignore @@ -1 +1,2 @@ gettimeofday +context_switch diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile index 5fa48702070d..8cb7415c55aa 100644 --- a/tools/testing/selftests/powerpc/benchmarks/Makefile +++ b/tools/testing/selftests/powerpc/benchmarks/Makefile @@ -1,4 +1,4 @@ -TEST_PROGS := gettimeofday +TEST_PROGS := gettimeofday context_switch CFLAGS += -O2 @@ -6,6 +6,8 @@ all: $(TEST_PROGS) $(TEST_PROGS): ../harness.c +context_switch: LDLIBS += -lpthread + include ../../lib.mk clean: diff --git a/tools/testing/selftests/powerpc/benchmarks/context_switch.c b/tools/testing/selftests/powerpc/benchmarks/context_switch.c new file mode 100644 index 000000000000..ed21a83a0f99 --- /dev/null +++ b/tools/testing/selftests/powerpc/benchmarks/context_switch.c @@ -0,0 +1,452 @@ +/* + * Context switch microbenchmark. + * + * Copyright (C) 2015 Anton Blanchard , IBM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int timeout = INT_MAX; + +static int touch_vdso; +struct timeval tv; + +static int touch_fp; +double fp; + +static int touch_vector; +typedef int v4si __attribute__ ((vector_size (16))); +v4si a, b, c; + +#ifdef __powerpc__ +static int touch_altivec; + +static void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void) +{ + c = a + b; +} +#endif + +static void touch(void) +{ + if (touch_vdso) + gettimeofday(&tv, NULL); + + if (touch_fp) + fp += 0.1; + +#ifdef __powerpc__ + if (touch_altivec) + altivec_touch_fn(); +#endif + + if (touch_vector) + c = a + b; + + asm volatile("# %0 %1 %2": : "r"(&tv), "r"(&fp), "r"(&c)); +} + +static void start_thread_on(void *(*fn)(void *), void *arg, unsigned long cpu) +{ + pthread_t tid; + cpu_set_t cpuset; + pthread_attr_t attr; + + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + + pthread_attr_init(&attr); + + if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset)) { + perror("pthread_attr_setaffinity_np"); + exit(1); + } + + if (pthread_create(&tid, &attr, fn, arg)) { + perror("pthread_create"); + exit(1); + } +} + +static void start_process_on(void *(*fn)(void *), void *arg, unsigned long cpu) +{ + int pid; + cpu_set_t cpuset; + + pid = fork(); + if (pid == -1) { + perror("fork"); + exit(1); + } + + if (pid) + return; + + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + + if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) { + perror("sched_setaffinity"); + exit(1); + } + + fn(arg); + + exit(0); +} + +static unsigned long iterations; +static unsigned long iterations_prev; + +static void sigalrm_handler(int junk) +{ + unsigned long i = iterations; + + printf("%ld\n", i - iterations_prev); + iterations_prev = i; + + if (--timeout == 0) + kill(0, SIGUSR1); + + alarm(1); +} + +static void sigusr1_handler(int junk) +{ + exit(0); +} + +struct actions { + void (*setup)(int, int); + void *(*thread1)(void *); + void *(*thread2)(void *); +}; + +#define READ 0 +#define WRITE 1 + +static int pipe_fd1[2]; +static int pipe_fd2[2]; + +static void pipe_setup(int cpu1, int cpu2) +{ + if (pipe(pipe_fd1) || pipe(pipe_fd2)) + exit(1); +} + +static void *pipe_thread1(void *arg) +{ + signal(SIGALRM, sigalrm_handler); + alarm(1); + + while (1) { + assert(read(pipe_fd1[READ], &c, 1) == 1); + touch(); + + assert(write(pipe_fd2[WRITE], &c, 1) == 1); + touch(); + + iterations += 2; + } + + return NULL; +} + +static void *pipe_thread2(void *arg) +{ + while (1) { + assert(write(pipe_fd1[WRITE], &c, 1) == 1); + touch(); + + assert(read(pipe_fd2[READ], &c, 1) == 1); + touch(); + } + + return NULL; +} + +static struct actions pipe_actions = { + .setup = pipe_setup, + .thread1 = pipe_thread1, + .thread2 = pipe_thread2, +}; + +static void yield_setup(int cpu1, int cpu2) +{ + if (cpu1 != cpu2) { + fprintf(stderr, "Both threads must be on the same CPU for yield test\n"); + exit(1); + } +} + +static void *yield_thread1(void *arg) +{ + signal(SIGALRM, sigalrm_handler); + alarm(1); + + while (1) { + sched_yield(); + touch(); + + iterations += 2; + } + + return NULL; +} + +static void *yield_thread2(void *arg) +{ + while (1) { + sched_yield(); + touch(); + } + + return NULL; +} + +static struct actions yield_actions = { + .setup = yield_setup, + .thread1 = yield_thread1, + .thread2 = yield_thread2, +}; + +static long sys_futex(void *addr1, int op, int val1, struct timespec *timeout, + void *addr2, int val3) +{ + return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3); +} + +static unsigned long cmpxchg(unsigned long *p, unsigned long expected, + unsigned long desired) +{ + unsigned long exp = expected; + + __atomic_compare_exchange_n(p, &exp, desired, 0, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return exp; +} + +static unsigned long xchg(unsigned long *p, unsigned long val) +{ + return __atomic_exchange_n(p, val, __ATOMIC_SEQ_CST); +} + +static int mutex_lock(unsigned long *m) +{ + int c; + + c = cmpxchg(m, 0, 1); + if (!c) + return 0; + + if (c == 1) + c = xchg(m, 2); + + while (c) { + sys_futex(m, FUTEX_WAIT, 2, NULL, NULL, 0); + c = xchg(m, 2); + } + + return 0; +} + +static int mutex_unlock(unsigned long *m) +{ + if (*m == 2) + *m = 0; + else if (xchg(m, 0) == 1) + return 0; + + sys_futex(m, FUTEX_WAKE, 1, NULL, NULL, 0); + + return 0; +} + +static unsigned long *m1, *m2; + +static void futex_setup(int cpu1, int cpu2) +{ + int shmid; + void *shmaddr; + + shmid = shmget(IPC_PRIVATE, getpagesize(), SHM_R | SHM_W); + if (shmid < 0) { + perror("shmget"); + exit(1); + } + + shmaddr = shmat(shmid, NULL, 0); + if (shmaddr == (char *)-1) { + perror("shmat"); + shmctl(shmid, IPC_RMID, NULL); + exit(1); + } + + shmctl(shmid, IPC_RMID, NULL); + + m1 = shmaddr; + m2 = shmaddr + sizeof(*m1); + + *m1 = 0; + *m2 = 0; + + mutex_lock(m1); + mutex_lock(m2); +} + +static void *futex_thread1(void *arg) +{ + signal(SIGALRM, sigalrm_handler); + alarm(1); + + while (1) { + mutex_lock(m2); + mutex_unlock(m1); + + iterations += 2; + } + + return NULL; +} + +static void *futex_thread2(void *arg) +{ + while (1) { + mutex_unlock(m2); + mutex_lock(m1); + } + + return NULL; +} + +static struct actions futex_actions = { + .setup = futex_setup, + .thread1 = futex_thread1, + .thread2 = futex_thread2, +}; + +static int processes; + +static struct option options[] = { + { "test", required_argument, 0, 't' }, + { "process", no_argument, &processes, 1 }, + { "timeout", required_argument, 0, 's' }, + { "vdso", no_argument, &touch_vdso, 1 }, + { "fp", no_argument, &touch_fp, 1 }, +#ifdef __powerpc__ + { "altivec", no_argument, &touch_altivec, 1 }, +#endif + { "vector", no_argument, &touch_vector, 1 }, + { 0, }, +}; + +static void usage(void) +{ + fprintf(stderr, "Usage: context_switch2 CPU1 CPU2\n\n"); + fprintf(stderr, "\t\t--test=X\tpipe, futex or yield\n"); + fprintf(stderr, "\t\t--process\tUse processes (default threads)\n"); + fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run\n"); + fprintf(stderr, "\t\t--vdso\t\ttouch VDSO\n"); + fprintf(stderr, "\t\t--fp\t\ttouch FP\n"); +#ifdef __powerpc__ + fprintf(stderr, "\t\t--altivec\ttouch altivec\n"); +#endif + fprintf(stderr, "\t\t--vector\ttouch vector\n"); +} + +int main(int argc, char *argv[]) +{ + signed char c; + struct actions *actions = &pipe_actions; + int cpu1; + int cpu2; + static void (*start_fn)(void *(*fn)(void *), void *arg, unsigned long cpu); + + while (1) { + int option_index = 0; + + c = getopt_long(argc, argv, "", options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 0: + if (options[option_index].flag != 0) + break; + + usage(); + exit(1); + break; + + case 't': + if (!strcmp(optarg, "pipe")) { + actions = &pipe_actions; + } else if (!strcmp(optarg, "yield")) { + actions = &yield_actions; + } else if (!strcmp(optarg, "futex")) { + actions = &futex_actions; + } else { + usage(); + exit(1); + } + break; + + case 's': + timeout = atoi(optarg); + break; + + default: + usage(); + exit(1); + } + } + + if (processes) + start_fn = start_process_on; + else + start_fn = start_thread_on; + + if (((argc - optind) != 2)) { + usage(); + exit(1); + } + + /* Create a new process group so we can signal everyone for exit */ + setpgid(getpid(), getpid()); + + signal(SIGUSR1, sigusr1_handler); + + cpu1 = atoi(argv[optind++]); + cpu2 = atoi(argv[optind++]); + + actions->setup(cpu1, cpu2); + + start_fn(actions->thread1, NULL, cpu1); + start_fn(actions->thread2, NULL, cpu2); + + while (1) + sleep(3600); + + return 0; +} -- cgit v1.2.3-59-g8ed1b From ea0c321784565c681507e02acf900deaa1e9e952 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 2 Dec 2015 20:44:10 +1100 Subject: selftests/powerpc: Make context_switch do something with no args For ease of use make the context_switch test do something useful when called with no arguments. Default to a 30 second run, using threads, doing yield, and use any online cpu. Make it print out what it's doing to avoid confusion. Signed-off-by: Michael Ellerman Acked-by: Anton Blanchard --- .../testing/selftests/powerpc/benchmarks/Makefile | 1 + .../selftests/powerpc/benchmarks/context_switch.c | 32 ++++++++++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile index 8cb7415c55aa..912445ff7ce7 100644 --- a/tools/testing/selftests/powerpc/benchmarks/Makefile +++ b/tools/testing/selftests/powerpc/benchmarks/Makefile @@ -6,6 +6,7 @@ all: $(TEST_PROGS) $(TEST_PROGS): ../harness.c +context_switch: ../utils.c context_switch: LDLIBS += -lpthread include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/benchmarks/context_switch.c b/tools/testing/selftests/powerpc/benchmarks/context_switch.c index ed21a83a0f99..d8b6d10f36a6 100644 --- a/tools/testing/selftests/powerpc/benchmarks/context_switch.c +++ b/tools/testing/selftests/powerpc/benchmarks/context_switch.c @@ -26,7 +26,9 @@ #include #include -static unsigned int timeout = INT_MAX; +#include "../utils.h" + +static unsigned int timeout = 30; static int touch_vdso; struct timeval tv; @@ -363,9 +365,9 @@ static struct option options[] = { static void usage(void) { fprintf(stderr, "Usage: context_switch2 CPU1 CPU2\n\n"); - fprintf(stderr, "\t\t--test=X\tpipe, futex or yield\n"); + fprintf(stderr, "\t\t--test=X\tpipe, futex or yield (default)\n"); fprintf(stderr, "\t\t--process\tUse processes (default threads)\n"); - fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run\n"); + fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n"); fprintf(stderr, "\t\t--vdso\t\ttouch VDSO\n"); fprintf(stderr, "\t\t--fp\t\ttouch FP\n"); #ifdef __powerpc__ @@ -377,7 +379,7 @@ static void usage(void) int main(int argc, char *argv[]) { signed char c; - struct actions *actions = &pipe_actions; + struct actions *actions = &yield_actions; int cpu1; int cpu2; static void (*start_fn)(void *(*fn)(void *), void *arg, unsigned long cpu); @@ -428,18 +430,30 @@ int main(int argc, char *argv[]) start_fn = start_thread_on; if (((argc - optind) != 2)) { - usage(); - exit(1); + cpu1 = cpu2 = pick_online_cpu(); + } else { + cpu1 = atoi(argv[optind++]); + cpu2 = atoi(argv[optind++]); } + printf("Using %s with ", processes ? "processes" : "threads"); + + if (actions == &pipe_actions) + printf("pipe"); + else if (actions == &yield_actions) + printf("yield"); + else + printf("futex"); + + printf(" on cpus %d/%d touching FP:%s altivec:%s vector:%s vdso:%s\n", + cpu1, cpu2, touch_fp ? "yes" : "no", touch_altivec ? "yes" : "no", + touch_vector ? "yes" : "no", touch_vdso ? "yes" : "no"); + /* Create a new process group so we can signal everyone for exit */ setpgid(getpid(), getpid()); signal(SIGUSR1, sigusr1_handler); - cpu1 = atoi(argv[optind++]); - cpu2 = atoi(argv[optind++]); - actions->setup(cpu1, cpu2); start_fn(actions->thread1, NULL, cpu1); -- cgit v1.2.3-59-g8ed1b From 51c21e72eb99d1136614135d633baae269893778 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 2 Dec 2015 20:44:11 +1100 Subject: selftests/powerpc: Make context_switch touch FP/altivec/vector by default Simply because it touches more code paths that way, and therefore tests more things. Signed-off-by: Michael Ellerman Acked-by: Anton Blanchard --- tools/testing/selftests/powerpc/benchmarks/context_switch.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/benchmarks/context_switch.c b/tools/testing/selftests/powerpc/benchmarks/context_switch.c index d8b6d10f36a6..7b785941adec 100644 --- a/tools/testing/selftests/powerpc/benchmarks/context_switch.c +++ b/tools/testing/selftests/powerpc/benchmarks/context_switch.c @@ -33,15 +33,15 @@ static unsigned int timeout = 30; static int touch_vdso; struct timeval tv; -static int touch_fp; +static int touch_fp = 1; double fp; -static int touch_vector; +static int touch_vector = 1; typedef int v4si __attribute__ ((vector_size (16))); v4si a, b, c; #ifdef __powerpc__ -static int touch_altivec; +static int touch_altivec = 1; static void __attribute__((__target__("no-vsx"))) altivec_touch_fn(void) { @@ -354,11 +354,11 @@ static struct option options[] = { { "process", no_argument, &processes, 1 }, { "timeout", required_argument, 0, 's' }, { "vdso", no_argument, &touch_vdso, 1 }, - { "fp", no_argument, &touch_fp, 1 }, + { "no-fp", no_argument, &touch_fp, 0 }, #ifdef __powerpc__ - { "altivec", no_argument, &touch_altivec, 1 }, + { "no-altivec", no_argument, &touch_altivec, 0 }, #endif - { "vector", no_argument, &touch_vector, 1 }, + { "no-vector", no_argument, &touch_vector, 0 }, { 0, }, }; -- cgit v1.2.3-59-g8ed1b From a8da474ec18f4c4c39f83202d64d73a23b755c1d Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Mon, 7 Dec 2015 10:50:51 +1100 Subject: selftests/powerpc: Add script to test HMI functionality HMIs (Hypervisor Management|Maintenance Interrupts) are a class of interrupt on POWER systems. HMI support has traditionally been exceptionally difficult to test, however Skiboot ships a tool that, with the correct magic numbers, will inject them. This, therefore, is a first pass at a script to inject HMIs and monitor Linux's response. It injects an HMI on each core on every chip in turn It then watches dmesg to see if it's acknowledged by Linux. On a Tuletta, I observed that we see 8 (or sometimes 9 or more) events per injection, regardless of SMT setting, so we wait for 8 before progressing. It sits in a new scripts/ directory in selftests/powerpc, because it's not designed to be run as part of the regular make selftests process. In particular, it is quite possibly going to end up garding lots of your CPUs, so it should only be run if you know how to undo that. CC: Mahesh J Salgaonkar Signed-off-by: Daniel Axtens Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/scripts/hmi.sh | 89 ++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100755 tools/testing/selftests/powerpc/scripts/hmi.sh (limited to 'tools') diff --git a/tools/testing/selftests/powerpc/scripts/hmi.sh b/tools/testing/selftests/powerpc/scripts/hmi.sh new file mode 100755 index 000000000000..83fb253ae3bd --- /dev/null +++ b/tools/testing/selftests/powerpc/scripts/hmi.sh @@ -0,0 +1,89 @@ +#!/bin/sh +# +# Copyright 2015, Daniel Axtens, IBM Corporation +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + + +# do we have ./getscom, ./putscom? +if [ -x ./getscom ] && [ -x ./putscom ]; then + GETSCOM=./getscom + PUTSCOM=./putscom +elif which getscom > /dev/null; then + GETSCOM=$(which getscom) + PUTSCOM=$(which putscom) +else + cat < /dev/null; then + echo "Error injecting. Aborting!" + exit 1 + fi + + # now we want to wait for all the HMIs to be processed + # we expect one per thread on the core + i=0; + new_hmis=$(COUNT_HMIS) + while [ $new_hmis -lt $((old_hmis + expected_hmis)) ] && [ $i -lt 12 ]; do + echo "Seen $((new_hmis - old_hmis)) HMI(s) out of $expected_hmis expected, sleeping" + sleep 5; + i=$((i + 1)) + new_hmis=$(COUNT_HMIS) + done + if [ $i = 12 ]; then + echo "Haven't seen expected $expected_hmis recoveries after 1 min. Aborting." + exit 1 + fi + echo "Processed $expected_hmis events; presumed success. Check dmesg." + echo "" +done -- cgit v1.2.3-59-g8ed1b