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:
@@ -94,4 +94,12 @@
|
|||||||
PPC_LL r0, STACK_FRAME_LR_POS(%r1); \
|
PPC_LL r0, STACK_FRAME_LR_POS(%r1); \
|
||||||
mtlr r0;
|
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 */
|
#endif /* _SELFTESTS_POWERPC_BASIC_ASM_H */
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ $(TM_TESTS): CFLAGS += -I../tm -mhtm
|
|||||||
|
|
||||||
CFLAGS += -I../../../../../usr/include -fno-pie
|
CFLAGS += -I../../../../../usr/include -fno-pie
|
||||||
|
|
||||||
|
$(OUTPUT)/ptrace-gpr: ptrace-gpr.S
|
||||||
$(OUTPUT)/ptrace-pkey $(OUTPUT)/core-pkey: LDLIBS += -pthread
|
$(OUTPUT)/ptrace-pkey $(OUTPUT)/core-pkey: LDLIBS += -pthread
|
||||||
|
|
||||||
$(TEST_GEN_PROGS): ../harness.c ../utils.c ../lib/reg.S
|
$(TEST_GEN_PROGS): ../harness.c ../utils.c ../lib/reg.S
|
||||||
|
|||||||
52
tools/testing/selftests/powerpc/ptrace/ptrace-gpr.S
Normal file
52
tools/testing/selftests/powerpc/ptrace/ptrace-gpr.S
Normal 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
|
||||||
@@ -16,32 +16,27 @@ double a = FPR_1;
|
|||||||
double b = FPR_2;
|
double b = FPR_2;
|
||||||
double c = FPR_3;
|
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)
|
void gpr(void)
|
||||||
{
|
{
|
||||||
unsigned long gpr_buf[18];
|
unsigned long gpr_buf[32];
|
||||||
double fpr_buf[32];
|
double fpr_buf[32];
|
||||||
|
int i;
|
||||||
|
|
||||||
cptr = (int *)shmat(shm_id, NULL, 0);
|
cptr = (int *)shmat(shm_id, NULL, 0);
|
||||||
|
memset(gpr_buf, 0, sizeof(gpr_buf));
|
||||||
|
memset(fpr_buf, 0, sizeof(fpr_buf));
|
||||||
|
|
||||||
asm __volatile__(
|
for (i = 0; i < 32; i++) {
|
||||||
ASM_LOAD_GPR_IMMED(gpr_1)
|
gpr_buf[i] = GPR_1;
|
||||||
ASM_LOAD_FPR(flt_1)
|
fpr_buf[i] = a;
|
||||||
:
|
}
|
||||||
: [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"
|
|
||||||
);
|
|
||||||
|
|
||||||
cptr[1] = 1;
|
gpr_child_loop(&cptr[0], &cptr[1], gpr_buf, fpr_buf);
|
||||||
|
|
||||||
while (!cptr[0])
|
|
||||||
asm volatile("" : : : "memory");
|
|
||||||
|
|
||||||
shmdt((void *)cptr);
|
shmdt((void *)cptr);
|
||||||
store_gpr(gpr_buf);
|
|
||||||
store_fpr(fpr_buf);
|
|
||||||
|
|
||||||
if (validate_gpr(gpr_buf, GPR_3))
|
if (validate_gpr(gpr_buf, GPR_3))
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user