| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2022 ARM Limited |
| * |
| * Verify that the TPIDR2 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_TPIDR2 "S3_3_C13_C0_5" |
| |
| static uint64_t get_tpidr2(void) |
| { |
| uint64_t val; |
| |
| asm volatile ( |
| "mrs %0, " SYS_TPIDR2 "\n" |
| : "=r"(val) |
| : |
| : "cc"); |
| |
| return val; |
| } |
| |
| int tpidr2_present(struct tdescr *td, siginfo_t *si, ucontext_t *uc) |
| { |
| struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context); |
| struct tpidr2_context *tpidr2_ctx; |
| size_t offset; |
| bool in_sigframe; |
| bool have_sme; |
| __u64 orig_tpidr2; |
| |
| have_sme = getauxval(AT_HWCAP2) & HWCAP2_SME; |
| if (have_sme) |
| orig_tpidr2 = get_tpidr2(); |
| |
| if (!get_current_context(td, &context.uc, sizeof(context))) |
| return 1; |
| |
| tpidr2_ctx = (struct tpidr2_context *) |
| get_header(head, TPIDR2_MAGIC, td->live_sz, &offset); |
| |
| in_sigframe = tpidr2_ctx != NULL; |
| |
| fprintf(stderr, "TPIDR2 sigframe %s on system %s SME\n", |
| in_sigframe ? "present" : "absent", |
| have_sme ? "with" : "without"); |
| |
| td->pass = (in_sigframe == have_sme); |
| |
| /* |
| * Check that the value we read back was the one present at |
| * the time that the signal was triggered. TPIDR2 is owned by |
| * libc so we can't safely choose the value and it is possible |
| * that we may need to revisit this in future if something |
| * starts deciding to set a new TPIDR2 between us reading and |
| * the signal. |
| */ |
| if (have_sme && tpidr2_ctx) { |
| if (tpidr2_ctx->tpidr2 != orig_tpidr2) { |
| fprintf(stderr, "TPIDR2 in frame is %llx, was %llx\n", |
| tpidr2_ctx->tpidr2, orig_tpidr2); |
| td->pass = false; |
| } |
| } |
| |
| return 0; |
| } |
| |
| struct tdescr tde = { |
| .name = "TPIDR2", |
| .descr = "Validate that TPIDR2 is present as expected", |
| .timeout = 3, |
| .run = tpidr2_present, |
| }; |