selftests/powerpc: Add test to check if VSRs are corrupted
authorRashmica Gupta <rashmicy@gmail.com>
Thu, 10 Dec 2015 09:49:33 +0000 (20:49 +1100)
committerMichael Ellerman <mpe@ellerman.id.au>
Mon, 14 Dec 2015 09:41:50 +0000 (20:41 +1100)
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 <rashmicy@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
tools/testing/selftests/powerpc/tm/.gitignore
tools/testing/selftests/powerpc/tm/Makefile
tools/testing/selftests/powerpc/tm/tm-vmxcopy.c [new file with mode: 0644]

index e6668217ccd0749e965ab7f1a5bb977c6e764e98..7d0f14b8cb2e465657e509e6e7875627859d348b 100644 (file)
@@ -2,3 +2,4 @@ tm-resched-dscr
 tm-syscall
 tm-signal-msr-resv
 tm-signal-stack
+tm-vmxcopy
index e7ceff809fa0f3e5357dbcb3a0601bdc1b22c94b..737f72c964e65c22ea2923dfb6843f522074e5bc 100644 (file)
@@ -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 (file)
index 0000000..0274de7
--- /dev/null
@@ -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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <assert.h>
+
+#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");
+}