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

From: Cyril Bur <[email-masked]>
Date: Mon, 23 Nov 2015 11:58:53 +1100

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

> 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.

Yeah, I'm sure I could get that wrong haha.

Hmmmm this got me thinking. Today we always enable FP and Altivec when we
enable VSX but isn't there a world where we could actually run with FP and
Altivec disabled and VSX on? In which case, is the whole thing volatile or
does the kernel still need to save the subset of the matrix which corresponds 
to non-volatile FPs and non-volatile Altivec?
> 
> 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.
> 

Yep

> > +
> > +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?
> 

Sure why not.

> > @@ -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
> 

Thanks

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