18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (C) 2019 ARM Limited */ 38c2ecf20Sopenharmony_ci#include "testcases.h" 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_cistruct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic, 68c2ecf20Sopenharmony_ci size_t resv_sz, size_t *offset) 78c2ecf20Sopenharmony_ci{ 88c2ecf20Sopenharmony_ci size_t offs = 0; 98c2ecf20Sopenharmony_ci struct _aarch64_ctx *found = NULL; 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci if (!head || resv_sz < HDR_SZ) 128c2ecf20Sopenharmony_ci return found; 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci while (offs <= resv_sz - HDR_SZ && 158c2ecf20Sopenharmony_ci head->magic != magic && head->magic) { 168c2ecf20Sopenharmony_ci offs += head->size; 178c2ecf20Sopenharmony_ci head = GET_RESV_NEXT_HEAD(head); 188c2ecf20Sopenharmony_ci } 198c2ecf20Sopenharmony_ci if (head->magic == magic) { 208c2ecf20Sopenharmony_ci found = head; 218c2ecf20Sopenharmony_ci if (offset) 228c2ecf20Sopenharmony_ci *offset = offs; 238c2ecf20Sopenharmony_ci } 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci return found; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cibool validate_extra_context(struct extra_context *extra, char **err) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct _aarch64_ctx *term; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (!extra || !err) 338c2ecf20Sopenharmony_ci return false; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci fprintf(stderr, "Validating EXTRA...\n"); 368c2ecf20Sopenharmony_ci term = GET_RESV_NEXT_HEAD(&extra->head); 378c2ecf20Sopenharmony_ci if (!term || term->magic || term->size) { 388c2ecf20Sopenharmony_ci *err = "Missing terminator after EXTRA context"; 398c2ecf20Sopenharmony_ci return false; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci if (extra->datap & 0x0fUL) 428c2ecf20Sopenharmony_ci *err = "Extra DATAP misaligned"; 438c2ecf20Sopenharmony_ci else if (extra->size & 0x0fUL) 448c2ecf20Sopenharmony_ci *err = "Extra SIZE misaligned"; 458c2ecf20Sopenharmony_ci else if (extra->datap != (uint64_t)term + sizeof(*term)) 468c2ecf20Sopenharmony_ci *err = "Extra DATAP misplaced (not contiguous)"; 478c2ecf20Sopenharmony_ci if (*err) 488c2ecf20Sopenharmony_ci return false; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return true; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cibool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci bool terminated = false; 568c2ecf20Sopenharmony_ci size_t offs = 0; 578c2ecf20Sopenharmony_ci int flags = 0; 588c2ecf20Sopenharmony_ci struct extra_context *extra = NULL; 598c2ecf20Sopenharmony_ci struct _aarch64_ctx *head = 608c2ecf20Sopenharmony_ci (struct _aarch64_ctx *)uc->uc_mcontext.__reserved; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (!err) 638c2ecf20Sopenharmony_ci return false; 648c2ecf20Sopenharmony_ci /* Walk till the end terminator verifying __reserved contents */ 658c2ecf20Sopenharmony_ci while (head && !terminated && offs < resv_sz) { 668c2ecf20Sopenharmony_ci if ((uint64_t)head & 0x0fUL) { 678c2ecf20Sopenharmony_ci *err = "Misaligned HEAD"; 688c2ecf20Sopenharmony_ci return false; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci switch (head->magic) { 728c2ecf20Sopenharmony_ci case 0: 738c2ecf20Sopenharmony_ci if (head->size) 748c2ecf20Sopenharmony_ci *err = "Bad size for terminator"; 758c2ecf20Sopenharmony_ci else 768c2ecf20Sopenharmony_ci terminated = true; 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci case FPSIMD_MAGIC: 798c2ecf20Sopenharmony_ci if (flags & FPSIMD_CTX) 808c2ecf20Sopenharmony_ci *err = "Multiple FPSIMD_MAGIC"; 818c2ecf20Sopenharmony_ci else if (head->size != 828c2ecf20Sopenharmony_ci sizeof(struct fpsimd_context)) 838c2ecf20Sopenharmony_ci *err = "Bad size for fpsimd_context"; 848c2ecf20Sopenharmony_ci flags |= FPSIMD_CTX; 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci case ESR_MAGIC: 878c2ecf20Sopenharmony_ci if (head->size != sizeof(struct esr_context)) 888c2ecf20Sopenharmony_ci *err = "Bad size for esr_context"; 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci case SVE_MAGIC: 918c2ecf20Sopenharmony_ci if (flags & SVE_CTX) 928c2ecf20Sopenharmony_ci *err = "Multiple SVE_MAGIC"; 938c2ecf20Sopenharmony_ci else if (head->size != 948c2ecf20Sopenharmony_ci sizeof(struct sve_context)) 958c2ecf20Sopenharmony_ci *err = "Bad size for sve_context"; 968c2ecf20Sopenharmony_ci flags |= SVE_CTX; 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci case EXTRA_MAGIC: 998c2ecf20Sopenharmony_ci if (flags & EXTRA_CTX) 1008c2ecf20Sopenharmony_ci *err = "Multiple EXTRA_MAGIC"; 1018c2ecf20Sopenharmony_ci else if (head->size != 1028c2ecf20Sopenharmony_ci sizeof(struct extra_context)) 1038c2ecf20Sopenharmony_ci *err = "Bad size for extra_context"; 1048c2ecf20Sopenharmony_ci flags |= EXTRA_CTX; 1058c2ecf20Sopenharmony_ci extra = (struct extra_context *)head; 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci case KSFT_BAD_MAGIC: 1088c2ecf20Sopenharmony_ci /* 1098c2ecf20Sopenharmony_ci * This is a BAD magic header defined 1108c2ecf20Sopenharmony_ci * artificially by a testcase and surely 1118c2ecf20Sopenharmony_ci * unknown to the Kernel parse_user_sigframe(). 1128c2ecf20Sopenharmony_ci * It MUST cause a Kernel induced SEGV 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci *err = "BAD MAGIC !"; 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci default: 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * A still unknown Magic: potentially freshly added 1198c2ecf20Sopenharmony_ci * to the Kernel code and still unknown to the 1208c2ecf20Sopenharmony_ci * tests. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci fprintf(stdout, 1238c2ecf20Sopenharmony_ci "SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n", 1248c2ecf20Sopenharmony_ci head->magic); 1258c2ecf20Sopenharmony_ci break; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (*err) 1298c2ecf20Sopenharmony_ci return false; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci offs += head->size; 1328c2ecf20Sopenharmony_ci if (resv_sz < offs + sizeof(*head)) { 1338c2ecf20Sopenharmony_ci *err = "HEAD Overrun"; 1348c2ecf20Sopenharmony_ci return false; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (flags & EXTRA_CTX) 1388c2ecf20Sopenharmony_ci if (!validate_extra_context(extra, err)) 1398c2ecf20Sopenharmony_ci return false; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci head = GET_RESV_NEXT_HEAD(head); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (terminated && !(flags & FPSIMD_CTX)) { 1458c2ecf20Sopenharmony_ci *err = "Missing FPSIMD"; 1468c2ecf20Sopenharmony_ci return false; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return true; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * This function walks through the records inside the provided reserved area 1548c2ecf20Sopenharmony_ci * trying to find enough space to fit @need_sz bytes: if not enough space is 1558c2ecf20Sopenharmony_ci * available and an extra_context record is present, it throws away the 1568c2ecf20Sopenharmony_ci * extra_context record. 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci * It returns a pointer to a new header where it is possible to start storing 1598c2ecf20Sopenharmony_ci * our need_sz bytes. 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * @shead: points to the start of reserved area 1628c2ecf20Sopenharmony_ci * @need_sz: needed bytes 1638c2ecf20Sopenharmony_ci * @resv_sz: reserved area size in bytes 1648c2ecf20Sopenharmony_ci * @offset: if not null, this will be filled with the offset of the return 1658c2ecf20Sopenharmony_ci * head pointer from @shead 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * @return: pointer to a new head where to start storing need_sz bytes, or 1688c2ecf20Sopenharmony_ci * NULL if space could not be made available. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_cistruct _aarch64_ctx *get_starting_head(struct _aarch64_ctx *shead, 1718c2ecf20Sopenharmony_ci size_t need_sz, size_t resv_sz, 1728c2ecf20Sopenharmony_ci size_t *offset) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci size_t offs = 0; 1758c2ecf20Sopenharmony_ci struct _aarch64_ctx *head; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci head = get_terminator(shead, resv_sz, &offs); 1788c2ecf20Sopenharmony_ci /* not found a terminator...no need to update offset if any */ 1798c2ecf20Sopenharmony_ci if (!head) 1808c2ecf20Sopenharmony_ci return head; 1818c2ecf20Sopenharmony_ci if (resv_sz - offs < need_sz) { 1828c2ecf20Sopenharmony_ci fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n", 1838c2ecf20Sopenharmony_ci resv_sz - offs); 1848c2ecf20Sopenharmony_ci head = get_header(shead, EXTRA_MAGIC, resv_sz, &offs); 1858c2ecf20Sopenharmony_ci if (!head || resv_sz - offs < need_sz) { 1868c2ecf20Sopenharmony_ci fprintf(stderr, 1878c2ecf20Sopenharmony_ci "Failed to reclaim space on sigframe.\n"); 1888c2ecf20Sopenharmony_ci return NULL; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci fprintf(stderr, "Available space:%zd\n", resv_sz - offs); 1938c2ecf20Sopenharmony_ci if (offset) 1948c2ecf20Sopenharmony_ci *offset = offs; 1958c2ecf20Sopenharmony_ci return head; 1968c2ecf20Sopenharmony_ci} 197