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

kselftest/arm64: Test FPSIMD format data writes via NT_ARM_SVE in fp-ptrace



The NT_ARM_SVE register set supports two data formats, the native SVE one
and an alternative format where we embed a copy of user_fpsimd_data as used
for NT_PRFPREG in the SVE register set. The register data is set as for a
write to NT_PRFPREG and changes in vector length and streaming mode are
handled as for any NT_ARM_SVE write. This has not previously been tested by
fp-ptrace, add coverage of it.

We do not support writes in FPSIMD format for NT_ARM_SSVE so we skip the
test for anything that would leave us in streaming mode.

Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20250718-arm64-fp-ptrace-sve-fpsimd-v1-1-7ecda32aa297@kernel.org


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent b5cebb5d
Loading
Loading
Loading
Loading
+64 −2
Original line number Diff line number Diff line
@@ -1066,6 +1066,23 @@ static bool sve_write_supported(struct test_config *config)
	return true;
}

static bool sve_write_fpsimd_supported(struct test_config *config)
{
	if (!sve_supported())
		return false;

	if ((config->svcr_in & SVCR_ZA) != (config->svcr_expected & SVCR_ZA))
		return false;

	if (config->svcr_expected & SVCR_SM)
		return false;

	if (config->sme_vl_in != config->sme_vl_expected)
		return false;

	return true;
}

static void fpsimd_write_expected(struct test_config *config)
{
	int vl;
@@ -1152,7 +1169,7 @@ static void sve_write_expected(struct test_config *config)
	}
}

static void sve_write(pid_t child, struct test_config *config)
static void sve_write_sve(pid_t child, struct test_config *config)
{
	struct user_sve_header *sve;
	struct iovec iov;
@@ -1195,6 +1212,45 @@ static void sve_write(pid_t child, struct test_config *config)
	free(iov.iov_base);
}

static void sve_write_fpsimd(pid_t child, struct test_config *config)
{
	struct user_sve_header *sve;
	struct user_fpsimd_state *fpsimd;
	struct iovec iov;
	int ret, vl, vq;

	vl = vl_expected(config);
	vq = __sve_vq_from_vl(vl);

	if (!vl)
		return;

	iov.iov_len = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq,
							  SVE_PT_REGS_FPSIMD);
	iov.iov_base = malloc(iov.iov_len);
	if (!iov.iov_base) {
		ksft_print_msg("Failed allocating %lu byte SVE write buffer\n",
			       iov.iov_len);
		return;
	}
	memset(iov.iov_base, 0, iov.iov_len);

	sve = iov.iov_base;
	sve->size = iov.iov_len;
	sve->flags = SVE_PT_REGS_FPSIMD;
	sve->vl = vl;

	fpsimd = iov.iov_base + SVE_PT_REGS_OFFSET;
	memcpy(&fpsimd->vregs, v_expected, sizeof(v_expected));

	ret = ptrace(PTRACE_SETREGSET, child, NT_ARM_SVE, &iov);
	if (ret != 0)
		ksft_print_msg("Failed to write SVE: %s (%d)\n",
			       strerror(errno), errno);

	free(iov.iov_base);
}

static bool za_write_supported(struct test_config *config)
{
	if ((config->svcr_in & SVCR_SM) != (config->svcr_expected & SVCR_SM))
@@ -1386,7 +1442,13 @@ static struct test_definition sve_test_defs[] = {
		.name = "SVE write",
		.supported = sve_write_supported,
		.set_expected_values = sve_write_expected,
		.modify_values = sve_write,
		.modify_values = sve_write_sve,
	},
	{
		.name = "SVE write FPSIMD format",
		.supported = sve_write_fpsimd_supported,
		.set_expected_values = fpsimd_write_expected,
		.modify_values = sve_write_fpsimd,
	},
};