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

selftests/powerpc/ptrace: Do more of ptrace-gpr in asm

The ptrace-gpr test includes some inline asm to load GPR and FPR
registers. It then goes back to C to wait for the parent to trace it and
then checks register contents.

The split between inline asm and C is fragile, it relies on the compiler
not using any non-volatile GPRs after the inline asm block. It also
requires a very large and unwieldy inline asm block.

So convert the logic to set registers, wait, and store registers to a
single asm function, meaning there's no window for the compiler to
intervene.

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220627140239.2464900-10-mpe@ellerman.id.au

+73 -17
+8
tools/testing/selftests/powerpc/include/basic_asm.h
··· 94 94 PPC_LL r0, STACK_FRAME_LR_POS(%r1); \ 95 95 mtlr r0; 96 96 97 + .macro OP_REGS op, reg_width, start_reg, end_reg, base_reg, base_reg_offset=0, skip=0 98 + .set i, \start_reg 99 + .rept (\end_reg - \start_reg + 1) 100 + \op i, (\reg_width * (i - \skip) + \base_reg_offset)(\base_reg) 101 + .set i, i + 1 102 + .endr 103 + .endm 104 + 97 105 #endif /* _SELFTESTS_POWERPC_BASIC_ASM_H */
+1
tools/testing/selftests/powerpc/ptrace/Makefile
··· 35 35 36 36 CFLAGS += -I../../../../../usr/include -fno-pie 37 37 38 + $(OUTPUT)/ptrace-gpr: ptrace-gpr.S 38 39 $(OUTPUT)/ptrace-pkey $(OUTPUT)/core-pkey: LDLIBS += -pthread 39 40 40 41 $(TEST_GEN_PROGS): ../harness.c ../utils.c ../lib/reg.S
+52
tools/testing/selftests/powerpc/ptrace/ptrace-gpr.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * test helper assembly functions 4 + * 5 + * Copyright (C) 2016 Simon Guo, IBM Corporation. 6 + * Copyright 2022 Michael Ellerman, IBM Corporation. 7 + */ 8 + #include "basic_asm.h" 9 + 10 + #define GPR_SIZE __SIZEOF_LONG__ 11 + #define FIRST_GPR 14 12 + #define NUM_GPRS (32 - FIRST_GPR) 13 + #define STACK_SIZE (NUM_GPRS * GPR_SIZE) 14 + 15 + // gpr_child_loop(int *read_flag, int *write_flag, 16 + // unsigned long *gpr_buf, double *fpr_buf); 17 + FUNC_START(gpr_child_loop) 18 + // r3 = read_flag 19 + // r4 = write_flag 20 + // r5 = gpr_buf 21 + // r6 = fpr_buf 22 + PUSH_BASIC_STACK(STACK_SIZE) 23 + 24 + // Save non-volatile GPRs 25 + OP_REGS PPC_STL, GPR_SIZE, FIRST_GPR, 31, %r1, STACK_FRAME_LOCAL(0, 0), FIRST_GPR 26 + 27 + // Load GPRs with expected values 28 + OP_REGS PPC_LL, GPR_SIZE, FIRST_GPR, 31, r5, 0, FIRST_GPR 29 + 30 + // Load FPRs with expected values 31 + OP_REGS lfd, 8, 0, 31, r6 32 + 33 + // Signal to parent that we're ready 34 + li r0, 1 35 + stw r0, 0(r4) 36 + 37 + // Wait for parent to finish 38 + 1: lwz r0, 0(r3) 39 + cmpwi r0, 0 40 + beq 1b // Loop while flag is zero 41 + 42 + // Save GPRs back to caller buffer 43 + OP_REGS PPC_STL, GPR_SIZE, FIRST_GPR, 31, r5, 0, FIRST_GPR 44 + 45 + // Save FPRs 46 + OP_REGS stfd, 8, 0, 31, r6 47 + 48 + // Reload non-volatile GPRs 49 + OP_REGS PPC_LL, GPR_SIZE, FIRST_GPR, 31, %r1, STACK_FRAME_LOCAL(0, 0), FIRST_GPR 50 + 51 + POP_BASIC_STACK(STACK_SIZE) 52 + blr
+12 -17
tools/testing/selftests/powerpc/ptrace/ptrace-gpr.c
··· 16 16 double b = FPR_2; 17 17 double c = FPR_3; 18 18 19 + extern void gpr_child_loop(int *read_flag, int *write_flag, 20 + unsigned long *gpr_buf, double *fpr_buf); 21 + 19 22 void gpr(void) 20 23 { 21 - unsigned long gpr_buf[18]; 24 + unsigned long gpr_buf[32]; 22 25 double fpr_buf[32]; 26 + int i; 23 27 24 28 cptr = (int *)shmat(shm_id, NULL, 0); 29 + memset(gpr_buf, 0, sizeof(gpr_buf)); 30 + memset(fpr_buf, 0, sizeof(fpr_buf)); 25 31 26 - asm __volatile__( 27 - ASM_LOAD_GPR_IMMED(gpr_1) 28 - ASM_LOAD_FPR(flt_1) 29 - : 30 - : [gpr_1]"i"(GPR_1), [flt_1] "b" (&a) 31 - : "memory", "r6", "r7", "r8", "r9", "r10", 32 - "r11", "r12", "r13", "r14", "r15", "r16", "r17", 33 - "r18", "r19", "r20", "r21", "r22", "r23", "r24", 34 - "r25", "r26", "r27", "r28", "r29", "r30", "r31" 35 - ); 32 + for (i = 0; i < 32; i++) { 33 + gpr_buf[i] = GPR_1; 34 + fpr_buf[i] = a; 35 + } 36 36 37 - cptr[1] = 1; 38 - 39 - while (!cptr[0]) 40 - asm volatile("" : : : "memory"); 37 + gpr_child_loop(&cptr[0], &cptr[1], gpr_buf, fpr_buf); 41 38 42 39 shmdt((void *)cptr); 43 - store_gpr(gpr_buf); 44 - store_fpr(fpr_buf); 45 40 46 41 if (validate_gpr(gpr_buf, GPR_3)) 47 42 exit(1);