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

kselftest/arm64: signal: Add SME signal handling tests



Add test cases for the SME signal handing ABI patterned off the SVE tests.
Due to the small size of the tests and the differences in ABI (especially
around needing to account for both streaming SVE and ZA) there is some code
duplication here.

We currently cover:
 - Reporting of the vector length.
 - Lack of support for changing vector length.
 - Presence and size of register state for streaming SVE and ZA.

As with the SVE tests we do not yet have any validation of register
contents.

Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Reviewed-by: default avatarShuah Khan <skhan@linuxfoundation.org>
Acked-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20220419112247.711548-36-broonie@kernel.org


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 5aa45cc5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
mangle_*
fake_sigreturn_*
sme_*
ssve_*
sve_*
za_*
!*.[ch]
+4 −0
Original line number Diff line number Diff line
@@ -34,11 +34,15 @@
enum {
	FSSBS_BIT,
	FSVE_BIT,
	FSME_BIT,
	FSME_FA64_BIT,
	FMAX_END
};

#define FEAT_SSBS		(1UL << FSSBS_BIT)
#define FEAT_SVE		(1UL << FSVE_BIT)
#define FEAT_SME		(1UL << FSME_BIT)
#define FEAT_SME_FA64		(1UL << FSME_FA64_BIT)

/*
 * A descriptor used to describe and configure a test case.
+6 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ static int sig_copyctx = SIGTRAP;
static char const *const feats_names[FMAX_END] = {
	" SSBS ",
	" SVE ",
	" SME ",
	" FA64 ",
};

#define MAX_FEATS_SZ	128
@@ -268,6 +270,10 @@ int test_init(struct tdescr *td)
			td->feats_supported |= FEAT_SSBS;
		if (getauxval(AT_HWCAP) & HWCAP_SVE)
			td->feats_supported |= FEAT_SVE;
		if (getauxval(AT_HWCAP2) & HWCAP2_SME)
			td->feats_supported |= FEAT_SME;
		if (getauxval(AT_HWCAP2) & HWCAP2_SME_FA64)
			td->feats_supported |= FEAT_SME_FA64;
		if (feats_ok(td)) {
			if (td->feats_required & td->feats_supported)
				fprintf(stderr,
+92 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2021 ARM Limited
 *
 * Attempt to change the streaming SVE vector length in a signal
 * handler, this is not supported and is expected to segfault.
 */

#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>

#include "test_signals_utils.h"
#include "testcases.h"

struct fake_sigframe sf;
static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0;

static bool sme_get_vls(struct tdescr *td)
{
	int vq, vl;

	/*
	 * Enumerate up to SVE_VQ_MAX vector lengths
	 */
	for (vq = SVE_VQ_MAX; vq > 0; --vq) {
		vl = prctl(PR_SVE_SET_VL, vq * 16);
		if (vl == -1)
			return false;

		vl &= PR_SME_VL_LEN_MASK;

		/* Skip missing VLs */
		vq = sve_vq_from_vl(vl);

		vls[nvls++] = vl;
	}

	/* We need at least two VLs */
	if (nvls < 2) {
		fprintf(stderr, "Only %d VL supported\n", nvls);
		return false;
	}

	return true;
}

static int fake_sigreturn_ssve_change_vl(struct tdescr *td,
					 siginfo_t *si, ucontext_t *uc)
{
	size_t resv_sz, offset;
	struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf);
	struct sve_context *sve;

	/* Get a signal context with a SME ZA frame in it */
	if (!get_current_context(td, &sf.uc))
		return 1;

	resv_sz = GET_SF_RESV_SIZE(sf);
	head = get_header(head, SVE_MAGIC, resv_sz, &offset);
	if (!head) {
		fprintf(stderr, "No SVE context\n");
		return 1;
	}

	if (head->size != sizeof(struct sve_context)) {
		fprintf(stderr, "Register data present, aborting\n");
		return 1;
	}

	sve = (struct sve_context *)head;

	/* No changes are supported; init left us at minimum VL so go to max */
	fprintf(stderr, "Attempting to change VL from %d to %d\n",
		sve->vl, vls[0]);
	sve->vl = vls[0];

	fake_sigreturn(&sf, sizeof(sf), 0);

	return 1;
}

struct tdescr tde = {
	.name = "FAKE_SIGRETURN_SSVE_CHANGE",
	.descr = "Attempt to change Streaming SVE VL",
	.feats_required = FEAT_SME,
	.sig_ok = SIGSEGV,
	.timeout = 3,
	.init = sme_get_vls,
	.run = fake_sigreturn_ssve_change_vl,
};
+38 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2021 ARM Limited
 *
 * Verify that using a streaming mode instruction without enabling it
 * generates a SIGILL.
 */

#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>

#include "test_signals_utils.h"
#include "testcases.h"

int sme_trap_no_sm_trigger(struct tdescr *td)
{
	/* SMSTART ZA ; ADDHA ZA0.S, P0/M, P0/M, Z0.S */
	asm volatile(".inst 0xd503457f ; .inst 0xc0900000");

	return 0;
}

int sme_trap_no_sm_run(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
{
	return 1;
}

struct tdescr tde = {
	.name = "SME trap without SM",
	.descr = "Check that we get a SIGILL if we use streaming mode without enabling it",
	.timeout = 3,
	.feats_required = FEAT_SME,   /* We need a SMSTART ZA */
	.sanity_disabled = true,
	.trigger = sme_trap_no_sm_trigger,
	.run = sme_trap_no_sm_run,
	.sig_ok = SIGILL,
};
Loading