From 96c447077c2f66ed4117fd832a84c40265dbd9f2 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:07 +1000 Subject: selftests/powerpc: Compile selftests against headers without AT_HWCAP2 It might be nice to compile selftests against older kernels and headers but which may not have HWCAP2. Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/utils.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h index fbd33e52ef8f..ecd11b51475d 100644 --- a/tools/testing/selftests/powerpc/utils.h +++ b/tools/testing/selftests/powerpc/utils.h @@ -32,10 +32,17 @@ static inline bool have_hwcap(unsigned long ftr) return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr; } +#ifdef AT_HWCAP2 static inline bool have_hwcap2(unsigned long ftr2) { return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2; } +#else +static inline bool have_hwcap2(unsigned long ftr2) +{ + return false; +} +#endif /* Yes, this is evil */ #define FAIL_IF(x) \ -- cgit v1.2.3 From 65ca668f58a260e144621fd93a413da67635b999 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:13 +1000 Subject: selftests/powerpc: Check for VSX preservation across userspace preemption Ensure the kernel correctly switches VSX registers correctly. VSX registers are all volatile, and despite the kernel preserving VSX across syscalls, it doesn't have to. Test that during interrupts and timeslices ending the VSX regs remain the same. Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/math/Makefile | 5 +- tools/testing/selftests/powerpc/math/vsx_asm.S | 61 +++++++++ tools/testing/selftests/powerpc/math/vsx_preempt.c | 147 +++++++++++++++++++++ tools/testing/selftests/powerpc/vsx_asm.h | 71 ++++++++++ 4 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/math/vsx_asm.S create mode 100644 tools/testing/selftests/powerpc/math/vsx_preempt.c create mode 100644 tools/testing/selftests/powerpc/vsx_asm.h (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/math/Makefile b/tools/testing/selftests/powerpc/math/Makefile index 5b88875d5955..a505b66d408a 100644 --- a/tools/testing/selftests/powerpc/math/Makefile +++ b/tools/testing/selftests/powerpc/math/Makefile @@ -1,4 +1,4 @@ -TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal +TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal vsx_preempt all: $(TEST_PROGS) @@ -13,6 +13,9 @@ vmx_syscall: vmx_asm.S vmx_preempt: vmx_asm.S vmx_signal: vmx_asm.S +vsx_preempt: CFLAGS += -mvsx +vsx_preempt: vsx_asm.S + include ../../lib.mk clean: diff --git a/tools/testing/selftests/powerpc/math/vsx_asm.S b/tools/testing/selftests/powerpc/math/vsx_asm.S new file mode 100644 index 000000000000..a110dd882d5e --- /dev/null +++ b/tools/testing/selftests/powerpc/math/vsx_asm.S @@ -0,0 +1,61 @@ +/* + * Copyright 2015, Cyril Bur, IBM Corp. + * + * 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. + */ + +#include "../basic_asm.h" +#include "../vsx_asm.h" + +#long check_vsx(vector int *r3); +#This function wraps storeing VSX regs to the end of an array and a +#call to a comparison function in C which boils down to a memcmp() +FUNC_START(check_vsx) + PUSH_BASIC_STACK(32) + std r3,STACK_FRAME_PARAM(0)(sp) + addi r3, r3, 16 * 12 #Second half of array + bl store_vsx + ld r3,STACK_FRAME_PARAM(0)(sp) + bl vsx_memcmp + POP_BASIC_STACK(32) + blr +FUNC_END(check_vsx) + +# int preempt_vmx(vector int *varray, int *threads_starting, +# int *running); +# On starting will (atomically) decrement threads_starting as a signal +# that the VMX have been loaded with varray. Will proceed to check the +# validity of the VMX registers while running is not zero. +FUNC_START(preempt_vsx) + PUSH_BASIC_STACK(512) + std r3,STACK_FRAME_PARAM(0)(sp) # vector int *varray + std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting + std r5,STACK_FRAME_PARAM(2)(sp) # int *running + + bl load_vsx + nop + + sync + # Atomic DEC + ld r3,STACK_FRAME_PARAM(1)(sp) +1: lwarx r4,0,r3 + addi r4,r4,-1 + stwcx. r4,0,r3 + bne- 1b + +2: ld r3,STACK_FRAME_PARAM(0)(sp) + bl check_vsx + nop + cmpdi r3,0 + bne 3f + ld r4,STACK_FRAME_PARAM(2)(sp) + ld r5,0(r4) + cmpwi r5,0 + bne 2b + +3: POP_BASIC_STACK(512) + blr +FUNC_END(preempt_vsx) diff --git a/tools/testing/selftests/powerpc/math/vsx_preempt.c b/tools/testing/selftests/powerpc/math/vsx_preempt.c new file mode 100644 index 000000000000..6387f03a0a6a --- /dev/null +++ b/tools/testing/selftests/powerpc/math/vsx_preempt.c @@ -0,0 +1,147 @@ +/* + * Copyright 2015, Cyril Bur, IBM Corp. + * + * 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. + * + * This test attempts to see if the VSX registers change across preemption. + * There is no way to be sure preemption happened so this test just + * uses many threads and a long wait. As such, a successful test + * doesn't mean much but a failure is bad. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +/* Time to wait for workers to get preempted (seconds) */ +#define PREEMPT_TIME 20 +/* + * Factor by which to multiply number of online CPUs for total number of + * worker threads + */ +#define THREAD_FACTOR 8 + +/* + * Ensure there is twice the number of non-volatile VMX regs! + * check_vmx() is going to use the other half as space to put the live + * registers before calling vsx_memcmp() + */ +__thread vector int varray[24] = { + {1, 2, 3, 4 }, {5, 6, 7, 8 }, {9, 10,11,12}, + {13,14,15,16}, {17,18,19,20}, {21,22,23,24}, + {25,26,27,28}, {29,30,31,32}, {33,34,35,36}, + {37,38,39,40}, {41,42,43,44}, {45,46,47,48} +}; + +int threads_starting; +int running; + +extern long preempt_vsx(vector int *varray, int *threads_starting, int *running); + +long vsx_memcmp(vector int *a) { + vector int zero = {0, 0, 0, 0}; + int i; + + FAIL_IF(a != varray); + + for(i = 0; i < 12; i++) { + if (memcmp(&a[i + 12], &zero, sizeof(vector int)) == 0) { + fprintf(stderr, "Detected zero from the VSX reg %d\n", i + 12); + return 2; + } + } + + if (memcmp(a, &a[12], 12 * sizeof(vector int))) { + long *p = (long *)a; + fprintf(stderr, "VSX mismatch\n"); + for (i = 0; i < 24; i=i+2) + fprintf(stderr, "%d: 0x%08lx%08lx | 0x%08lx%08lx\n", + i/2 + i%2 + 20, p[i], p[i + 1], p[i + 24], p[i + 25]); + return 1; + } + return 0; +} + +void *preempt_vsx_c(void *p) +{ + int i, j; + long rc; + srand(pthread_self()); + for (i = 0; i < 12; i++) + for (j = 0; j < 4; j++) { + varray[i][j] = rand(); + /* Don't want zero because it hides kernel problems */ + if (varray[i][j] == 0) + j--; + } + rc = preempt_vsx(varray, &threads_starting, &running); + if (rc == 2) + fprintf(stderr, "Caught zeros in VSX compares\n"); + return (void *)rc; +} + +int test_preempt_vsx(void) +{ + int i, rc, threads; + pthread_t *tids; + + threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR; + tids = malloc(threads * sizeof(pthread_t)); + FAIL_IF(!tids); + + running = true; + threads_starting = threads; + for (i = 0; i < threads; i++) { + rc = pthread_create(&tids[i], NULL, preempt_vsx_c, NULL); + FAIL_IF(rc); + } + + setbuf(stdout, NULL); + /* Not really nessesary but nice to wait for every thread to start */ + printf("\tWaiting for %d workers to start...", threads_starting); + while(threads_starting) + asm volatile("": : :"memory"); + printf("done\n"); + + printf("\tWaiting for %d seconds to let some workers get preempted...", PREEMPT_TIME); + sleep(PREEMPT_TIME); + printf("done\n"); + + printf("\tStopping workers..."); + /* + * Working are checking this value every loop. In preempt_vsx 'cmpwi r5,0; bne 2b'. + * r5 will have loaded the value of running. + */ + running = 0; + for (i = 0; i < threads; i++) { + void *rc_p; + pthread_join(tids[i], &rc_p); + + /* + * Harness will say the fail was here, look at why preempt_vsx + * returned + */ + if ((long) rc_p) + printf("oops\n"); + FAIL_IF((long) rc_p); + } + printf("done\n"); + + return 0; +} + +int main(int argc, char *argv[]) +{ + return test_harness(test_preempt_vsx, "vsx_preempt"); +} diff --git a/tools/testing/selftests/powerpc/vsx_asm.h b/tools/testing/selftests/powerpc/vsx_asm.h new file mode 100644 index 000000000000..d828bfb6ef2d --- /dev/null +++ b/tools/testing/selftests/powerpc/vsx_asm.h @@ -0,0 +1,71 @@ +/* + * Copyright 2015, Cyril Bur, IBM Corp. + * + * 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. + */ + +#include "basic_asm.h" + +/* + * Careful this will 'clobber' vsx (by design), VSX are always + * volatile though so unlike vmx this isn't so much of an issue + * Still should avoid calling from C + */ +FUNC_START(load_vsx) + li r5,0 + lxvx vs20,r5,r3 + addi r5,r5,16 + lxvx vs21,r5,r3 + addi r5,r5,16 + lxvx vs22,r5,r3 + addi r5,r5,16 + lxvx vs23,r5,r3 + addi r5,r5,16 + lxvx vs24,r5,r3 + addi r5,r5,16 + lxvx vs25,r5,r3 + addi r5,r5,16 + lxvx vs26,r5,r3 + addi r5,r5,16 + lxvx vs27,r5,r3 + addi r5,r5,16 + lxvx vs28,r5,r3 + addi r5,r5,16 + lxvx vs29,r5,r3 + addi r5,r5,16 + lxvx vs30,r5,r3 + addi r5,r5,16 + lxvx vs31,r5,r3 + blr +FUNC_END(load_vsx) + +FUNC_START(store_vsx) + li r5,0 + stxvx vs20,r5,r3 + addi r5,r5,16 + stxvx vs21,r5,r3 + addi r5,r5,16 + stxvx vs22,r5,r3 + addi r5,r5,16 + stxvx vs23,r5,r3 + addi r5,r5,16 + stxvx vs24,r5,r3 + addi r5,r5,16 + stxvx vs25,r5,r3 + addi r5,r5,16 + stxvx vs26,r5,r3 + addi r5,r5,16 + stxvx vs27,r5,r3 + addi r5,r5,16 + stxvx vs28,r5,r3 + addi r5,r5,16 + stxvx vs29,r5,r3 + addi r5,r5,16 + stxvx vs30,r5,r3 + addi r5,r5,16 + stxvx vs31,r5,r3 + blr +FUNC_END(store_vsx) -- cgit v1.2.3 From be4a9f56666af94eccf7993661c1a62db033bff9 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:14 +1000 Subject: selftests/powerpc: Rework FPU stack placement macros and move to header file The FPU regs are placed at the top of the stack frame. Currently the position expected to be passed to the macro. The macros now should be passed the stack frame size and from there they can calculate where to put the regs, this makes the use simpler. Also move them to a header file to be used in an different area of the powerpc selftests Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/fpu_asm.h | 80 ++++++++++++++++++++++++++ tools/testing/selftests/powerpc/math/fpu_asm.S | 73 ++--------------------- 2 files changed, 85 insertions(+), 68 deletions(-) create mode 100644 tools/testing/selftests/powerpc/fpu_asm.h (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/fpu_asm.h b/tools/testing/selftests/powerpc/fpu_asm.h new file mode 100644 index 000000000000..6a387d255e27 --- /dev/null +++ b/tools/testing/selftests/powerpc/fpu_asm.h @@ -0,0 +1,80 @@ +/* + * Copyright 2016, Cyril Bur, IBM Corp. + * + * 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. + */ + +#ifndef _SELFTESTS_POWERPC_FPU_ASM_H +#define _SELFTESTS_POWERPC_FPU_ASM_H +#include "basic_asm.h" + +#define PUSH_FPU(stack_size) \ + stfd f31,(stack_size + STACK_FRAME_MIN_SIZE)(%r1); \ + stfd f30,(stack_size + STACK_FRAME_MIN_SIZE - 8)(%r1); \ + stfd f29,(stack_size + STACK_FRAME_MIN_SIZE - 16)(%r1); \ + stfd f28,(stack_size + STACK_FRAME_MIN_SIZE - 24)(%r1); \ + stfd f27,(stack_size + STACK_FRAME_MIN_SIZE - 32)(%r1); \ + stfd f26,(stack_size + STACK_FRAME_MIN_SIZE - 40)(%r1); \ + stfd f25,(stack_size + STACK_FRAME_MIN_SIZE - 48)(%r1); \ + stfd f24,(stack_size + STACK_FRAME_MIN_SIZE - 56)(%r1); \ + stfd f23,(stack_size + STACK_FRAME_MIN_SIZE - 64)(%r1); \ + stfd f22,(stack_size + STACK_FRAME_MIN_SIZE - 72)(%r1); \ + stfd f21,(stack_size + STACK_FRAME_MIN_SIZE - 80)(%r1); \ + stfd f20,(stack_size + STACK_FRAME_MIN_SIZE - 88)(%r1); \ + stfd f19,(stack_size + STACK_FRAME_MIN_SIZE - 96)(%r1); \ + stfd f18,(stack_size + STACK_FRAME_MIN_SIZE - 104)(%r1); \ + stfd f17,(stack_size + STACK_FRAME_MIN_SIZE - 112)(%r1); \ + stfd f16,(stack_size + STACK_FRAME_MIN_SIZE - 120)(%r1); \ + stfd f15,(stack_size + STACK_FRAME_MIN_SIZE - 128)(%r1); \ + stfd f14,(stack_size + STACK_FRAME_MIN_SIZE - 136)(%r1); + +#define POP_FPU(stack_size) \ + lfd f31,(stack_size + STACK_FRAME_MIN_SIZE)(%r1); \ + lfd f30,(stack_size + STACK_FRAME_MIN_SIZE - 8)(%r1); \ + lfd f29,(stack_size + STACK_FRAME_MIN_SIZE - 16)(%r1); \ + lfd f28,(stack_size + STACK_FRAME_MIN_SIZE - 24)(%r1); \ + lfd f27,(stack_size + STACK_FRAME_MIN_SIZE - 32)(%r1); \ + lfd f26,(stack_size + STACK_FRAME_MIN_SIZE - 40)(%r1); \ + lfd f25,(stack_size + STACK_FRAME_MIN_SIZE - 48)(%r1); \ + lfd f24,(stack_size + STACK_FRAME_MIN_SIZE - 56)(%r1); \ + lfd f23,(stack_size + STACK_FRAME_MIN_SIZE - 64)(%r1); \ + lfd f22,(stack_size + STACK_FRAME_MIN_SIZE - 72)(%r1); \ + lfd f21,(stack_size + STACK_FRAME_MIN_SIZE - 80)(%r1); \ + lfd f20,(stack_size + STACK_FRAME_MIN_SIZE - 88)(%r1); \ + lfd f19,(stack_size + STACK_FRAME_MIN_SIZE - 96)(%r1); \ + lfd f18,(stack_size + STACK_FRAME_MIN_SIZE - 104)(%r1); \ + lfd f17,(stack_size + STACK_FRAME_MIN_SIZE - 112)(%r1); \ + lfd f16,(stack_size + STACK_FRAME_MIN_SIZE - 120)(%r1); \ + lfd f15,(stack_size + STACK_FRAME_MIN_SIZE - 128)(%r1); \ + lfd f14,(stack_size + STACK_FRAME_MIN_SIZE - 136)(%r1); + +/* + * Careful calling this, it will 'clobber' fpu (by design) + * Don't call this from C + */ +FUNC_START(load_fpu) + lfd f14,0(r3) + lfd f15,8(r3) + lfd f16,16(r3) + lfd f17,24(r3) + lfd f18,32(r3) + lfd f19,40(r3) + lfd f20,48(r3) + lfd f21,56(r3) + lfd f22,64(r3) + lfd f23,72(r3) + lfd f24,80(r3) + lfd f25,88(r3) + lfd f26,96(r3) + lfd f27,104(r3) + lfd f28,112(r3) + lfd f29,120(r3) + lfd f30,128(r3) + lfd f31,136(r3) + blr +FUNC_END(load_fpu) + +#endif /* _SELFTESTS_POWERPC_FPU_ASM_H */ diff --git a/tools/testing/selftests/powerpc/math/fpu_asm.S b/tools/testing/selftests/powerpc/math/fpu_asm.S index f3711d80e709..241f067a510f 100644 --- a/tools/testing/selftests/powerpc/math/fpu_asm.S +++ b/tools/testing/selftests/powerpc/math/fpu_asm.S @@ -8,70 +8,7 @@ */ #include "../basic_asm.h" - -#define PUSH_FPU(pos) \ - stfd f14,pos(sp); \ - stfd f15,pos+8(sp); \ - stfd f16,pos+16(sp); \ - stfd f17,pos+24(sp); \ - stfd f18,pos+32(sp); \ - stfd f19,pos+40(sp); \ - stfd f20,pos+48(sp); \ - stfd f21,pos+56(sp); \ - stfd f22,pos+64(sp); \ - stfd f23,pos+72(sp); \ - stfd f24,pos+80(sp); \ - stfd f25,pos+88(sp); \ - stfd f26,pos+96(sp); \ - stfd f27,pos+104(sp); \ - stfd f28,pos+112(sp); \ - stfd f29,pos+120(sp); \ - stfd f30,pos+128(sp); \ - stfd f31,pos+136(sp); - -#define POP_FPU(pos) \ - lfd f14,pos(sp); \ - lfd f15,pos+8(sp); \ - lfd f16,pos+16(sp); \ - lfd f17,pos+24(sp); \ - lfd f18,pos+32(sp); \ - lfd f19,pos+40(sp); \ - lfd f20,pos+48(sp); \ - lfd f21,pos+56(sp); \ - lfd f22,pos+64(sp); \ - lfd f23,pos+72(sp); \ - lfd f24,pos+80(sp); \ - lfd f25,pos+88(sp); \ - lfd f26,pos+96(sp); \ - lfd f27,pos+104(sp); \ - lfd f28,pos+112(sp); \ - lfd f29,pos+120(sp); \ - lfd f30,pos+128(sp); \ - lfd f31,pos+136(sp); - -# Careful calling this, it will 'clobber' fpu (by design) -# Don't call this from C -FUNC_START(load_fpu) - lfd f14,0(r3) - lfd f15,8(r3) - lfd f16,16(r3) - lfd f17,24(r3) - lfd f18,32(r3) - lfd f19,40(r3) - lfd f20,48(r3) - lfd f21,56(r3) - lfd f22,64(r3) - lfd f23,72(r3) - lfd f24,80(r3) - lfd f25,88(r3) - lfd f26,96(r3) - lfd f27,104(r3) - lfd f28,112(r3) - lfd f29,120(r3) - lfd f30,128(r3) - lfd f31,136(r3) - blr -FUNC_END(load_fpu) +#include "../fpu_asm.h" FUNC_START(check_fpu) mr r4,r3 @@ -138,9 +75,9 @@ FUNC_START(test_fpu) # r4 holds pointer to the pid # f14-f31 are non volatiles PUSH_BASIC_STACK(256) + PUSH_FPU(256) std r3,STACK_FRAME_PARAM(0)(sp) # Address of darray std r4,STACK_FRAME_PARAM(1)(sp) # Address of pid - PUSH_FPU(STACK_FRAME_LOCAL(2,0)) bl load_fpu nop @@ -155,7 +92,7 @@ FUNC_START(test_fpu) bl check_fpu nop - POP_FPU(STACK_FRAME_LOCAL(2,0)) + POP_FPU(256) POP_BASIC_STACK(256) blr FUNC_END(test_fpu) @@ -166,10 +103,10 @@ FUNC_END(test_fpu) # registers while running is not zero. FUNC_START(preempt_fpu) PUSH_BASIC_STACK(256) + PUSH_FPU(256) std r3,STACK_FRAME_PARAM(0)(sp) # double *darray std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting std r5,STACK_FRAME_PARAM(2)(sp) # int *running - PUSH_FPU(STACK_FRAME_LOCAL(3,0)) bl load_fpu nop @@ -192,7 +129,7 @@ FUNC_START(preempt_fpu) cmpwi r5,0 bne 2b -3: POP_FPU(STACK_FRAME_LOCAL(3,0)) +3: POP_FPU(256) POP_BASIC_STACK(256) blr FUNC_END(preempt_fpu) -- cgit v1.2.3 From 2b4093790abdf0219f8ca192ecc4ecc63cdb5124 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:15 +1000 Subject: selftests/powerpc: Move VMX stack frame macros to header file Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/math/vmx_asm.S | 85 +---------------------- tools/testing/selftests/powerpc/vmx_asm.h | 96 ++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 84 deletions(-) create mode 100644 tools/testing/selftests/powerpc/vmx_asm.h (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/math/vmx_asm.S b/tools/testing/selftests/powerpc/math/vmx_asm.S index 1b8c248b3ac1..fd74da488625 100644 --- a/tools/testing/selftests/powerpc/math/vmx_asm.S +++ b/tools/testing/selftests/powerpc/math/vmx_asm.S @@ -8,90 +8,7 @@ */ #include "../basic_asm.h" - -# POS MUST BE 16 ALIGNED! -#define PUSH_VMX(pos,reg) \ - li reg,pos; \ - stvx v20,reg,sp; \ - addi reg,reg,16; \ - stvx v21,reg,sp; \ - addi reg,reg,16; \ - stvx v22,reg,sp; \ - addi reg,reg,16; \ - stvx v23,reg,sp; \ - addi reg,reg,16; \ - stvx v24,reg,sp; \ - addi reg,reg,16; \ - stvx v25,reg,sp; \ - addi reg,reg,16; \ - stvx v26,reg,sp; \ - addi reg,reg,16; \ - stvx v27,reg,sp; \ - addi reg,reg,16; \ - stvx v28,reg,sp; \ - addi reg,reg,16; \ - stvx v29,reg,sp; \ - addi reg,reg,16; \ - stvx v30,reg,sp; \ - addi reg,reg,16; \ - stvx v31,reg,sp; - -# POS MUST BE 16 ALIGNED! -#define POP_VMX(pos,reg) \ - li reg,pos; \ - lvx v20,reg,sp; \ - addi reg,reg,16; \ - lvx v21,reg,sp; \ - addi reg,reg,16; \ - lvx v22,reg,sp; \ - addi reg,reg,16; \ - lvx v23,reg,sp; \ - addi reg,reg,16; \ - lvx v24,reg,sp; \ - addi reg,reg,16; \ - lvx v25,reg,sp; \ - addi reg,reg,16; \ - lvx v26,reg,sp; \ - addi reg,reg,16; \ - lvx v27,reg,sp; \ - addi reg,reg,16; \ - lvx v28,reg,sp; \ - addi reg,reg,16; \ - lvx v29,reg,sp; \ - addi reg,reg,16; \ - lvx v30,reg,sp; \ - addi reg,reg,16; \ - lvx v31,reg,sp; - -# Carefull this will 'clobber' vmx (by design) -# Don't call this from C -FUNC_START(load_vmx) - li r5,0 - lvx v20,r5,r3 - addi r5,r5,16 - lvx v21,r5,r3 - addi r5,r5,16 - lvx v22,r5,r3 - addi r5,r5,16 - lvx v23,r5,r3 - addi r5,r5,16 - lvx v24,r5,r3 - addi r5,r5,16 - lvx v25,r5,r3 - addi r5,r5,16 - lvx v26,r5,r3 - addi r5,r5,16 - lvx v27,r5,r3 - addi r5,r5,16 - lvx v28,r5,r3 - addi r5,r5,16 - lvx v29,r5,r3 - addi r5,r5,16 - lvx v30,r5,r3 - addi r5,r5,16 - lvx v31,r5,r3 - blr -FUNC_END(load_vmx) +#include "../vmx_asm.h" # Should be safe from C, only touches r4, r5 and v0,v1,v2 FUNC_START(check_vmx) diff --git a/tools/testing/selftests/powerpc/vmx_asm.h b/tools/testing/selftests/powerpc/vmx_asm.h new file mode 100644 index 000000000000..2eaaeca9cf1d --- /dev/null +++ b/tools/testing/selftests/powerpc/vmx_asm.h @@ -0,0 +1,96 @@ +/* + * Copyright 2015, Cyril Bur, IBM Corp. + * + * 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. + */ + +#include "basic_asm.h" + +/* POS MUST BE 16 ALIGNED! */ +#define PUSH_VMX(pos,reg) \ + li reg,pos; \ + stvx v20,reg,%r1; \ + addi reg,reg,16; \ + stvx v21,reg,%r1; \ + addi reg,reg,16; \ + stvx v22,reg,%r1; \ + addi reg,reg,16; \ + stvx v23,reg,%r1; \ + addi reg,reg,16; \ + stvx v24,reg,%r1; \ + addi reg,reg,16; \ + stvx v25,reg,%r1; \ + addi reg,reg,16; \ + stvx v26,reg,%r1; \ + addi reg,reg,16; \ + stvx v27,reg,%r1; \ + addi reg,reg,16; \ + stvx v28,reg,%r1; \ + addi reg,reg,16; \ + stvx v29,reg,%r1; \ + addi reg,reg,16; \ + stvx v30,reg,%r1; \ + addi reg,reg,16; \ + stvx v31,reg,%r1; + +/* POS MUST BE 16 ALIGNED! */ +#define POP_VMX(pos,reg) \ + li reg,pos; \ + lvx v20,reg,%r1; \ + addi reg,reg,16; \ + lvx v21,reg,%r1; \ + addi reg,reg,16; \ + lvx v22,reg,%r1; \ + addi reg,reg,16; \ + lvx v23,reg,%r1; \ + addi reg,reg,16; \ + lvx v24,reg,%r1; \ + addi reg,reg,16; \ + lvx v25,reg,%r1; \ + addi reg,reg,16; \ + lvx v26,reg,%r1; \ + addi reg,reg,16; \ + lvx v27,reg,%r1; \ + addi reg,reg,16; \ + lvx v28,reg,%r1; \ + addi reg,reg,16; \ + lvx v29,reg,%r1; \ + addi reg,reg,16; \ + lvx v30,reg,%r1; \ + addi reg,reg,16; \ + lvx v31,reg,%r1; + +/* + * Careful this will 'clobber' vmx (by design) + * Don't call this from C + */ +FUNC_START(load_vmx) + li r5,0 + lvx v20,r5,r3 + addi r5,r5,16 + lvx v21,r5,r3 + addi r5,r5,16 + lvx v22,r5,r3 + addi r5,r5,16 + lvx v23,r5,r3 + addi r5,r5,16 + lvx v24,r5,r3 + addi r5,r5,16 + lvx v25,r5,r3 + addi r5,r5,16 + lvx v26,r5,r3 + addi r5,r5,16 + lvx v27,r5,r3 + addi r5,r5,16 + lvx v28,r5,r3 + addi r5,r5,16 + lvx v29,r5,r3 + addi r5,r5,16 + lvx v30,r5,r3 + addi r5,r5,16 + lvx v31,r5,r3 + blr +FUNC_END(load_vmx) -- cgit v1.2.3 From babcd9c4b3e8d271144da4b2b412c3b9991b35d2 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:16 +1000 Subject: selftests/powerpc: Introduce GPR asm helper header file Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/gpr_asm.h | 96 +++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 tools/testing/selftests/powerpc/gpr_asm.h (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/gpr_asm.h b/tools/testing/selftests/powerpc/gpr_asm.h new file mode 100644 index 000000000000..f6f38852d3a0 --- /dev/null +++ b/tools/testing/selftests/powerpc/gpr_asm.h @@ -0,0 +1,96 @@ +/* + * Copyright 2016, Cyril Bur, IBM Corp. + * + * 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. + */ + +#ifndef _SELFTESTS_POWERPC_GPR_ASM_H +#define _SELFTESTS_POWERPC_GPR_ASM_H + +#include "basic_asm.h" + +#define __PUSH_NVREGS(top_pos); \ + std r31,(top_pos)(%r1); \ + std r30,(top_pos - 8)(%r1); \ + std r29,(top_pos - 16)(%r1); \ + std r28,(top_pos - 24)(%r1); \ + std r27,(top_pos - 32)(%r1); \ + std r26,(top_pos - 40)(%r1); \ + std r25,(top_pos - 48)(%r1); \ + std r24,(top_pos - 56)(%r1); \ + std r23,(top_pos - 64)(%r1); \ + std r22,(top_pos - 72)(%r1); \ + std r21,(top_pos - 80)(%r1); \ + std r20,(top_pos - 88)(%r1); \ + std r19,(top_pos - 96)(%r1); \ + std r18,(top_pos - 104)(%r1); \ + std r17,(top_pos - 112)(%r1); \ + std r16,(top_pos - 120)(%r1); \ + std r15,(top_pos - 128)(%r1); \ + std r14,(top_pos - 136)(%r1) + +#define __POP_NVREGS(top_pos); \ + ld r31,(top_pos)(%r1); \ + ld r30,(top_pos - 8)(%r1); \ + ld r29,(top_pos - 16)(%r1); \ + ld r28,(top_pos - 24)(%r1); \ + ld r27,(top_pos - 32)(%r1); \ + ld r26,(top_pos - 40)(%r1); \ + ld r25,(top_pos - 48)(%r1); \ + ld r24,(top_pos - 56)(%r1); \ + ld r23,(top_pos - 64)(%r1); \ + ld r22,(top_pos - 72)(%r1); \ + ld r21,(top_pos - 80)(%r1); \ + ld r20,(top_pos - 88)(%r1); \ + ld r19,(top_pos - 96)(%r1); \ + ld r18,(top_pos - 104)(%r1); \ + ld r17,(top_pos - 112)(%r1); \ + ld r16,(top_pos - 120)(%r1); \ + ld r15,(top_pos - 128)(%r1); \ + ld r14,(top_pos - 136)(%r1) + +#define PUSH_NVREGS(stack_size) \ + __PUSH_NVREGS(stack_size + STACK_FRAME_MIN_SIZE) + +/* 18 NV FPU REGS */ +#define PUSH_NVREGS_BELOW_FPU(stack_size) \ + __PUSH_NVREGS(stack_size + STACK_FRAME_MIN_SIZE - (18 * 8)) + +#define POP_NVREGS(stack_size) \ + __POP_NVREGS(stack_size + STACK_FRAME_MIN_SIZE) + +/* 18 NV FPU REGS */ +#define POP_NVREGS_BELOW_FPU(stack_size) \ + __POP_NVREGS(stack_size + STACK_FRAME_MIN_SIZE - (18 * 8)) + +/* + * Careful calling this, it will 'clobber' NVGPRs (by design) + * Don't call this from C + */ +FUNC_START(load_gpr) + ld r14,0(r3) + ld r15,8(r3) + ld r16,16(r3) + ld r17,24(r3) + ld r18,32(r3) + ld r19,40(r3) + ld r20,48(r3) + ld r21,56(r3) + ld r22,64(r3) + ld r23,72(r3) + ld r24,80(r3) + ld r25,88(r3) + ld r26,96(r3) + ld r27,104(r3) + ld r28,112(r3) + ld r29,120(r3) + ld r30,128(r3) + ld r31,136(r3) + blr +FUNC_END(load_gpr) + + +#endif /* _SELFTESTS_POWERPC_GPR_ASM_H */ -- cgit v1.2.3 From 0886c6d4d21edc9902adfbf02e6e74916287ae04 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:17 +1000 Subject: selftests/powerpc: Allow tests to extend their kill timeout Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/harness.c | 9 +++++++-- tools/testing/selftests/powerpc/utils.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c index 52f9be7f61f0..248a820048df 100644 --- a/tools/testing/selftests/powerpc/harness.c +++ b/tools/testing/selftests/powerpc/harness.c @@ -19,9 +19,9 @@ #include "subunit.h" #include "utils.h" -#define TIMEOUT 120 #define KILL_TIMEOUT 5 +static uint64_t timeout = 120; int run_test(int (test_function)(void), char *name) { @@ -44,7 +44,7 @@ int run_test(int (test_function)(void), char *name) setpgid(pid, pid); /* Wake us up in timeout seconds */ - alarm(TIMEOUT); + alarm(timeout); terminated = false; wait: @@ -94,6 +94,11 @@ static struct sigaction alarm_action = { .sa_handler = alarm_handler, }; +void test_harness_set_timeout(uint64_t time) +{ + timeout = time; +} + int test_harness(int (test_function)(void), char *name) { int rc; diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h index ecd11b51475d..53405e8a52ab 100644 --- a/tools/testing/selftests/powerpc/utils.h +++ b/tools/testing/selftests/powerpc/utils.h @@ -22,7 +22,7 @@ typedef uint32_t u32; typedef uint16_t u16; typedef uint8_t u8; - +void test_harness_set_timeout(uint64_t time); int test_harness(int (test_function)(void), char *name); extern void *get_auxv_entry(int type); int pick_online_cpu(void); -- cgit v1.2.3 From 8e03bd4e70b6a4c70ac3ea6766b2bc06a8ad91a3 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:18 +1000 Subject: selftests/powerpc: Add TM tcheck helpers in C Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/tm.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/tm/tm.h b/tools/testing/selftests/powerpc/tm/tm.h index 60318bad7d7a..2c8da74304e7 100644 --- a/tools/testing/selftests/powerpc/tm/tm.h +++ b/tools/testing/selftests/powerpc/tm/tm.h @@ -52,4 +52,31 @@ static inline bool failure_is_nesting(void) return (__builtin_get_texasru() & 0x400000); } +static inline int tcheck(void) +{ + long cr; + asm volatile ("tcheck 0" : "=r"(cr) : : "cr0"); + return (cr >> 28) & 4; +} + +static inline bool tcheck_doomed(void) +{ + return tcheck() & 8; +} + +static inline bool tcheck_active(void) +{ + return tcheck() & 4; +} + +static inline bool tcheck_suspended(void) +{ + return tcheck() & 2; +} + +static inline bool tcheck_transactional(void) +{ + return tcheck() & 6; +} + #endif /* _SELFTESTS_POWERPC_TM_TM_H */ -- cgit v1.2.3 From ef186331b427fdf2bf791d184921df6c6c6e9a63 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:19 +1000 Subject: selftests/powerpc: Check that signals always get delivered Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/Makefile | 1 + tools/testing/selftests/powerpc/signal/Makefile | 13 +++ tools/testing/selftests/powerpc/signal/signal.S | 50 ++++++++++ tools/testing/selftests/powerpc/signal/signal.c | 111 +++++++++++++++++++++ tools/testing/selftests/powerpc/signal/signal_tm.c | 110 ++++++++++++++++++++ 5 files changed, 285 insertions(+) create mode 100644 tools/testing/selftests/powerpc/signal/Makefile create mode 100644 tools/testing/selftests/powerpc/signal/signal.S create mode 100644 tools/testing/selftests/powerpc/signal/signal.c create mode 100644 tools/testing/selftests/powerpc/signal/signal_tm.c (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index 1cc6d64c39b7..db54a33f850f 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile @@ -19,6 +19,7 @@ SUB_DIRS = alignment \ dscr \ mm \ pmu \ + signal \ primitives \ stringloops \ switch_endian \ diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile new file mode 100644 index 000000000000..f0eef27458e2 --- /dev/null +++ b/tools/testing/selftests/powerpc/signal/Makefile @@ -0,0 +1,13 @@ +TEST_PROGS := signal signal_tm + +all: $(TEST_PROGS) + +$(TEST_PROGS): ../harness.c ../utils.c signal.S + +CFLAGS += -maltivec +signal_tm: CFLAGS += -mhtm + +include ../../lib.mk + +clean: + rm -f $(TEST_PROGS) *.o diff --git a/tools/testing/selftests/powerpc/signal/signal.S b/tools/testing/selftests/powerpc/signal/signal.S new file mode 100644 index 000000000000..7043d521df0a --- /dev/null +++ b/tools/testing/selftests/powerpc/signal/signal.S @@ -0,0 +1,50 @@ +/* + * Copyright 2015, Cyril Bur, IBM Corp. + * + * 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. + */ + +#include "../basic_asm.h" + +/* long signal_self(pid_t pid, int sig); */ +FUNC_START(signal_self) + li r0,37 /* sys_kill */ + /* r3 already has our pid in it */ + /* r4 already has signal type in it */ + sc + bc 4,3,1f + subfze r3,r3 +1: blr +FUNC_END(signal_self) + +/* long tm_signal_self(pid_t pid, int sig, int *ret); */ +FUNC_START(tm_signal_self) + PUSH_BASIC_STACK(8) + std r5,STACK_FRAME_PARAM(0)(sp) /* ret */ + tbegin. + beq 1f + tsuspend. + li r0,37 /* sys_kill */ + /* r3 already has our pid in it */ + /* r4 already has signal type in it */ + sc + ld r5,STACK_FRAME_PARAM(0)(sp) /* ret */ + bc 4,3,2f + subfze r3,r3 +2: std r3,0(r5) + tabort. 0 + tresume. /* Be nice to some cleanup, jumps back to tbegin then to 1: */ + /* + * Transaction should be proper doomed and we should never get + * here + */ + li r3,1 + POP_BASIC_STACK(8) + blr +1: li r3,0 + POP_BASIC_STACK(8) + blr +FUNC_END(tm_signal_self) diff --git a/tools/testing/selftests/powerpc/signal/signal.c b/tools/testing/selftests/powerpc/signal/signal.c new file mode 100644 index 000000000000..e7dedd28b3c2 --- /dev/null +++ b/tools/testing/selftests/powerpc/signal/signal.c @@ -0,0 +1,111 @@ +/* + * Copyright 2016, Cyril Bur, IBM Corp. + * + * 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. + * + * Sending one self a signal should always get delivered. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "utils.h" + +#define MAX_ATTEMPT 500000 +#define TIMEOUT 5 + +extern long signal_self(pid_t pid, int sig); + +static sig_atomic_t signaled; +static sig_atomic_t fail; + +static void signal_handler(int sig) +{ + if (sig == SIGUSR1) + signaled = 1; + else + fail = 1; +} + +static int test_signal() +{ + int i; + struct sigaction act; + pid_t ppid = getpid(); + pid_t pid; + + act.sa_handler = signal_handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + if (sigaction(SIGUSR1, &act, NULL) < 0) { + perror("sigaction SIGUSR1"); + exit(1); + } + if (sigaction(SIGALRM, &act, NULL) < 0) { + perror("sigaction SIGALRM"); + exit(1); + } + + /* Don't do this for MAX_ATTEMPT, its simply too long */ + for(i = 0; i < 1000; i++) { + pid = fork(); + if (pid == -1) { + perror("fork"); + exit(1); + } + if (pid == 0) { + signal_self(ppid, SIGUSR1); + exit(1); + } else { + alarm(0); /* Disable any pending */ + alarm(2); + while (!signaled && !fail) + asm volatile("": : :"memory"); + if (!signaled) { + fprintf(stderr, "Didn't get signal from child\n"); + FAIL_IF(1); /* For the line number */ + } + /* Otherwise we'll loop too fast and fork() will eventually fail */ + waitpid(pid, NULL, 0); + } + } + + for (i = 0; i < MAX_ATTEMPT; i++) { + long rc; + + alarm(0); /* Disable any pending */ + signaled = 0; + alarm(TIMEOUT); + rc = signal_self(ppid, SIGUSR1); + if (rc) { + fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx", + i, fail, rc); + FAIL_IF(1); /* For the line number */ + } + while (!signaled && !fail) + asm volatile("": : :"memory"); + if (!signaled) { + fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx", + i, fail, rc); + FAIL_IF(1); /* For the line number */ + } + } + + return 0; +} + +int main(void) +{ + test_harness_set_timeout(300); + return test_harness(test_signal, "signal"); +} diff --git a/tools/testing/selftests/powerpc/signal/signal_tm.c b/tools/testing/selftests/powerpc/signal/signal_tm.c new file mode 100644 index 000000000000..2e7451a37cc6 --- /dev/null +++ b/tools/testing/selftests/powerpc/signal/signal_tm.c @@ -0,0 +1,110 @@ +/* + * Copyright 2016, Cyril Bur, IBM Corp. + * + * 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. + * + * Sending one self a signal should always get delivered. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "utils.h" +#include "../tm/tm.h" + +#define MAX_ATTEMPT 500000 +#define TIMEOUT 10 + +extern long tm_signal_self(pid_t pid, int sig, long *ret); + +static sig_atomic_t signaled; +static sig_atomic_t fail; + +static void signal_handler(int sig) +{ + if (tcheck_active()) { + fail = 2; + return; + } + + if (sig == SIGUSR1) + signaled = 1; + else + fail = 1; +} + +static int test_signal_tm() +{ + int i; + struct sigaction act; + + act.sa_handler = signal_handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + if (sigaction(SIGUSR1, &act, NULL) < 0) { + perror("sigaction SIGUSR1"); + exit(1); + } + if (sigaction(SIGALRM, &act, NULL) < 0) { + perror("sigaction SIGALRM"); + exit(1); + } + + SKIP_IF(!have_htm()); + + for (i = 0; i < MAX_ATTEMPT; i++) { + /* + * If anything bad happens in ASM and we fail to set ret + * because *handwave* TM this will cause failure + */ + long ret = 0xdead; + long rc = 0xbeef; + + alarm(0); /* Disable any pending */ + signaled = 0; + alarm(TIMEOUT); + FAIL_IF(tcheck_transactional()); + rc = tm_signal_self(getpid(), SIGUSR1, &ret); + if (ret == 0xdead) + /* + * This basically means the transaction aborted before we + * even got to the suspend... this is crazy but it + * happens. + * Yes this also means we might never make forward + * progress... the alarm() will trip eventually... + */ + continue; + + if (rc || ret) { + /* Ret is actually an errno */ + printf("TEXASR 0x%016lx, TFIAR 0x%016lx\n", + __builtin_get_texasr(), __builtin_get_tfiar()); + fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n", + i, fail, rc, ret); + FAIL_IF(ret); + } + while(!signaled && !fail) + asm volatile("": : :"memory"); + if (!signaled) { + fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n", + i, fail, rc, ret); + FAIL_IF(fail); /* For the line number */ + } + } + + return 0; +} + +int main(void) +{ + return test_harness(test_signal_tm, "signal_tm"); +} -- cgit v1.2.3 From f10d4424b20c101f3b4dd599819083e1e4b5a3fa Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:20 +1000 Subject: selftests/powerpc: Add checks for transactional GPRs in signal contexts If a thread receives a signal while transactional the kernel creates a second context to show the transactional state of the process. This test loads some known values and waits for a signal and confirms that the expected values are in the signal context. Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/Makefile | 7 +- .../powerpc/tm/tm-signal-context-chk-gpr.c | 90 ++++++++++++++++ tools/testing/selftests/powerpc/tm/tm-signal.S | 114 +++++++++++++++++++++ 3 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c create mode 100644 tools/testing/selftests/powerpc/tm/tm-signal.S (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index 9d301d785d9e..e1204f6f9175 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -1,5 +1,7 @@ +SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr + TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ - tm-vmxcopy tm-fork tm-tar tm-tmspr tm-exec tm-execed + tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS) all: $(TEST_PROGS) @@ -11,6 +13,9 @@ tm-syscall: tm-syscall-asm.S tm-syscall: CFLAGS += -I../../../../../usr/include tm-tmspr: CFLAGS += -pthread +$(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S +$(SIGNAL_CONTEXT_CHK_TESTS): CFLAGS += -mhtm -m64 -mvsx + include ../../lib.mk clean: diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c new file mode 100644 index 000000000000..df91330a08ef --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-gpr.c @@ -0,0 +1,90 @@ +/* + * Copyright 2016, Cyril Bur, IBM Corp. + * + * 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. + * + * + * Test the kernel's signal frame code. + * + * The kernel sets up two sets of ucontexts if the signal was to be + * delivered while the thread was in a transaction. + * Expected behaviour is that the checkpointed state is in the user + * context passed to the signal handler. The speculated state can be + * accessed with the uc_link pointer. + * + * The rationale for this is that if TM unaware code (which linked + * against TM libs) installs a signal handler it will not know of the + * speculative nature of the 'live' registers and may infer the wrong + * thing. + */ + +#include +#include +#include +#include + +#include + +#include "utils.h" +#include "tm.h" + +#define MAX_ATTEMPT 500000 + +#define NV_GPR_REGS 18 + +long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); + +static sig_atomic_t fail; + +static long gps[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18}; + +static void signal_usr1(int signum, siginfo_t *info, void *uc) +{ + int i; + ucontext_t *ucp = uc; + ucontext_t *tm_ucp = ucp->uc_link; + + for (i = 0; i < NV_GPR_REGS && !fail; i++) { + fail = (ucp->uc_mcontext.gp_regs[i + 14] != gps[i]); + fail |= (tm_ucp->uc_mcontext.gp_regs[i + 14] != gps[i + NV_GPR_REGS]); + if (fail) + printf("Failed on %d GPR %lu or %lu\n", i, + ucp->uc_mcontext.gp_regs[i + 14], tm_ucp->uc_mcontext.gp_regs[i + 14]); + } +} + +static int tm_signal_context_chk_gpr() +{ + struct sigaction act; + int i; + long rc; + pid_t pid = getpid(); + + 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); + } + + i = 0; + while (i < MAX_ATTEMPT && !fail) { + rc = tm_signal_self_context_load(pid, gps, NULL, NULL, NULL); + FAIL_IF(rc != pid); + i++; + } + + return fail; +} + +int main(void) +{ + return test_harness(tm_signal_context_chk_gpr, "tm_signal_context_chk_gpr"); +} diff --git a/tools/testing/selftests/powerpc/tm/tm-signal.S b/tools/testing/selftests/powerpc/tm/tm-signal.S new file mode 100644 index 000000000000..4e13e8b3a96f --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal.S @@ -0,0 +1,114 @@ +/* + * Copyright 2015, Cyril Bur, IBM Corp. + * + * 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. + */ + +#include "../basic_asm.h" +#include "../gpr_asm.h" +#include "../fpu_asm.h" +#include "../vmx_asm.h" +#include "../vsx_asm.h" + +/* + * Large caveat here being that the caller cannot expect the + * signal to always be sent! The hardware can (AND WILL!) abort + * the transaction between the tbegin and the tsuspend (however + * unlikely it seems or infrequently it actually happens). + * You have been warned. + */ +/* long tm_signal_self(pid_t pid, long *gprs, double *fps, vector *vms, vector *vss); */ +FUNC_START(tm_signal_self_context_load) + PUSH_BASIC_STACK(512) + /* + * Don't strictly need to save and restore as it depends on if + * we're going to use them, however this reduces messy logic + */ + PUSH_VMX(STACK_FRAME_LOCAL(5,0),r8) + PUSH_FPU(512) + PUSH_NVREGS_BELOW_FPU(512) + std r3, STACK_FRAME_PARAM(0)(sp) /* pid */ + std r4, STACK_FRAME_PARAM(1)(sp) /* gps */ + std r5, STACK_FRAME_PARAM(2)(sp) /* fps */ + std r6, STACK_FRAME_PARAM(3)(sp) /* vms */ + std r7, STACK_FRAME_PARAM(4)(sp) /* vss */ + + ld r3, STACK_FRAME_PARAM(1)(sp) + cmpdi r3, 0 + beq skip_gpr_lc + bl load_gpr +skip_gpr_lc: + ld r3, STACK_FRAME_PARAM(2)(sp) + cmpdi r3, 0 + beq skip_fpu_lc + bl load_fpu +skip_fpu_lc: + ld r3, STACK_FRAME_PARAM(3)(sp) + cmpdi r3, 0 + beq skip_vmx_lc + bl load_vmx +skip_vmx_lc: + ld r3, STACK_FRAME_PARAM(4)(sp) + cmpdi r3, 0 + beq skip_vsx_lc + bl load_vsx +skip_vsx_lc: + /* + * Set r3 (return value) before tbegin. Use the pid as a known + * 'all good' return value, zero is used to indicate a non-doomed + * transaction. + */ + ld r3, STACK_FRAME_PARAM(0)(sp) + tbegin. + beq 1f + tsuspend. /* Can't enter a syscall transactionally */ + ld r3, STACK_FRAME_PARAM(1)(sp) + cmpdi r3, 0 + beq skip_gpr_lt + /* Get the second half of the array */ + addi r3, r3, 8 * 18 + bl load_gpr +skip_gpr_lt: + ld r3, STACK_FRAME_PARAM(2)(sp) + cmpdi r3, 0 + beq skip_fpu_lt + /* Get the second half of the array */ + addi r3, r3, 8 * 18 + bl load_fpu +skip_fpu_lt: + ld r3, STACK_FRAME_PARAM(3)(sp) + cmpdi r3, 0 + beq skip_vmx_lt + /* Get the second half of the array */ + addi r3, r3, 16 * 12 + bl load_vmx +skip_vmx_lt: + ld r3, STACK_FRAME_PARAM(4)(sp) + cmpdi r3, 0 + beq skip_vsx_lt + /* Get the second half of the array */ + addi r3, r3, 16 * 12 + bl load_vsx +skip_vsx_lt: + li r0, 37 /* sys_kill */ + ld r3, STACK_FRAME_PARAM(0)(sp) /* pid */ + li r4, 10 /* SIGUSR1 */ + sc /* Taking the signal will doom the transaction */ + tabort. 0 + tresume. /* Be super sure we abort */ + /* + * This will cause us to resume doomed transaction and cause + * hardware to cleanup, we'll end up at 1: anything between + * tresume. and 1: shouldn't ever run. + */ + li r3, 0 + 1: + POP_VMX(STACK_FRAME_LOCAL(5,0),r4) + POP_FPU(512) + POP_NVREGS_BELOW_FPU(512) + POP_BASIC_STACK(512) + blr +FUNC_END(tm_signal_self_context_load) -- cgit v1.2.3 From 5ca4ffcd5cee39af6b0b3ccfea59ebfffb5c2ad5 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:21 +1000 Subject: selftests/powerpc: Add checks for transactional FPUs in signal contexts If a thread receives a signal while transactional the kernel creates a second context to show the transactional state of the process. This test loads some known values and waits for a signal and confirms that the expected values are in the signal context. Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/Makefile | 2 +- .../powerpc/tm/tm-signal-context-chk-fpu.c | 92 ++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index e1204f6f9175..d5d983f991a4 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -1,4 +1,4 @@ -SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr +SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS) diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c new file mode 100644 index 000000000000..c760debbd5ad --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-fpu.c @@ -0,0 +1,92 @@ +/* + * Copyright 2016, Cyril Bur, IBM Corp. + * + * 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. + * + * + * Test the kernel's signal frame code. + * + * The kernel sets up two sets of ucontexts if the signal was to be + * delivered while the thread was in a transaction. + * Expected behaviour is that the checkpointed state is in the user + * context passed to the signal handler. The speculated state can be + * accessed with the uc_link pointer. + * + * The rationale for this is that if TM unaware code (which linked + * against TM libs) installs a signal handler it will not know of the + * speculative nature of the 'live' registers and may infer the wrong + * thing. + */ + +#include +#include +#include +#include + +#include + +#include "utils.h" +#include "tm.h" + +#define MAX_ATTEMPT 500000 + +#define NV_FPU_REGS 18 + +long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); + +/* Be sure there are 2x as many as there are NV FPU regs (2x18) */ +static double fps[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18 +}; + +static sig_atomic_t fail; + +static void signal_usr1(int signum, siginfo_t *info, void *uc) +{ + int i; + ucontext_t *ucp = uc; + ucontext_t *tm_ucp = ucp->uc_link; + + for (i = 0; i < NV_FPU_REGS && !fail; i++) { + fail = (ucp->uc_mcontext.fp_regs[i + 14] != fps[i]); + fail |= (tm_ucp->uc_mcontext.fp_regs[i + 14] != fps[i + NV_FPU_REGS]); + if (fail) + printf("Failed on %d FP %g or %g\n", i, ucp->uc_mcontext.fp_regs[i + 14], tm_ucp->uc_mcontext.fp_regs[i + 14]); + } +} + +static int tm_signal_context_chk_fpu() +{ + struct sigaction act; + int i; + long rc; + pid_t pid = getpid(); + + 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); + } + + i = 0; + while (i < MAX_ATTEMPT && !fail) { + rc = tm_signal_self_context_load(pid, NULL, fps, NULL, NULL); + FAIL_IF(rc != pid); + i++; + } + + return fail; +} + +int main(void) +{ + return test_harness(tm_signal_context_chk_fpu, "tm_signal_context_chk_fpu"); +} -- cgit v1.2.3 From 7bb0e7e38b5787d0d88c709c8933a08ed733eb94 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:22 +1000 Subject: selftests/powerpc: Add checks for transactional VMXs in signal contexts If a thread receives a signal while transactional the kernel creates a second context to show the transactional state of the process. This test loads some known values and waits for a signal and confirms that the expected values are in the signal context. Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/Makefile | 3 +- .../powerpc/tm/tm-signal-context-chk-vmx.c | 110 +++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index d5d983f991a4..d550ebca2a94 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -1,4 +1,5 @@ -SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu +SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu \ + tm-signal-context-chk-vmx TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS) diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c new file mode 100644 index 000000000000..f0ee55fd5185 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c @@ -0,0 +1,110 @@ +/* + * Copyright 2016, Cyril Bur, IBM Corp. + * + * 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. + * + * + * Test the kernel's signal frame code. + * + * The kernel sets up two sets of ucontexts if the signal was to be + * delivered while the thread was in a transaction. + * Expected behaviour is that the checkpointed state is in the user + * context passed to the signal handler. The speculated state can be + * accessed with the uc_link pointer. + * + * The rationale for this is that if TM unaware code (which linked + * against TM libs) installs a signal handler it will not know of the + * speculative nature of the 'live' registers and may infer the wrong + * thing. + */ + +#include +#include +#include +#include +#include + +#include + +#include "utils.h" +#include "tm.h" + +#define MAX_ATTEMPT 500000 + +#define NV_VMX_REGS 12 + +long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); + +static sig_atomic_t fail; + +vector int vms[] = { + {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12}, + {13,14,15,16},{17,18,19,20},{21,22,23,24}, + {25,26,27,28},{29,30,31,32},{33,34,35,36}, + {37,38,39,40},{41,42,43,44},{45,46,47,48}, + {-1, -2, -3, -4}, {-5, -6, -7, -8}, {-9, -10,-11,-12}, + {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24}, + {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36}, + {-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48} +}; + +static void signal_usr1(int signum, siginfo_t *info, void *uc) +{ + int i; + ucontext_t *ucp = uc; + ucontext_t *tm_ucp = ucp->uc_link; + + for (i = 0; i < NV_VMX_REGS && !fail; i++) { + fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[i + 20], + &vms[i], sizeof(vector int)); + fail |= memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[i + 20], + &vms[i + NV_VMX_REGS], sizeof (vector int)); + + if (fail) { + int j; + + fprintf(stderr, "Failed on %d vmx 0x", i); + for (j = 0; j < 4; j++) + fprintf(stderr, "%04x", ucp->uc_mcontext.v_regs->vrregs[i + 20][j]); + fprintf(stderr, " vs 0x"); + for (j = 0 ; j < 4; j++) + fprintf(stderr, "%04x", tm_ucp->uc_mcontext.v_regs->vrregs[i + 20][j]); + fprintf(stderr, "\n"); + } + } +} + +static int tm_signal_context_chk() +{ + struct sigaction act; + int i; + long rc; + pid_t pid = getpid(); + + 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); + } + + i = 0; + while (i < MAX_ATTEMPT && !fail) { + rc = tm_signal_self_context_load(pid, NULL, NULL, vms, NULL); + FAIL_IF(rc != pid); + i++; + } + + return fail; +} + +int main(void) +{ + return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vmx"); +} -- cgit v1.2.3 From dd9bda4780936d319476867901b20c86b490b0c0 Mon Sep 17 00:00:00 2001 From: Cyril Bur Date: Fri, 23 Sep 2016 16:18:23 +1000 Subject: selftests/powerpc: Add checks for transactional VSXs in signal contexts If a thread receives a signal while transactional the kernel creates a second context to show the transactional state of the process. This test loads some known values and waits for a signal and confirms that the expected values are in the signal context. Signed-off-by: Cyril Bur Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/Makefile | 2 +- .../powerpc/tm/tm-signal-context-chk-vsx.c | 125 +++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c (limited to 'tools/testing/selftests') diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index d550ebca2a94..c6c53c82fdd6 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -1,5 +1,5 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu \ - tm-signal-context-chk-vmx + tm-signal-context-chk-vmx tm-signal-context-chk-vsx TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS) diff --git a/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c new file mode 100644 index 000000000000..b99c3d835957 --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c @@ -0,0 +1,125 @@ +/* + * Copyright 2016, Cyril Bur, IBM Corp. + * + * 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. + * + * + * Test the kernel's signal frame code. + * + * The kernel sets up two sets of ucontexts if the signal was to be + * delivered while the thread was in a transaction. + * Expected behaviour is that the checkpointed state is in the user + * context passed to the signal handler. The speculated state can be + * accessed with the uc_link pointer. + * + * The rationale for this is that if TM unaware code (which linked + * against TM libs) installs a signal handler it will not know of the + * speculative nature of the 'live' registers and may infer the wrong + * thing. + */ + +#include +#include +#include +#include +#include + +#include + +#include "utils.h" +#include "tm.h" + +#define MAX_ATTEMPT 500000 + +#define NV_VSX_REGS 12 + +long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss); + +static sig_atomic_t fail; + +vector int vss[] = { + {1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12}, + {13,14,15,16},{17,18,19,20},{21,22,23,24}, + {25,26,27,28},{29,30,31,32},{33,34,35,36}, + {37,38,39,40},{41,42,43,44},{45,46,47,48}, + {-1, -2, -3, -4 },{-5, -6, -7, -8 },{-9, -10,-11,-12}, + {-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24}, + {-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36}, + {-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48} +}; + +static void signal_usr1(int signum, siginfo_t *info, void *uc) +{ + int i; + uint8_t vsc[sizeof(vector int)]; + uint8_t vst[sizeof(vector int)]; + ucontext_t *ucp = uc; + ucontext_t *tm_ucp = ucp->uc_link; + + /* + * The other half of the VSX regs will be after v_regs. + * + * In short, vmx_reserve array holds everything. v_regs is a 16 + * byte aligned pointer at the start of vmx_reserve (vmx_reserve + * may or may not be 16 aligned) where the v_regs structure exists. + * (half of) The VSX regsters are directly after v_regs so the + * easiest way to find them below. + */ + long *vsx_ptr = (long *)(ucp->uc_mcontext.v_regs + 1); + long *tm_vsx_ptr = (long *)(tm_ucp->uc_mcontext.v_regs + 1); + for (i = 0; i < NV_VSX_REGS && !fail; i++) { + memcpy(vsc, &ucp->uc_mcontext.fp_regs[i + 20], 8); + memcpy(vsc + 8, &vsx_ptr[20 + i], 8); + fail = memcmp(vsc, &vss[i], sizeof(vector int)); + memcpy(vst, &tm_ucp->uc_mcontext.fp_regs[i + 20], 8); + memcpy(vst + 8, &tm_vsx_ptr[20 + i], 8); + fail |= memcmp(vst, &vss[i + NV_VSX_REGS], sizeof(vector int)); + + if (fail) { + int j; + + fprintf(stderr, "Failed on %d vsx 0x", i); + for (j = 0; j < 16; j++) + fprintf(stderr, "%02x", vsc[j]); + fprintf(stderr, " vs 0x"); + for (j = 0; j < 16; j++) + fprintf(stderr, "%02x", vst[j]); + fprintf(stderr, "\n"); + } + } +} + +static int tm_signal_context_chk() +{ + struct sigaction act; + int i; + long rc; + pid_t pid = getpid(); + + 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); + } + + i = 0; + while (i < MAX_ATTEMPT && !fail) { + rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vss); + FAIL_IF(rc != pid); + i++; + } + + return fail; +} + +int main(void) +{ + return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vsx"); +} -- cgit v1.2.3