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 <cyril...@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"); > + > +} _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev