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
This commit is contained in:
Michael Ellerman 2022-06-28 00:02:36 +10:00
parent 149a497d5f
commit 611e385087
4 changed files with 73 additions and 17 deletions

View file

@ -94,4 +94,12 @@
PPC_LL r0, STACK_FRAME_LR_POS(%r1); \
mtlr r0;
.macro OP_REGS op, reg_width, start_reg, end_reg, base_reg, base_reg_offset=0, skip=0
.set i, \start_reg
.rept (\end_reg - \start_reg + 1)
\op i, (\reg_width * (i - \skip) + \base_reg_offset)(\base_reg)
.set i, i + 1
.endr
.endm
#endif /* _SELFTESTS_POWERPC_BASIC_ASM_H */

View file

@ -35,6 +35,7 @@ $(TM_TESTS): CFLAGS += -I../tm -mhtm
CFLAGS += -I../../../../../usr/include -fno-pie
$(OUTPUT)/ptrace-gpr: ptrace-gpr.S
$(OUTPUT)/ptrace-pkey $(OUTPUT)/core-pkey: LDLIBS += -pthread
$(TEST_GEN_PROGS): ../harness.c ../utils.c ../lib/reg.S

View file

@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* test helper assembly functions
*
* Copyright (C) 2016 Simon Guo, IBM Corporation.
* Copyright 2022 Michael Ellerman, IBM Corporation.
*/
#include "basic_asm.h"
#define GPR_SIZE __SIZEOF_LONG__
#define FIRST_GPR 14
#define NUM_GPRS (32 - FIRST_GPR)
#define STACK_SIZE (NUM_GPRS * GPR_SIZE)
// gpr_child_loop(int *read_flag, int *write_flag,
// unsigned long *gpr_buf, double *fpr_buf);
FUNC_START(gpr_child_loop)
// r3 = read_flag
// r4 = write_flag
// r5 = gpr_buf
// r6 = fpr_buf
PUSH_BASIC_STACK(STACK_SIZE)
// Save non-volatile GPRs
OP_REGS PPC_STL, GPR_SIZE, FIRST_GPR, 31, %r1, STACK_FRAME_LOCAL(0, 0), FIRST_GPR
// Load GPRs with expected values
OP_REGS PPC_LL, GPR_SIZE, FIRST_GPR, 31, r5, 0, FIRST_GPR
// Load FPRs with expected values
OP_REGS lfd, 8, 0, 31, r6
// Signal to parent that we're ready
li r0, 1
stw r0, 0(r4)
// Wait for parent to finish
1: lwz r0, 0(r3)
cmpwi r0, 0
beq 1b // Loop while flag is zero
// Save GPRs back to caller buffer
OP_REGS PPC_STL, GPR_SIZE, FIRST_GPR, 31, r5, 0, FIRST_GPR
// Save FPRs
OP_REGS stfd, 8, 0, 31, r6
// Reload non-volatile GPRs
OP_REGS PPC_LL, GPR_SIZE, FIRST_GPR, 31, %r1, STACK_FRAME_LOCAL(0, 0), FIRST_GPR
POP_BASIC_STACK(STACK_SIZE)
blr

View file

@ -16,32 +16,27 @@ double a = FPR_1;
double b = FPR_2;
double c = FPR_3;
extern void gpr_child_loop(int *read_flag, int *write_flag,
unsigned long *gpr_buf, double *fpr_buf);
void gpr(void)
{
unsigned long gpr_buf[18];
unsigned long gpr_buf[32];
double fpr_buf[32];
int i;
cptr = (int *)shmat(shm_id, NULL, 0);
memset(gpr_buf, 0, sizeof(gpr_buf));
memset(fpr_buf, 0, sizeof(fpr_buf));
asm __volatile__(
ASM_LOAD_GPR_IMMED(gpr_1)
ASM_LOAD_FPR(flt_1)
:
: [gpr_1]"i"(GPR_1), [flt_1] "b" (&a)
: "memory", "r6", "r7", "r8", "r9", "r10",
"r11", "r12", "r13", "r14", "r15", "r16", "r17",
"r18", "r19", "r20", "r21", "r22", "r23", "r24",
"r25", "r26", "r27", "r28", "r29", "r30", "r31"
);
for (i = 0; i < 32; i++) {
gpr_buf[i] = GPR_1;
fpr_buf[i] = a;
}
cptr[1] = 1;
while (!cptr[0])
asm volatile("" : : : "memory");
gpr_child_loop(&cptr[0], &cptr[1], gpr_buf, fpr_buf);
shmdt((void *)cptr);
store_gpr(gpr_buf);
store_fpr(fpr_buf);
if (validate_gpr(gpr_buf, GPR_3))
exit(1);