diff mbox

[2/2] powerpc/tm: test for regs sanity in VSX exception

Message ID 1498783490-23675-2-git-send-email-gromero@linux.vnet.ibm.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Gustavo Romero June 30, 2017, 12:44 a.m. UTC
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 <gromero@linux.vnet.ibm.com>
Signed-off-by: Breno Leitao <leitao@debian.org>
---
 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

Comments

Cyril Bur July 4, 2017, 12:49 a.m. UTC | #1
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 <gromero@linux.vnet.ibm.com>
> Signed-off-by: Breno Leitao <leitao@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 <cyrilbur@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");
> +}
diff mbox

Patch

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");
+}