On Thu, 2017-06-29 at 20:44 -0400, Gustavo Romero wrote: > Add a test to check if FP/VSX registers are sane (restored correctly) after > a VSX unavailable exception is caught in the middle of a transaction. > > Signed-off-by: Gustavo Romero <grom...@linux.vnet.ibm.com> > Signed-off-by: Breno Leitao <lei...@debian.org>
Looks good, its a nice test for a very difficult (difficult on purpose but still possible by accident!) to hit bug. Reviewed-by: Cyril Bur <cyril...@gmail.com> > --- > tools/testing/selftests/powerpc/tm/Makefile | 3 +- > .../testing/selftests/powerpc/tm/tm-vsx-unavail.c | 144 > +++++++++++++++++++++ > 2 files changed, 146 insertions(+), 1 deletion(-) > create mode 100644 tools/testing/selftests/powerpc/tm/tm-vsx-unavail.c > > diff --git a/tools/testing/selftests/powerpc/tm/Makefile > b/tools/testing/selftests/powerpc/tm/Makefile > index 958c11c..d0ffbb8 100644 > --- a/tools/testing/selftests/powerpc/tm/Makefile > +++ b/tools/testing/selftests/powerpc/tm/Makefile > @@ -2,7 +2,7 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr > tm-signal-context-chk-fpu > tm-signal-context-chk-vmx tm-signal-context-chk-vsx > > TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv > tm-signal-stack \ > - tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail \ > + tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail tm-vsx-unavail \ > $(SIGNAL_CONTEXT_CHK_TESTS) > > include ../../lib.mk > @@ -15,6 +15,7 @@ $(OUTPUT)/tm-syscall: tm-syscall-asm.S > $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include > $(OUTPUT)/tm-tmspr: CFLAGS += -pthread > $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 > +$(OUTPUT)/tm-vsx-unavail: CFLAGS += -pthread -m64 > > SIGNAL_CONTEXT_CHK_TESTS := $(patsubst > %,$(OUTPUT)/%,$(SIGNAL_CONTEXT_CHK_TESTS)) > $(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S > diff --git a/tools/testing/selftests/powerpc/tm/tm-vsx-unavail.c > b/tools/testing/selftests/powerpc/tm/tm-vsx-unavail.c > new file mode 100644 > index 0000000..7ff933a > --- /dev/null > +++ b/tools/testing/selftests/powerpc/tm/tm-vsx-unavail.c > @@ -0,0 +1,144 @@ > +/* > + * Copyright 2017, Gustavo Romero and Breno Leitao, IBM Corp. > + * Licensed under GPLv2. > + * > + * Force VSX unavailable exception during a transaction and see > + * if it corrupts the checkpointed FP registers state after the abort. > + */ > + > +#define _GNU_SOURCE > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <unistd.h> > +#include <inttypes.h> > +#include <pthread.h> > +#include <sched.h> > + > +#include "tm.h" > +#include "utils.h" > + > +int passed; > + > +void *ping(void *not_used) > +{ > + asm goto( > + // r3 = 0x5555555555555555 > + "lis 3, 0x5555 ;" > + "ori 3, 3, 0x5555 ;" > + "sldi 3, 3, 32 ;" > + "oris 3, 3, 0x5555 ;" > + "ori 3, 3, 0x5555 ;" > + > + //r4 = 0xFFFFFFFFFFFFFFFF > + "lis 4, 0xFFFF ;" > + "ori 4, 4, 0xFFFF ;" > + "sldi 4, 4, 32 ;" > + "oris 4, 4, 0xFFFF ;" > + "ori 4, 4, 0xFFFF ;" > + > + // vs33 and vs34 will just be used to construct vs0 from r3 and > + // r4. Both won't be used in any other place after that. > + "mtvsrd 33, 3 ;" > + "mtvsrd 34, 4 ;" > + > + // vs0 = (r3 || r4) = 0x5555555555555555FFFFFFFFFFFFFFFF > + "xxmrghd 0, 33, 34 ;" > + > + > + // Wait ~8s so we have a sufficient amount of context > + // switches so load_fp and load_vec overflow and MSR.FP, MSR.VEC > + // and MSR.VSX are disabled. > + " lis 7, 0x1 ;" > + " ori 7, 7, 0xBFFE ;" > + " sldi 7, 7, 15 ;" > + "1: addi 7, 7, -1 ;" > + " cmpdi 7, 0 ;" > + " bne 1b ;" > + > + // Any floating-point instruction in here. > + // N.B. 'fmr' is *not touching* any previously set register, > + // i.e. it's not touching vs0. > + "fmr 10, 10 ;" > + > + // vs0 is *still* 0x5555555555555555FFFFFFFFFFFFFFFF, right? > + // Get in a transaction and cause a VSX unavailable exception. > + "2: tbegin. ;" // Begin HTM > + " beq 3f ;" // Failure handler > + " xxmrghd 10, 10, 10 ;" // VSX unavailable in TM > + " tend. ;" // End HTM > + "3: nop ;" // Fall through to code below > + > + // Immediately after a transaction failure we save vs0 to two > + // general purpose registers to check its value. We need to have > + // the same value as before we entered in transactional state. > + > + // vs0 should be *still* 0x5555555555555555FFFFFFFFFFFFFFFF > + > + // Save high half - MSB (64bit). > + "mfvsrd 5, 0 ;" > + > + // Save low half - LSB (64bit). > + // We mess with vs3, but it's not important. > + "xxsldwi 3, 0, 0, 2 ;" > + "mfvsrd 6, 3 ;" > + > + // N.B. r3 and r4 never changed since they were used to > + // construct the initial vs0 value, hence we can use them to do > + // the comparison. r3 and r4 will be destroy but it's ok. > + "cmpd 3, 5 ;" // compare r3 to r5 > + "bne %[value_mismatch] ;" > + "cmpd 4, 6 ;" // compare r4 to r6 > + "bne %[value_mismatch] ;" > + "b %[value_ok] ;" > + : > + : > + : "r3", "r4", "vs33", "vs34", "vs0", > + "vs10", "fr10", "r7", "r5", "r6", "vs3" > + : value_mismatch, value_ok > + ); > +value_mismatch: > + passed = 0; > + return NULL; > +value_ok: > + passed = 1; > + return NULL; > +} > + > +void *pong(void *not_used) > +{ > + while (1) > + sched_yield(); // will be classed as interactive-like thread > +} > + > +int tm_vsx_unavail_test(void) > +{ > + pthread_t t0, t1; > + pthread_attr_t attr; > + cpu_set_t cpuset; > + > + // Set only CPU 0 in the mask. Both threads will be bound to cpu 0 > + CPU_ZERO(&cpuset); > + CPU_SET(0, &cpuset); > + > + // Init pthread attribute > + pthread_attr_init(&attr); > + > + // Set CPU 0 mask into the pthread attribute > + pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); > + > + // 'pong' thread used to induce context switches on 'ping' thread > + pthread_create(&t1, &attr /* bound to cpu 0 */, pong, NULL); > + > + printf("Checking if FP/VSX is sane after a VSX exception in TM...\n"); > + > + pthread_create(&t0, &attr /* bound to cpu 0 as well */, ping, NULL); > + pthread_join(t0, NULL); > + > + return passed ? EXIT_SUCCESS : EXIT_FAILURE; > +} > + > +int main(int argc, char **argv) > +{ > + return test_harness(tm_vsx_unavail_test, "tm_vsx_unavail_test"); > +}