Subject: Re: [PATCH 1/8] selftests/powerpc: Test the preservation of FPU and VMX regs across syscall

From: Michael Neuling <[email-masked]>
Date: Mon, 23 Nov 2015 11:23:13 +1100

On Wed, 2015-11-18 at 14:26 +1100, Cyril Bur wrote:
> Test that the non volatile floating point and Altivec registers get
> correctly preserved across the fork() syscall.

Can we add a test for VSX too?  I realise it's the same registers, but
the enable bits in the MSR are different so it's easy to get them wrong
in the kernel.

Additional comments below.

> fork() works nicely for this purpose, the registers should be the same for
> both parent and child
> 
> Signed-off-by: Cyril Bur <[email-masked]>
> ---
>  tools/testing/selftests/powerpc/Makefile           |   3 +-
>  tools/testing/selftests/powerpc/math/Makefile      |  14 ++
>  tools/testing/selftests/powerpc/math/basic_asm.h   |  26 +++
>  tools/testing/selftests/powerpc/math/fpu_asm.S     | 151 +++++++++++++++++
>  tools/testing/selftests/powerpc/math/fpu_syscall.c |  79 +++++++++
>  tools/testing/selftests/powerpc/math/vmx_asm.S     | 183 +++++++++++++++++++++
>  tools/testing/selftests/powerpc/math/vmx_syscall.c |  81 +++++++++
>  7 files changed, 536 insertions(+), 1 deletion(-)
>  create mode 100644 tools/testing/selftests/powerpc/math/Makefile
>  create mode 100644 tools/testing/selftests/powerpc/math/basic_asm.h
>  create mode 100644 tools/testing/selftests/powerpc/math/fpu_asm.S
>  create mode 100644 tools/testing/selftests/powerpc/math/fpu_syscall.c
>  create mode 100644 tools/testing/selftests/powerpc/math/vmx_asm.S
>  create mode 100644 tools/testing/selftests/powerpc/math/vmx_syscall.c
> 
> diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
> index 0c2706b..19e8191 100644
> --- a/tools/testing/selftests/powerpc/Makefile
> +++ b/tools/testing/selftests/powerpc/Makefile
> @@ -22,7 +22,8 @@ SUB_DIRS = benchmarks > 	> 	> \
>  > 	>    switch_endian> 	> \
>  > 	>    syscalls> 	> 	> \
>  > 	>    tm> 	> 	> 	> \
> -> 	>    vphn
> +> 	>    vphn         \
> +> 	>    math
>  
>  endif
>  
> diff --git a/tools/testing/selftests/powerpc/math/Makefile b/tools/testing/selftests/powerpc/math/Makefile
> new file mode 100644
> index 0000000..896d9e2
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/math/Makefile
> @@ -0,0 +1,14 @@
> +TEST_PROGS := fpu_syscall vmx_syscall

Add a new .gitignore in this dirfor these new build objects.

> +
> +all: $(TEST_PROGS)
> +
> +$(TEST_PROGS): ../harness.c
> +$(TEST_PROGS): CFLAGS += -O2 -g
> +
> +fpu_syscall: fpu_asm.S
> +vmx_syscall: vmx_asm.S
> +
> +include ../../lib.mk
> +
> +clean:
> +> 	> rm -f $(TEST_PROGS) *.o
> diff --git a/tools/testing/selftests/powerpc/math/basic_asm.h b/tools/testing/selftests/powerpc/math/basic_asm.h
> new file mode 100644
> index 0000000..27aca79
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/math/basic_asm.h

Can you put this up a directory since it's generically useful for
powerpc?

> @@ -0,0 +1,26 @@
> +#include 
> +#include 
> +
> +#define LOAD_REG_IMMEDIATE(reg,expr) \
> +> 	> lis> 	> reg,(expr)@highest;> 	> \
> +> 	> ori> 	> reg,reg,(expr)@higher;> 	> \
> +> 	> rldicr> 	> reg,reg,32,31;> 	> \
> +> 	> oris> 	> reg,reg,(expr)@high;> 	> \
> +> 	> ori> 	> reg,reg,(expr)@l;
> +
> +#define PUSH_BASIC_STACK(size) \
> +> 	> std> 	> 2,24(sp); \
> +> 	> mflr> 	> r0; \
> +> 	> std> 	> r0,16(sp); \
> +> 	> mfcr> 	> r0; \
> +> 	> stw> 	> r0,8(sp); \
> +> 	> stdu> 	> sp,-size(sp);
> +
> +#define POP_BASIC_STACK(size) \
> +> 	> addi> 	> sp,sp,size; \
> +> 	> ld> 	> 2,24(sp); \
> +> 	> ld> 	> r0,16(sp); \
> +> 	> mtlr> 	> r0; \
> +> 	> lwz> 	> r0,8(sp); \
> +> 	> mtcr> 	> r0; \
> +
> diff --git a/tools/testing/selftests/powerpc/math/fpu_asm.S b/tools/testing/selftests/powerpc/math/fpu_asm.S
> new file mode 100644
> index 0000000..d5412c1
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/math/fpu_asm.S
> @@ -0,0 +1,151 @@
> +#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)
> +
> +FUNC_START(check_fpu)
> +> 	> mr r4,r3
> +> 	> li> 	> r3,1 #assume a bad result
> +> 	> lfd> 	> f0,0(r4)
> +> 	> fcmpu> 	> cr1,f0,f14
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,8(r4)
> +> 	> fcmpu> 	> cr1,f0,f15
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,16(r4)
> +> 	> fcmpu> 	> cr1,f0,f16
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,24(r4)
> +> 	> fcmpu> 	> cr1,f0,f17
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,32(r4)
> +> 	> fcmpu> 	> cr1,f0,f18
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,40(r4)
> +> 	> fcmpu> 	> cr1,f0,f19
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,48(r4)
> +> 	> fcmpu> 	> cr1,f0,f20
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,56(r4)
> +> 	> fcmpu> 	> cr1,f0,f21
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,64(r4)
> +> 	> fcmpu> 	> cr1,f0,f22
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,72(r4)
> +> 	> fcmpu> 	> cr1,f0,f23
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,80(r4)
> +> 	> fcmpu> 	> cr1,f0,f24
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,88(r4)
> +> 	> fcmpu> 	> cr1,f0,f25
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,96(r4)
> +> 	> fcmpu> 	> cr1,f0,f26
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,104(r4)
> +> 	> fcmpu> 	> cr1,f0,f27
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,112(r4)
> +> 	> fcmpu> 	> cr1,f0,f28
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,120(r4)
> +> 	> fcmpu> 	> cr1,f0,f29
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,128(r4)
> +> 	> fcmpu> 	> cr1,f0,f30
> +> 	> bne> 	> cr1,1f
> +> 	> lfd> 	> f0,136(r4)
> +> 	> fcmpu> 	> cr1,f0,f31
> +> 	> bne> 	> cr1,1f
> +> 	> li> 	> r3,0 #Sucess!!!
> +1:> 	> blr
> +
> +FUNC_START(test_fpu)
> +> 	> #r3 holds pointer to where to put the result of fork

#r4 seems to hold a ptr to the pid

> +	#f14-f31 are non volatiles
> +> 	> PUSH_BASIC_STACK(256)
> +> 	> std> 	> r3,40(sp) #Address of darray
> +> 	> std r4,48(sp) #Address of pid
> +> 	> PUSH_FPU(56)
> +
> +> 	> bl load_fpu
> +> 	> nop
> +> 	> li> 	> r0,__NR_fork
> +> 	> sc
> +
> +> 	> #pass the result of the fork to the caller
> +> 	> ld> 	> r9,48(sp)
> +> 	> std> 	> r3,0(r9)
> +
> +> 	> ld r3,40(sp)
> +> 	> bl check_fpu
> +> 	> nop
> +
> +> 	> POP_FPU(56)
> +> 	> POP_BASIC_STACK(256)
> +> 	> blr
> +FUNC_END(test_fpu)
> diff --git a/tools/testing/selftests/powerpc/math/fpu_syscall.c b/tools/testing/selftests/powerpc/math/fpu_syscall.c
> new file mode 100644
> index 0000000..a967fd6
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/math/fpu_syscall.c
> @@ -0,0 +1,79 @@
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include "utils.h"
> +
> +extern int test_fpu(double *darray, pid_t *pid);
> +
> +double darray[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
> +> 	> 	>      1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
> +> 	> 	>      2.1};
> +
> +int syscall_fpu(void)
> +{
> +> 	> pid_t fork_pid;
> +> 	> int i;
> +> 	> int ret;
> +> 	> int child_ret;
> +> 	> for (i = 0; i < 1000; i++) {
> +> 	> 	> /* test_fpu will fork() */
> +> 	> 	> ret = test_fpu(darray, &fork_pid);
> +> 	> 	> if (fork_pid == -1)
> +> 	> 	> 	> return -1;
> +> 	> 	> if (fork_pid == 0)
> +> 	> 	> 	> exit(ret);
> +> 	> 	> waitpid(fork_pid, &child_ret, 0);
> +> 	> 	> if (ret || child_ret)
> +> 	> 	> 	> return 1;
> +> 	> }
> +
> +> 	> return 0;
> +}
> +
> +int test_syscall_fpu(void)
> +{
> +> 	> /*
> +> 	>  * Setup an environment with much context switching
> +> 	>  */
> +> 	> pid_t pid2;
> +> 	> pid_t pid = fork();
> +> 	> int ret;
> +> 	> int child_ret;
> +> 	> FAIL_IF(pid == -1);
> +
> +> 	> pid2 = fork();
> +> 	> /* Can't FAIL_IF(pid2 == -1); because already forked once */
> +> 	> if (pid2 == -1) {
> +> 	> 	> /*
> +> 	> 	>  * Couldn't fork, ensure test is a fail
> +> 	> 	>  */
> +> 	> 	> child_ret = ret = 1;
> +> 	> } else {
> +> 	> 	> ret = syscall_fpu();
> +> 	> 	> if (pid2)
> +> 	> 	> 	> waitpid(pid2, &child_ret, 0);
> +> 	> 	> else
> +> 	> 	> 	> exit(ret);
> +> 	> }
> +
> +> 	> ret |= child_ret;
> +
> +> 	> if (pid)
> +> 	> 	> waitpid(pid, &child_ret, 0);
> +> 	> else
> +> 	> 	> exit(ret);
> +
> +> 	> FAIL_IF(ret || child_ret);
> +> 	> return 0;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +> 	> return test_harness(test_syscall_fpu, "syscall_fpu");
> +
> +}
> diff --git a/tools/testing/selftests/powerpc/math/vmx_asm.S b/tools/testing/selftests/powerpc/math/vmx_asm.S
> new file mode 100644
> index 0000000..e642e67
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/math/vmx_asm.S
> @@ -0,0 +1,183 @@
> +#include "basic_asm.h"
> +
> +#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;
> +
> +#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)
> +
> +#Should be safe from C, only touches r4, r5 and v0,v1,v2
> +FUNC_START(check_vmx)
> +> 	> PUSH_BASIC_STACK(16)
> +> 	> mr r4,r3
> +> 	> li> 	> r3,1 #assume a bad result
> +> 	> li> 	> r5,0
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v20
> +> 	> vmr> 	> v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v21
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v22
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v23
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v24
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v25
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v26
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v27
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v28
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v29
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v30
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> addi> 	> r5,r5,16
> +> 	> lvx> 	> v0,r5,r4
> +> 	> vcmpequd.> 	> v1,v0,v31
> +> 	> vand> 	> v2,v2,v1
> +
> +> 	> li r5,0
> +> 	> stvx> 	> v2,r5,sp
> +> 	> ldx> 	> r0,r5,sp
> +> 	> cmpdi> 	> r0,0xffffffff
> +> 	> bne> 	> 1f
> +> 	> li> 	> r3,0
> +1:> 	> POP_BASIC_STACK(16)
> +> 	> blr
> +FUNC_END(check_vmx)
> +
> +#Safe from C
> +FUNC_START(test_vmx)
> +> 	> #r3 holds pointer to where to put the result of fork
> +> 	> #v20-v31 are non-volatile
> +> 	> PUSH_BASIC_STACK(512)
> +> 	> std> 	> r3,40(sp) #Address of varray
> +> 	> std r4,48(sp) #address of pid
> +> 	> PUSH_VMX(56, r4)
> +
> +> 	> bl load_vmx
> +
> +> 	> li> 	> r0,__NR_fork
> +> 	> sc
> +> 	> #Pass the result of fork back to the caller
> +> 	> ld> 	> r9,48(sp)
> +> 	> std> 	> r3,0(r9)
> +
> +> 	> ld r3,40(sp)
> +> 	> bl check_vmx
> +
> +> 	> POP_VMX(56,r4)
> +> 	> POP_BASIC_STACK(512)
> +> 	> blr
> +FUNC_END(test_vmx)
> diff --git a/tools/testing/selftests/powerpc/math/vmx_syscall.c b/tools/testing/selftests/powerpc/math/vmx_syscall.c
> new file mode 100644
> index 0000000..7adff05
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/math/vmx_syscall.c
> @@ -0,0 +1,81 @@
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include "utils.h"
> +
> +typedef int v4si __attribute__ ((vector_size (16)));
> +v4si varray[] = {{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}};
> +
> +extern int test_vmx(v4si *varray, pid_t *pid);
> +
> +int vmx_syscall(void)
> +{
> +> 	> pid_t fork_pid;
> +> 	> int i;
> +> 	> int ret;
> +> 	> int child_ret;
> +> 	> for (i = 0; i < 1000; i++) {
> +> 	> 	> /* test_vmx will fork() */
> +> 	> 	> ret = test_vmx(varray, &fork_pid);
> +> 	> 	> if (fork_pid == -1)
> +> 	> 	> 	> return -1;
> +> 	> 	> if (fork_pid == 0)
> +> 	> 	> 	> exit(ret);
> +> 	> 	> waitpid(fork_pid, &child_ret, 0);
> +> 	> 	> if (ret || child_ret)
> +> 	> 	> 	> return 1;
> +> 	> }
> +
> +> 	> return 0;
> +}
> +
> +int test_vmx_syscall(void)
> +{
> +> 	> /*
> +> 	>  * Setup an environment with much context switching
> +> 	>  */
> +> 	> pid_t pid2;
> +> 	> pid_t pid = fork();
> +> 	> int ret;
> +> 	> int child_ret;
> +> 	> FAIL_IF(pid == -1);
> +
> +> 	> pid2 = fork();
> +> 	> ret = vmx_syscall();
> +> 	> /* Can't FAIL_IF(pid2 == -1); because we've already forked */
> +> 	> if (pid2 == -1) {
> +> 	> 	> /*
> +> 	> 	>  * Couldn't fork, ensure child_ret is set and is a fail
> +> 	> 	>  */
> +> 	> 	> ret = child_ret = 1;
> +> 	> } else {
> +> 	> 	> if (pid2)
> +> 	> 	> 	> waitpid(pid2, &child_ret, 0);
> +> 	> 	> else
> +> 	> 	> 	> exit(ret);
> +> 	> }
> +
> +> 	> ret |= child_ret;
> +
> +> 	> if (pid)
> +> 	> 	> waitpid(pid, &child_ret, 0);
> +> 	> else
> +> 	> 	> exit(ret);
> +
> +> 	> FAIL_IF(ret || child_ret);
> +> 	> return 0;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +> 	> return test_harness(test_vmx_syscall, "vmx_syscall");
> +
> +}