Now that the core utilities for signal testing support handling data in EXTRA_CONTEXT blocks we can test larger SVE and SME VLs which spill over the limits in the base signal context. This is done by defining storage for the context as a union with a ucontext_t and a buffer together with some helpers for getting relevant sizes and offsets like we do for fake_sigframe, this isn't the most lovely code ever but is fairly straightforward to implement and much less invasive to the somewhat unclear and indistinct layers of abstraction in the signal handling test code. Signed-off-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20220829160703.874492-11-broonie@kernel.org Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
111 lines
2.8 KiB
C
111 lines
2.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* Copyright (C) 2019 ARM Limited */
|
|
#ifndef __TESTCASES_H__
|
|
#define __TESTCASES_H__
|
|
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <ucontext.h>
|
|
#include <signal.h>
|
|
|
|
/* Architecture specific sigframe definitions */
|
|
#include <asm/sigcontext.h>
|
|
|
|
#define FPSIMD_CTX (1 << 0)
|
|
#define SVE_CTX (1 << 1)
|
|
#define ZA_CTX (1 << 2)
|
|
#define EXTRA_CTX (1 << 3)
|
|
|
|
#define KSFT_BAD_MAGIC 0xdeadbeef
|
|
|
|
#define HDR_SZ \
|
|
sizeof(struct _aarch64_ctx)
|
|
|
|
#define GET_SF_RESV_HEAD(sf) \
|
|
(struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
|
|
|
|
#define GET_SF_RESV_SIZE(sf) \
|
|
sizeof((sf).uc.uc_mcontext.__reserved)
|
|
|
|
#define GET_BUF_RESV_HEAD(buf) \
|
|
(struct _aarch64_ctx *)(&(buf).uc.uc_mcontext.__reserved)
|
|
|
|
#define GET_BUF_RESV_SIZE(buf) \
|
|
(sizeof(buf) - sizeof(buf.uc) + \
|
|
sizeof((buf).uc.uc_mcontext.__reserved))
|
|
|
|
#define GET_UCP_RESV_SIZE(ucp) \
|
|
sizeof((ucp)->uc_mcontext.__reserved)
|
|
|
|
#define ASSERT_BAD_CONTEXT(uc) do { \
|
|
char *err = NULL; \
|
|
if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) { \
|
|
if (err) \
|
|
fprintf(stderr, \
|
|
"Using badly built context - ERR: %s\n",\
|
|
err); \
|
|
} else { \
|
|
abort(); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define ASSERT_GOOD_CONTEXT(uc) do { \
|
|
char *err = NULL; \
|
|
if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) { \
|
|
if (err) \
|
|
fprintf(stderr, \
|
|
"Detected BAD context - ERR: %s\n", err);\
|
|
abort(); \
|
|
} else { \
|
|
fprintf(stderr, "uc context validated.\n"); \
|
|
} \
|
|
} while (0)
|
|
|
|
/*
|
|
* A simple record-walker for __reserved area: it walks through assuming
|
|
* only to find a proper struct __aarch64_ctx header descriptor.
|
|
*
|
|
* Instead it makes no assumptions on the content and ordering of the
|
|
* records, any needed bounds checking must be enforced by the caller
|
|
* if wanted: this way can be used by caller on any maliciously built bad
|
|
* contexts.
|
|
*
|
|
* head->size accounts both for payload and header _aarch64_ctx size !
|
|
*/
|
|
#define GET_RESV_NEXT_HEAD(h) \
|
|
(struct _aarch64_ctx *)((char *)(h) + (h)->size)
|
|
|
|
struct fake_sigframe {
|
|
siginfo_t info;
|
|
ucontext_t uc;
|
|
};
|
|
|
|
|
|
bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
|
|
|
|
struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
|
|
size_t resv_sz, size_t *offset);
|
|
|
|
static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
|
|
size_t resv_sz,
|
|
size_t *offset)
|
|
{
|
|
return get_header(head, 0, resv_sz, offset);
|
|
}
|
|
|
|
static inline void write_terminator_record(struct _aarch64_ctx *tail)
|
|
{
|
|
if (tail) {
|
|
tail->magic = 0;
|
|
tail->size = 0;
|
|
}
|
|
}
|
|
|
|
struct _aarch64_ctx *get_starting_head(struct _aarch64_ctx *shead,
|
|
size_t need_sz, size_t resv_sz,
|
|
size_t *offset);
|
|
#endif
|