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

selftests/powerpc: Check all FPRs in fpu_preempt

There's a selftest that checks FPRs aren't corrupted by preemption, or
just process scheduling. However it only checks the non-volatile FPRs,
meaning corruption of the volatile FPRs could go undetected.

The check_fpu function it calls is used by several other tests, so for
now add a new routine to check all the FPRs. Increase the size of the
array of FPRs to 32, and initialise them all with random values.

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20231128132748.1990179-2-mpe@ellerman.id.au

+43 -13
+37 -4
tools/testing/selftests/powerpc/math/fpu_asm.S
··· 66 66 li r3,0 # Success!!! 67 67 1: blr 68 68 69 + 70 + // int check_all_fprs(double darray[32]) 71 + FUNC_START(check_all_fprs) 72 + PUSH_BASIC_STACK(8) 73 + mr r4, r3 // r4 = darray 74 + li r3, 1 // prepare for failure 75 + 76 + stfd f31, STACK_FRAME_LOCAL(0, 0)(sp) // backup f31 77 + 78 + // Check regs f0-f30, using f31 as scratch 79 + .set i, 0 80 + .rept 31 81 + lfd f31, (8 * i)(r4) // load expected value 82 + fcmpu cr0, i, f31 // compare 83 + bne cr0, 1f // bail if mismatch 84 + .set i, i + 1 85 + .endr 86 + 87 + lfd f31, STACK_FRAME_LOCAL(0, 0)(sp) // reload f31 88 + stfd f30, STACK_FRAME_LOCAL(0, 0)(sp) // backup f30 89 + 90 + lfd f30, (8 * 31)(r4) // load expected value of f31 91 + fcmpu cr0, f30, f31 // compare 92 + bne cr0, 1f // bail if mismatch 93 + 94 + lfd f30, STACK_FRAME_LOCAL(0, 0)(sp) // reload f30 95 + 96 + // Success 97 + li r3, 0 98 + 99 + 1: POP_BASIC_STACK(8) 100 + blr 101 + FUNC_END(check_all_fprs) 102 + 69 103 FUNC_START(test_fpu) 70 104 # r3 holds pointer to where to put the result of fork 71 105 # r4 holds pointer to the pid ··· 138 104 std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting 139 105 std r5,STACK_FRAME_PARAM(2)(sp) # int *running 140 106 141 - bl load_fpu 142 - nop 107 + // Load FPRs with expected values 108 + OP_REGS lfd, 8, 0, 31, r3 143 109 144 110 sync 145 111 # Atomic DEC ··· 150 116 bne- 1b 151 117 152 118 2: ld r3,STACK_FRAME_PARAM(0)(sp) 153 - bl check_fpu 154 - nop 119 + bl check_all_fprs 155 120 cmpdi r3,0 156 121 bne 3f 157 122 ld r4,STACK_FRAME_PARAM(2)(sp)
+6 -9
tools/testing/selftests/powerpc/math/fpu_preempt.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 2 /* 3 3 * Copyright 2015, Cyril Bur, IBM Corp. 4 + * Copyright 2023, Michael Ellerman, IBM Corp. 4 5 * 5 6 * This test attempts to see if the FPU registers change across preemption. 6 - * Two things should be noted here a) The check_fpu function in asm only checks 7 - * the non volatile registers as it is reused from the syscall test b) There is 8 - * no way to be sure preemption happened so this test just uses many threads 9 - * and a long wait. As such, a successful test doesn't mean much but a failure 10 - * is bad. 7 + * There is no way to be sure preemption happened so this test just uses many 8 + * threads and a long wait. As such, a successful test doesn't mean much but 9 + * a failure is bad. 11 10 */ 12 11 13 12 #include <stdio.h> ··· 29 30 #define THREAD_FACTOR 8 30 31 31 32 32 - __thread double darray[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 33 - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 34 - 2.1}; 33 + __thread double darray[32]; 35 34 36 35 int threads_starting; 37 36 int running; ··· 42 45 int i; 43 46 44 47 srand(pthread_self()); 45 - for (i = 0; i < 21; i++) 48 + for (i = 0; i < ARRAY_SIZE(darray); i++) 46 49 darray[i] = rand(); 47 50 48 51 rc = preempt_fpu(darray, &threads_starting, &running);