Commit c745b15c authored by Mark Brown's avatar Mark Brown Committed by Catalin Marinas
Browse files

kselftest/arm64: Test that ptrace takes effect in the target process



While we have test coverage for the ptrace interface in our selftests
the current programs have a number of gaps. The testing is done per
regset so does not cover interactions and at no point do any of the
tests actually run the traced processes meaning that there is no
validation that anything we read or write corresponds to register values
the process actually sees. Let's add a new program which attempts to cover
these gaps.

Each test we do performs a single ptrace write. For each test we generate
some random initial register data in memory and then fork() and trace a
child. The child will load the generated data into the registers then
trigger a breakpoint. The parent waits for the breakpoint then reads the
entire child register state via ptrace, verifying that the values expected
were actually loaded by the child. It then does the write being tested
and resumes the child. Once resumed the child saves the register state
it sees to memory and executes another breakpoint. The parent uses
process_vm_readv() to get these values from the child and verifies that
the values were as expected before cleaning up the child.

We generate configurations with combinations of vector lengths and SVCR
values and then try every ptrace write which will implement the
transition we generated. In order to control execution time (especially
in emulation) we only cover the minimum and maximum VL for each of SVE
and SME, this will ensure we generate both increasing and decreasing
changes in vector length. In order to provide a baseline test we also
check the case where we resume the child without doing a ptrace write.

In order to simplify the generation of the test count for kselftest we
will report but skip a substantial number of tests that can't actually
be expressed via a single ptrace write, several times more than we
actually run. This is noisy and will add some overhead but is very much
simpler so is probably worth the tradeoff.

Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20240122-arm64-test-ptrace-regs-v1-1-0897f822d73e@kernel.org


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 54be6c6c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
fp-pidbench
fp-ptrace
fp-stress
fpsimd-test
rdvl-sme
+4 −1
Original line number Diff line number Diff line
@@ -5,7 +5,9 @@ top_srcdir = $(realpath ../../../../../)

CFLAGS += $(KHDR_INCLUDES)

TEST_GEN_PROGS := fp-stress \
TEST_GEN_PROGS := \
	fp-ptrace \
	fp-stress \
	sve-ptrace sve-probe-vls \
	vec-syscfg \
	za-fork za-ptrace
@@ -24,6 +26,7 @@ EXTRA_CLEAN += $(OUTPUT)/asm-utils.o $(OUTPUT)/rdvl.o $(OUTPUT)/za-fork-asm.o
# Build with nolibc to avoid effects due to libc's clone() support
$(OUTPUT)/fp-pidbench: fp-pidbench.S $(OUTPUT)/asm-utils.o
	$(CC) -nostdlib $^ -o $@
$(OUTPUT)/fp-ptrace: fp-ptrace.c fp-ptrace-asm.S
$(OUTPUT)/fpsimd-test: fpsimd-test.S $(OUTPUT)/asm-utils.o
	$(CC) -nostdlib $^ -o $@
$(OUTPUT)/rdvl-sve: rdvl-sve.c $(OUTPUT)/rdvl.o
+279 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2021-3 ARM Limited.
//
// Assembly portion of the FP ptrace test

//
// Load values from memory into registers, break on a breakpoint, then
// break on a further breakpoint
//

#include "fp-ptrace.h"
#include "sme-inst.h"

.arch_extension sve

// Load and save register values with pauses for ptrace
//
// x0 - SVE in use
// x1 - SME in use
// x2 - SME2 in use
// x3 - FA64 supported

.globl load_and_save
load_and_save:
	stp	x11, x12, [sp, #-0x10]!

	// This should be redundant in the SVE case
	ldr	x7, =v_in
	ldp	q0, q1, [x7]
	ldp	q2, q3, [x7, #16 * 2]
	ldp	q4, q5, [x7, #16 * 4]
	ldp	q6, q7, [x7, #16 * 6]
	ldp	q8, q9, [x7, #16 * 8]
	ldp	q10, q11, [x7, #16 * 10]
	ldp	q12, q13, [x7, #16 * 12]
	ldp	q14, q15, [x7, #16 * 14]
	ldp	q16, q17, [x7, #16 * 16]
	ldp	q18, q19, [x7, #16 * 18]
	ldp	q20, q21, [x7, #16 * 20]
	ldp	q22, q23, [x7, #16 * 22]
	ldp	q24, q25, [x7, #16 * 24]
	ldp	q26, q27, [x7, #16 * 26]
	ldp	q28, q29, [x7, #16 * 28]
	ldp	q30, q31, [x7, #16 * 30]

	// SME?
	cbz	x1, check_sve_in

	adrp	x7, svcr_in
	ldr	x7, [x7, :lo12:svcr_in]
	// SVCR is 0 by default, avoid triggering SME if not in use
	cbz	x7, check_sve_in
	msr	S3_3_C4_C2_2, x7

	// ZA?
	tbz	x7, #SVCR_ZA_SHIFT, check_sm_in
	rdsvl	11, 1
	mov	w12, #0
	ldr	x6, =za_in
1:	_ldr_za 12, 6
	add	x6, x6, x11
	add	x12, x12, #1
	cmp	x11, x12
	bne	1b

	// ZT?
	cbz	x2, check_sm_in
	adrp	x6, zt_in
	add	x6, x6, :lo12:zt_in
	_ldr_zt 6

	// In streaming mode?
check_sm_in:
	tbz	x7, #SVCR_SM_SHIFT, check_sve_in
	mov	x4, x3		// Load FFR if we have FA64
	b	load_sve

	// SVE?
check_sve_in:
	cbz	x0, wait_for_writes
	mov	x4, #1

load_sve:
	ldr	x7, =z_in
	ldr	z0, [x7, #0, MUL VL]
	ldr	z1, [x7, #1, MUL VL]
	ldr	z2, [x7, #2, MUL VL]
	ldr	z3, [x7, #3, MUL VL]
	ldr	z4, [x7, #4, MUL VL]
	ldr	z5, [x7, #5, MUL VL]
	ldr	z6, [x7, #6, MUL VL]
	ldr	z7, [x7, #7, MUL VL]
	ldr	z8, [x7, #8, MUL VL]
	ldr	z9, [x7, #9, MUL VL]
	ldr	z10, [x7, #10, MUL VL]
	ldr	z11, [x7, #11, MUL VL]
	ldr	z12, [x7, #12, MUL VL]
	ldr	z13, [x7, #13, MUL VL]
	ldr	z14, [x7, #14, MUL VL]
	ldr	z15, [x7, #15, MUL VL]
	ldr	z16, [x7, #16, MUL VL]
	ldr	z17, [x7, #17, MUL VL]
	ldr	z18, [x7, #18, MUL VL]
	ldr	z19, [x7, #19, MUL VL]
	ldr	z20, [x7, #20, MUL VL]
	ldr	z21, [x7, #21, MUL VL]
	ldr	z22, [x7, #22, MUL VL]
	ldr	z23, [x7, #23, MUL VL]
	ldr	z24, [x7, #24, MUL VL]
	ldr	z25, [x7, #25, MUL VL]
	ldr	z26, [x7, #26, MUL VL]
	ldr	z27, [x7, #27, MUL VL]
	ldr	z28, [x7, #28, MUL VL]
	ldr	z29, [x7, #29, MUL VL]
	ldr	z30, [x7, #30, MUL VL]
	ldr	z31, [x7, #31, MUL VL]

	// FFR is not present in base SME
	cbz	x4, 1f
	ldr	x7, =ffr_in
	ldr	p0, [x7]
	ldr	x7, [x7, #0]
	cbz	x7, 1f
	wrffr	p0.b
1:

	ldr	x7, =p_in
	ldr	p0, [x7, #0, MUL VL]
	ldr	p1, [x7, #1, MUL VL]
	ldr	p2, [x7, #2, MUL VL]
	ldr	p3, [x7, #3, MUL VL]
	ldr	p4, [x7, #4, MUL VL]
	ldr	p5, [x7, #5, MUL VL]
	ldr	p6, [x7, #6, MUL VL]
	ldr	p7, [x7, #7, MUL VL]
	ldr	p8, [x7, #8, MUL VL]
	ldr	p9, [x7, #9, MUL VL]
	ldr	p10, [x7, #10, MUL VL]
	ldr	p11, [x7, #11, MUL VL]
	ldr	p12, [x7, #12, MUL VL]
	ldr	p13, [x7, #13, MUL VL]
	ldr	p14, [x7, #14, MUL VL]
	ldr	p15, [x7, #15, MUL VL]

wait_for_writes:
	// Wait for the parent
	brk #0

	// Save values
	ldr	x7, =v_out
	stp	q0, q1, [x7]
	stp	q2, q3, [x7, #16 * 2]
	stp	q4, q5, [x7, #16 * 4]
	stp	q6, q7, [x7, #16 * 6]
	stp	q8, q9, [x7, #16 * 8]
	stp	q10, q11, [x7, #16 * 10]
	stp	q12, q13, [x7, #16 * 12]
	stp	q14, q15, [x7, #16 * 14]
	stp	q16, q17, [x7, #16 * 16]
	stp	q18, q19, [x7, #16 * 18]
	stp	q20, q21, [x7, #16 * 20]
	stp	q22, q23, [x7, #16 * 22]
	stp	q24, q25, [x7, #16 * 24]
	stp	q26, q27, [x7, #16 * 26]
	stp	q28, q29, [x7, #16 * 28]
	stp	q30, q31, [x7, #16 * 30]

	// SME?
	cbz	x1, check_sve_out

	rdsvl	11, 1
	adrp	x6, sme_vl_out
	str	x11, [x6, :lo12:sme_vl_out]

	mrs	x7, S3_3_C4_C2_2
	adrp	x6, svcr_out
	str	x7, [x6, :lo12:svcr_out]

	// ZA?
	tbz	x7, #SVCR_ZA_SHIFT, check_sm_out
	mov	w12, #0
	ldr	x6, =za_out
1:	_str_za 12, 6
	add	x6, x6, x11
	add	x12, x12, #1
	cmp	x11, x12
	bne	1b

	// ZT?
	cbz	x2, check_sm_out
	adrp	x6, zt_out
	add	x6, x6, :lo12:zt_out
	_str_zt 6

	// In streaming mode?
check_sm_out:
	tbz	x7, #SVCR_SM_SHIFT, check_sve_out
	mov	x4, x3				// FFR?
	b	read_sve

	// SVE?
check_sve_out:
	cbz	x0, wait_for_reads
	mov	x4, #1

	rdvl	x7, #1
	adrp	x6, sve_vl_out
	str	x7, [x6, :lo12:sve_vl_out]

read_sve:
	ldr	x7, =z_out
	str	z0, [x7, #0, MUL VL]
	str	z1, [x7, #1, MUL VL]
	str	z2, [x7, #2, MUL VL]
	str	z3, [x7, #3, MUL VL]
	str	z4, [x7, #4, MUL VL]
	str	z5, [x7, #5, MUL VL]
	str	z6, [x7, #6, MUL VL]
	str	z7, [x7, #7, MUL VL]
	str	z8, [x7, #8, MUL VL]
	str	z9, [x7, #9, MUL VL]
	str	z10, [x7, #10, MUL VL]
	str	z11, [x7, #11, MUL VL]
	str	z12, [x7, #12, MUL VL]
	str	z13, [x7, #13, MUL VL]
	str	z14, [x7, #14, MUL VL]
	str	z15, [x7, #15, MUL VL]
	str	z16, [x7, #16, MUL VL]
	str	z17, [x7, #17, MUL VL]
	str	z18, [x7, #18, MUL VL]
	str	z19, [x7, #19, MUL VL]
	str	z20, [x7, #20, MUL VL]
	str	z21, [x7, #21, MUL VL]
	str	z22, [x7, #22, MUL VL]
	str	z23, [x7, #23, MUL VL]
	str	z24, [x7, #24, MUL VL]
	str	z25, [x7, #25, MUL VL]
	str	z26, [x7, #26, MUL VL]
	str	z27, [x7, #27, MUL VL]
	str	z28, [x7, #28, MUL VL]
	str	z29, [x7, #29, MUL VL]
	str	z30, [x7, #30, MUL VL]
	str	z31, [x7, #31, MUL VL]

	ldr	x7, =p_out
	str	p0, [x7, #0, MUL VL]
	str	p1, [x7, #1, MUL VL]
	str	p2, [x7, #2, MUL VL]
	str	p3, [x7, #3, MUL VL]
	str	p4, [x7, #4, MUL VL]
	str	p5, [x7, #5, MUL VL]
	str	p6, [x7, #6, MUL VL]
	str	p7, [x7, #7, MUL VL]
	str	p8, [x7, #8, MUL VL]
	str	p9, [x7, #9, MUL VL]
	str	p10, [x7, #10, MUL VL]
	str	p11, [x7, #11, MUL VL]
	str	p12, [x7, #12, MUL VL]
	str	p13, [x7, #13, MUL VL]
	str	p14, [x7, #14, MUL VL]
	str	p15, [x7, #15, MUL VL]

	// Only save FFR if it exists
	cbz	x4, wait_for_reads
	ldr	x7, =ffr_out
	rdffr	p0.b
	str	p0, [x7]

wait_for_reads:
	// Wait for the parent
	brk #0

	// Ensure we don't leave ourselves in streaming mode
	cbz	x1, out
	msr	S3_3_C4_C2_2, xzr

out:
	ldp	x11, x12, [sp, #-0x10]
	ret
+1503 −0

File added.

Preview size limit exceeded, changes collapsed.

+13 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2021-3 ARM Limited.

#ifndef FP_PTRACE_H
#define FP_PTRACE_H

#define SVCR_SM_SHIFT 0
#define SVCR_ZA_SHIFT 1

#define SVCR_SM (1 << SVCR_SM_SHIFT)
#define SVCR_ZA (1 << SVCR_ZA_SHIFT)

#endif