Commit 611e3850 authored by Michael Ellerman's avatar Michael Ellerman
Browse files

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: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220627140239.2464900-10-mpe@ellerman.id.au
parent 149a497d
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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 */
+1 −0
Original line number Diff line number Diff line
@@ -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
+52 −0
Original line number Diff line number Diff line
/* 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
+12 −17
Original line number Diff line number Diff line
@@ -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"
		);

	cptr[1] = 1;
	for (i = 0; i < 32; i++) {
		gpr_buf[i] = GPR_1;
		fpr_buf[i] = a;
	}

	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);