Message ID | 1447817215-15804-2-git-send-email-cyrilbur@gmail.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
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 <cyrilbur@gmail.com> > --- > 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"); > + > +}
On Mon, 23 Nov 2015 11:23:13 +1100 Michael Neuling <mikey@neuling.org> 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 <cyrilbur@gmail.com> > > --- > > 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"); > > + > > +}
On Mon, 2015-11-23 at 11:58 +1100, Cyril Bur wrote: > On Mon, 23 Nov 2015 11:23:13 +1100 > Michael Neuling <mikey@neuling.org> 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? The hardware can run with FP and VMX off and VSX on but we should never do that in Linux. Mikey
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 + +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 @@ -0,0 +1,26 @@ +#include <ppc-asm.h> +#include <asm/unistd.h> + +#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 + #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 <stdio.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> + +#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 <stdio.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> + +#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"); + +}
Test that the non volatile floating point and Altivec registers get correctly preserved across the fork() syscall. fork() works nicely for this purpose, the registers should be the same for both parent and child Signed-off-by: Cyril Bur <cyrilbur@gmail.com> --- 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