Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/powerpc: Test FPU and VMX regs in signal ucontext

Load up the non volatile FPU and VMX regs and ensure that they are the
expected value in a signal handler

Signed-off-by: Cyril Bur <cyrilbur@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Cyril Bur and committed by
Michael Ellerman
48e8c571 e5ab8be6

+296 -1
+2
tools/testing/selftests/powerpc/math/.gitignore
··· 2 2 vmx_syscall 3 3 fpu_preempt 4 4 vmx_preempt 5 + fpu_signal 6 + vmx_signal
+3 -1
tools/testing/selftests/powerpc/math/Makefile
··· 1 - TEST_PROGS := fpu_syscall fpu_preempt vmx_syscall vmx_preempt 1 + TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal 2 2 3 3 all: $(TEST_PROGS) 4 4 ··· 7 7 8 8 fpu_syscall: fpu_asm.S 9 9 fpu_preempt: fpu_asm.S 10 + fpu_signal: fpu_asm.S 10 11 11 12 vmx_syscall: vmx_asm.S 12 13 vmx_preempt: vmx_asm.S 14 + vmx_signal: vmx_asm.S 13 15 14 16 include ../../lib.mk 15 17
+135
tools/testing/selftests/powerpc/math/fpu_signal.c
··· 1 + /* 2 + * Copyright 2015, Cyril Bur, IBM Corp. 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 7 + * 2 of the License, or (at your option) any later version. 8 + * 9 + * This test attempts to see if the FPU registers are correctly reported in a 10 + * signal context. Each worker just spins checking its FPU registers, at some 11 + * point a signal will interrupt it and C code will check the signal context 12 + * ensuring it is also the same. 13 + */ 14 + 15 + #include <stdio.h> 16 + #include <unistd.h> 17 + #include <sys/syscall.h> 18 + #include <sys/time.h> 19 + #include <sys/types.h> 20 + #include <sys/wait.h> 21 + #include <stdlib.h> 22 + #include <pthread.h> 23 + 24 + #include "utils.h" 25 + 26 + /* Number of times each thread should receive the signal */ 27 + #define ITERATIONS 10 28 + /* 29 + * Factor by which to multiply number of online CPUs for total number of 30 + * worker threads 31 + */ 32 + #define THREAD_FACTOR 8 33 + 34 + __thread double darray[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 35 + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 36 + 2.1}; 37 + 38 + bool bad_context; 39 + int threads_starting; 40 + int running; 41 + 42 + extern long preempt_fpu(double *darray, int *threads_starting, int *running); 43 + 44 + void signal_fpu_sig(int sig, siginfo_t *info, void *context) 45 + { 46 + int i; 47 + ucontext_t *uc = context; 48 + mcontext_t *mc = &uc->uc_mcontext; 49 + 50 + /* Only the non volatiles were loaded up */ 51 + for (i = 14; i < 32; i++) { 52 + if (mc->fp_regs[i] != darray[i - 14]) { 53 + bad_context = true; 54 + break; 55 + } 56 + } 57 + } 58 + 59 + void *signal_fpu_c(void *p) 60 + { 61 + int i; 62 + long rc; 63 + struct sigaction act; 64 + act.sa_sigaction = signal_fpu_sig; 65 + act.sa_flags = SA_SIGINFO; 66 + rc = sigaction(SIGUSR1, &act, NULL); 67 + if (rc) 68 + return p; 69 + 70 + srand(pthread_self()); 71 + for (i = 0; i < 21; i++) 72 + darray[i] = rand(); 73 + 74 + rc = preempt_fpu(darray, &threads_starting, &running); 75 + 76 + return (void *) rc; 77 + } 78 + 79 + int test_signal_fpu(void) 80 + { 81 + int i, j, rc, threads; 82 + void *rc_p; 83 + pthread_t *tids; 84 + 85 + threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR; 86 + tids = malloc(threads * sizeof(pthread_t)); 87 + FAIL_IF(!tids); 88 + 89 + running = true; 90 + threads_starting = threads; 91 + for (i = 0; i < threads; i++) { 92 + rc = pthread_create(&tids[i], NULL, signal_fpu_c, NULL); 93 + FAIL_IF(rc); 94 + } 95 + 96 + setbuf(stdout, NULL); 97 + printf("\tWaiting for all workers to start..."); 98 + while (threads_starting) 99 + asm volatile("": : :"memory"); 100 + printf("done\n"); 101 + 102 + printf("\tSending signals to all threads %d times...", ITERATIONS); 103 + for (i = 0; i < ITERATIONS; i++) { 104 + for (j = 0; j < threads; j++) { 105 + pthread_kill(tids[j], SIGUSR1); 106 + } 107 + sleep(1); 108 + } 109 + printf("done\n"); 110 + 111 + printf("\tStopping workers..."); 112 + running = 0; 113 + for (i = 0; i < threads; i++) { 114 + pthread_join(tids[i], &rc_p); 115 + 116 + /* 117 + * Harness will say the fail was here, look at why signal_fpu 118 + * returned 119 + */ 120 + if ((long) rc_p || bad_context) 121 + printf("oops\n"); 122 + if (bad_context) 123 + fprintf(stderr, "\t!! bad_context is true\n"); 124 + FAIL_IF((long) rc_p || bad_context); 125 + } 126 + printf("done\n"); 127 + 128 + free(tids); 129 + return 0; 130 + } 131 + 132 + int main(int argc, char *argv[]) 133 + { 134 + return test_harness(test_signal_fpu, "fpu_signal"); 135 + }
+156
tools/testing/selftests/powerpc/math/vmx_signal.c
··· 1 + /* 2 + * Copyright 2015, Cyril Bur, IBM Corp. 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 7 + * 2 of the License, or (at your option) any later version. 8 + * 9 + * This test attempts to see if the VMX registers are correctly reported in a 10 + * signal context. Each worker just spins checking its VMX registers, at some 11 + * point a signal will interrupt it and C code will check the signal context 12 + * ensuring it is also the same. 13 + */ 14 + 15 + #include <stdio.h> 16 + #include <unistd.h> 17 + #include <sys/syscall.h> 18 + #include <sys/time.h> 19 + #include <sys/types.h> 20 + #include <sys/wait.h> 21 + #include <stdlib.h> 22 + #include <string.h> 23 + #include <pthread.h> 24 + #include <altivec.h> 25 + 26 + #include "utils.h" 27 + 28 + /* Number of times each thread should receive the signal */ 29 + #define ITERATIONS 10 30 + /* 31 + * Factor by which to multiply number of online CPUs for total number of 32 + * worker threads 33 + */ 34 + #define THREAD_FACTOR 8 35 + 36 + __thread vector int varray[] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10,11,12}, 37 + {13,14,15,16},{17,18,19,20},{21,22,23,24}, 38 + {25,26,27,28},{29,30,31,32},{33,34,35,36}, 39 + {37,38,39,40},{41,42,43,44},{45,46,47,48}}; 40 + 41 + bool bad_context; 42 + int running; 43 + int threads_starting; 44 + 45 + extern int preempt_vmx(vector int *varray, int *threads_starting, int *sentinal); 46 + 47 + void signal_vmx_sig(int sig, siginfo_t *info, void *context) 48 + { 49 + int i; 50 + ucontext_t *uc = context; 51 + mcontext_t *mc = &uc->uc_mcontext; 52 + 53 + /* Only the non volatiles were loaded up */ 54 + for (i = 20; i < 32; i++) { 55 + if (memcmp(mc->v_regs->vrregs[i], &varray[i - 20], 16)) { 56 + int j; 57 + /* 58 + * Shouldn't printf() in a signal handler, however, this is a 59 + * test and we've detected failure. Understanding what failed 60 + * is paramount. All that happens after this is tests exit with 61 + * failure. 62 + */ 63 + printf("VMX mismatch at reg %d!\n", i); 64 + printf("Reg | Actual | Expected\n"); 65 + for (j = 20; j < 32; j++) { 66 + printf("%d | 0x%04x%04x%04x%04x | 0x%04x%04x%04x%04x\n", j, mc->v_regs->vrregs[j][0], 67 + mc->v_regs->vrregs[j][1], mc->v_regs->vrregs[j][2], mc->v_regs->vrregs[j][3], 68 + varray[j - 20][0], varray[j - 20][1], varray[j - 20][2], varray[j - 20][3]); 69 + } 70 + bad_context = true; 71 + break; 72 + } 73 + } 74 + } 75 + 76 + void *signal_vmx_c(void *p) 77 + { 78 + int i, j; 79 + long rc; 80 + struct sigaction act; 81 + act.sa_sigaction = signal_vmx_sig; 82 + act.sa_flags = SA_SIGINFO; 83 + rc = sigaction(SIGUSR1, &act, NULL); 84 + if (rc) 85 + return p; 86 + 87 + srand(pthread_self()); 88 + for (i = 0; i < 12; i++) 89 + for (j = 0; j < 4; j++) 90 + varray[i][j] = rand(); 91 + 92 + rc = preempt_vmx(varray, &threads_starting, &running); 93 + 94 + return (void *) rc; 95 + } 96 + 97 + int test_signal_vmx(void) 98 + { 99 + int i, j, rc, threads; 100 + void *rc_p; 101 + pthread_t *tids; 102 + 103 + threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR; 104 + tids = malloc(threads * sizeof(pthread_t)); 105 + FAIL_IF(!tids); 106 + 107 + running = true; 108 + threads_starting = threads; 109 + for (i = 0; i < threads; i++) { 110 + rc = pthread_create(&tids[i], NULL, signal_vmx_c, NULL); 111 + FAIL_IF(rc); 112 + } 113 + 114 + setbuf(stdout, NULL); 115 + printf("\tWaiting for %d workers to start... %d", threads, threads_starting); 116 + while (threads_starting) { 117 + asm volatile("": : :"memory"); 118 + usleep(1000); 119 + printf(", %d", threads_starting); 120 + } 121 + printf(" ...done\n"); 122 + 123 + printf("\tSending signals to all threads %d times...", ITERATIONS); 124 + for (i = 0; i < ITERATIONS; i++) { 125 + for (j = 0; j < threads; j++) { 126 + pthread_kill(tids[j], SIGUSR1); 127 + } 128 + sleep(1); 129 + } 130 + printf("done\n"); 131 + 132 + printf("\tKilling workers..."); 133 + running = 0; 134 + for (i = 0; i < threads; i++) { 135 + pthread_join(tids[i], &rc_p); 136 + 137 + /* 138 + * Harness will say the fail was here, look at why signal_vmx 139 + * returned 140 + */ 141 + if ((long) rc_p || bad_context) 142 + printf("oops\n"); 143 + if (bad_context) 144 + fprintf(stderr, "\t!! bad_context is true\n"); 145 + FAIL_IF((long) rc_p || bad_context); 146 + } 147 + printf("done\n"); 148 + 149 + free(tids); 150 + return 0; 151 + } 152 + 153 + int main(int argc, char *argv[]) 154 + { 155 + return test_harness(test_signal_vmx, "vmx_signal"); 156 + }