| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2023 ARM Limited |
| * |
| * Verify that the FPMR register context in signal frames is set up as |
| * expected. |
| */ |
| |
| #include <signal.h> |
| #include <ucontext.h> |
| #include <sys/auxv.h> |
| #include <sys/prctl.h> |
| #include <unistd.h> |
| #include <asm/sigcontext.h> |
| |
| #include "test_signals_utils.h" |
| #include "testcases.h" |
| |
| static union { |
| ucontext_t uc; |
| char buf[1024 * 128]; |
| } context; |
| |
| #define SYS_FPMR "S3_3_C4_C4_2" |
| |
| static uint64_t get_fpmr(void) |
| { |
| uint64_t val; |
| |
| asm volatile ( |
| "mrs %0, " SYS_FPMR "\n" |
| : "=r"(val) |
| : |
| : "cc"); |
| |
| return val; |
| } |
| |
| int fpmr_present(struct tdescr *td, siginfo_t *si, ucontext_t *uc) |
| { |
| struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context); |
| struct fpmr_context *fpmr_ctx; |
| size_t offset; |
| bool in_sigframe; |
| bool have_fpmr; |
| __u64 orig_fpmr; |
| |
| have_fpmr = getauxval(AT_HWCAP2) & HWCAP2_FPMR; |
| if (have_fpmr) |
| orig_fpmr = get_fpmr(); |
| |
| if (!get_current_context(td, &context.uc, sizeof(context))) |
| return 1; |
| |
| fpmr_ctx = (struct fpmr_context *) |
| get_header(head, FPMR_MAGIC, td->live_sz, &offset); |
| |
| in_sigframe = fpmr_ctx != NULL; |
| |
| fprintf(stderr, "FPMR sigframe %s on system %s FPMR\n", |
| in_sigframe ? "present" : "absent", |
| have_fpmr ? "with" : "without"); |
| |
| td->pass = (in_sigframe == have_fpmr); |
| |
| if (have_fpmr && fpmr_ctx) { |
| if (fpmr_ctx->fpmr != orig_fpmr) { |
| fprintf(stderr, "FPMR in frame is %llx, was %llx\n", |
| fpmr_ctx->fpmr, orig_fpmr); |
| td->pass = false; |
| } |
| } |
| |
| return 0; |
| } |
| |
| struct tdescr tde = { |
| .name = "FPMR", |
| .descr = "Validate that FPMR is present as expected", |
| .timeout = 3, |
| .run = fpmr_present, |
| }; |