Path: blob/master/tools/testing/selftests/arm64/signal/testcases/testcases.c
26295 views
// SPDX-License-Identifier: GPL-2.01/* Copyright (C) 2019 ARM Limited */23#include <ctype.h>4#include <string.h>56#include "testcases.h"78bool validate_extra_context(struct extra_context *extra, char **err,9void **extra_data, size_t *extra_size)10{11struct _aarch64_ctx *term;1213if (!extra || !err)14return false;1516fprintf(stderr, "Validating EXTRA...\n");17term = GET_RESV_NEXT_HEAD(&extra->head);18if (!term || term->magic || term->size) {19*err = "Missing terminator after EXTRA context";20return false;21}22if (extra->datap & 0x0fUL)23*err = "Extra DATAP misaligned";24else if (extra->size & 0x0fUL)25*err = "Extra SIZE misaligned";26else if (extra->datap != (uint64_t)term + 0x10UL)27*err = "Extra DATAP misplaced (not contiguous)";28if (*err)29return false;3031*extra_data = (void *)extra->datap;32*extra_size = extra->size;3334return true;35}3637bool validate_sve_context(struct sve_context *sve, char **err)38{39/* Size will be rounded up to a multiple of 16 bytes */40size_t regs_size41= ((SVE_SIG_CONTEXT_SIZE(sve_vq_from_vl(sve->vl)) + 15) / 16) * 16;4243if (!sve || !err)44return false;4546/* Either a bare sve_context or a sve_context followed by regs data */47if ((sve->head.size != sizeof(struct sve_context)) &&48(sve->head.size != regs_size)) {49*err = "bad size for SVE context";50return false;51}5253if (!sve_vl_valid(sve->vl)) {54*err = "SVE VL invalid";5556return false;57}5859return true;60}6162bool validate_za_context(struct za_context *za, char **err)63{64/* Size will be rounded up to a multiple of 16 bytes */65size_t regs_size66= ((ZA_SIG_CONTEXT_SIZE(sve_vq_from_vl(za->vl)) + 15) / 16) * 16;6768if (!za || !err)69return false;7071/* Either a bare za_context or a za_context followed by regs data */72if ((za->head.size != sizeof(struct za_context)) &&73(za->head.size != regs_size)) {74*err = "bad size for ZA context";75return false;76}7778if (!sve_vl_valid(za->vl)) {79*err = "SME VL in ZA context invalid";8081return false;82}8384return true;85}8687bool validate_zt_context(struct zt_context *zt, char **err)88{89if (!zt || !err)90return false;9192/* If the context is present there should be at least one register */93if (zt->nregs == 0) {94*err = "no registers";95return false;96}9798/* Size should agree with the number of registers */99if (zt->head.size != ZT_SIG_CONTEXT_SIZE(zt->nregs)) {100*err = "register count does not match size";101return false;102}103104return true;105}106107bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)108{109bool terminated = false;110size_t offs = 0;111int flags = 0;112int new_flags, i;113struct extra_context *extra = NULL;114struct sve_context *sve = NULL;115struct za_context *za = NULL;116struct zt_context *zt = NULL;117struct _aarch64_ctx *head =118(struct _aarch64_ctx *)uc->uc_mcontext.__reserved;119void *extra_data = NULL;120size_t extra_sz = 0;121char magic[4];122123if (!err)124return false;125/* Walk till the end terminator verifying __reserved contents */126while (head && !terminated && offs < resv_sz) {127if ((uint64_t)head & 0x0fUL) {128*err = "Misaligned HEAD";129return false;130}131132new_flags = 0;133134switch (head->magic) {135case 0:136if (head->size) {137*err = "Bad size for terminator";138} else if (extra_data) {139/* End of main data, walking the extra data */140head = extra_data;141resv_sz = extra_sz;142offs = 0;143144extra_data = NULL;145extra_sz = 0;146continue;147} else {148terminated = true;149}150break;151case FPSIMD_MAGIC:152if (flags & FPSIMD_CTX)153*err = "Multiple FPSIMD_MAGIC";154else if (head->size !=155sizeof(struct fpsimd_context))156*err = "Bad size for fpsimd_context";157new_flags |= FPSIMD_CTX;158break;159case ESR_MAGIC:160if (head->size != sizeof(struct esr_context))161*err = "Bad size for esr_context";162break;163case POE_MAGIC:164if (head->size != sizeof(struct poe_context))165*err = "Bad size for poe_context";166break;167case TPIDR2_MAGIC:168if (head->size != sizeof(struct tpidr2_context))169*err = "Bad size for tpidr2_context";170break;171case SVE_MAGIC:172if (flags & SVE_CTX)173*err = "Multiple SVE_MAGIC";174/* Size is validated in validate_sve_context() */175sve = (struct sve_context *)head;176new_flags |= SVE_CTX;177break;178case ZA_MAGIC:179if (flags & ZA_CTX)180*err = "Multiple ZA_MAGIC";181/* Size is validated in validate_za_context() */182za = (struct za_context *)head;183new_flags |= ZA_CTX;184break;185case ZT_MAGIC:186if (flags & ZT_CTX)187*err = "Multiple ZT_MAGIC";188/* Size is validated in validate_za_context() */189zt = (struct zt_context *)head;190new_flags |= ZT_CTX;191break;192case FPMR_MAGIC:193if (flags & FPMR_CTX)194*err = "Multiple FPMR_MAGIC";195else if (head->size !=196sizeof(struct fpmr_context))197*err = "Bad size for fpmr_context";198new_flags |= FPMR_CTX;199break;200case GCS_MAGIC:201if (flags & GCS_CTX)202*err = "Multiple GCS_MAGIC";203if (head->size != sizeof(struct gcs_context))204*err = "Bad size for gcs_context";205new_flags |= GCS_CTX;206break;207case EXTRA_MAGIC:208if (flags & EXTRA_CTX)209*err = "Multiple EXTRA_MAGIC";210else if (head->size !=211sizeof(struct extra_context))212*err = "Bad size for extra_context";213new_flags |= EXTRA_CTX;214extra = (struct extra_context *)head;215break;216case KSFT_BAD_MAGIC:217/*218* This is a BAD magic header defined219* artificially by a testcase and surely220* unknown to the Kernel parse_user_sigframe().221* It MUST cause a Kernel induced SEGV222*/223*err = "BAD MAGIC !";224break;225default:226/*227* A still unknown Magic: potentially freshly added228* to the Kernel code and still unknown to the229* tests. Magic numbers are supposed to be allocated230* as somewhat meaningful ASCII strings so try to231* print as such as well as the raw number.232*/233memcpy(magic, &head->magic, sizeof(magic));234for (i = 0; i < sizeof(magic); i++)235if (!isalnum(magic[i]))236magic[i] = '?';237238fprintf(stdout,239"SKIP Unknown MAGIC: 0x%X (%c%c%c%c) - Is KSFT arm64/signal up to date ?\n",240head->magic,241magic[3], magic[2], magic[1], magic[0]);242break;243}244245if (*err)246return false;247248offs += head->size;249if (resv_sz < offs + sizeof(*head)) {250*err = "HEAD Overrun";251return false;252}253254if (new_flags & EXTRA_CTX)255if (!validate_extra_context(extra, err,256&extra_data, &extra_sz))257return false;258if (new_flags & SVE_CTX)259if (!validate_sve_context(sve, err))260return false;261if (new_flags & ZA_CTX)262if (!validate_za_context(za, err))263return false;264if (new_flags & ZT_CTX)265if (!validate_zt_context(zt, err))266return false;267268flags |= new_flags;269270head = GET_RESV_NEXT_HEAD(head);271}272273if (terminated && !(flags & FPSIMD_CTX)) {274*err = "Missing FPSIMD";275return false;276}277278if (terminated && (flags & ZT_CTX) && !(flags & ZA_CTX)) {279*err = "ZT context but no ZA context";280return false;281}282283return true;284}285286/*287* This function walks through the records inside the provided reserved area288* trying to find enough space to fit @need_sz bytes: if not enough space is289* available and an extra_context record is present, it throws away the290* extra_context record.291*292* It returns a pointer to a new header where it is possible to start storing293* our need_sz bytes.294*295* @shead: points to the start of reserved area296* @need_sz: needed bytes297* @resv_sz: reserved area size in bytes298* @offset: if not null, this will be filled with the offset of the return299* head pointer from @shead300*301* @return: pointer to a new head where to start storing need_sz bytes, or302* NULL if space could not be made available.303*/304struct _aarch64_ctx *get_starting_head(struct _aarch64_ctx *shead,305size_t need_sz, size_t resv_sz,306size_t *offset)307{308size_t offs = 0;309struct _aarch64_ctx *head;310311head = get_terminator(shead, resv_sz, &offs);312/* not found a terminator...no need to update offset if any */313if (!head)314return head;315if (resv_sz - offs < need_sz) {316fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",317resv_sz - offs);318head = get_header(shead, EXTRA_MAGIC, resv_sz, &offs);319if (!head || resv_sz - offs < need_sz) {320fprintf(stderr,321"Failed to reclaim space on sigframe.\n");322return NULL;323}324}325326fprintf(stderr, "Available space:%zd\n", resv_sz - offs);327if (offset)328*offset = offs;329return head;330}331332333