diff mbox series

[v5,12/12] linux-user/aarch64: Add ESR signal frame for PACFAIL

Message ID 20230829232335.965414-13-richard.henderson@linaro.org
State New
Headers show
Series Implement Most ARMv8.3 Pointer Authentication Features | expand

Commit Message

Richard Henderson Aug. 29, 2023, 11:23 p.m. UTC
The PACFAIL fault uses ILL_ILLOPN and includes ESR.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/aarch64/cpu_loop.c |  7 ++++++-
 linux-user/aarch64/signal.c   |  6 ++++++
 tests/tcg/aarch64/pauth-2.c   | 25 ++++++++++++++++++++++++-
 3 files changed, 36 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index 22c9789326..5af17e8724 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -110,7 +110,12 @@  void cpu_loop(CPUARMState *env)
             /* just indicate that signals should be handled asap */
             break;
         case EXCP_UDEF:
-            force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
+            /* See kernel's do_el0_fpac, and our need_save_esr(). */
+            if (syn_get_ec(env->exception.syndrome) == EC_PACFAIL) {
+                force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
+            } else {
+                force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
+            }
             break;
         case EXCP_PREFETCH_ABORT:
         case EXCP_DATA_ABORT:
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
index 40a476c33e..375b8350f6 100644
--- a/linux-user/aarch64/signal.c
+++ b/linux-user/aarch64/signal.c
@@ -582,6 +582,7 @@  static bool need_save_esr(target_siginfo_t *info, CPUARMState *env)
 {
     int sig = info->si_signo;
     int type = info->si_code >> 16;
+    int code = info->si_code & 0xffff;
 
     if (type != QEMU_SI_FAULT) {
         return false;
@@ -596,6 +597,11 @@  static bool need_save_esr(target_siginfo_t *info, CPUARMState *env)
         return true;
     }
 
+    /* See arch/arm64/kernel/traps.c, do_el0_fpac, and our cpu_loop(). */
+    if (sig == TARGET_SIGILL && code == TARGET_ILL_ILLOPN) {
+        return true;
+    }
+
     return false;
 }
 
diff --git a/tests/tcg/aarch64/pauth-2.c b/tests/tcg/aarch64/pauth-2.c
index 89ffdbf1df..aaf7c4a19f 100644
--- a/tests/tcg/aarch64/pauth-2.c
+++ b/tests/tcg/aarch64/pauth-2.c
@@ -5,14 +5,37 @@ 
 #include "pauth.h"
 
 
+static inline struct _aarch64_ctx *first_ctx(ucontext_t *uc)
+{
+    return (struct _aarch64_ctx *)&uc->uc_mcontext.__reserved;
+}
+
+static inline struct _aarch64_ctx *next_ctx(struct _aarch64_ctx *hdr)
+{
+    return (struct _aarch64_ctx *)((char *)hdr + hdr->size);
+}
+
 static void sigill(int sig, siginfo_t *info, void *vuc)
 {
     ucontext_t *uc = vuc;
-    uint64_t test;
+    struct _aarch64_ctx *hdr;
+    struct esr_context *ec;
+    uint64_t test, esr;
 
     /* There is only one insn below that is allowed to fault. */
     asm volatile("adr %0, auth2_insn" : "=r"(test));
     assert(test == uc->uc_mcontext.pc);
+
+    /* Find the esr_context. */
+    for (hdr = first_ctx(uc); hdr->magic != ESR_MAGIC; hdr = next_ctx(hdr)) {
+        assert(hdr->magic != 0);
+    }
+
+    ec = (struct esr_context *)hdr;
+    esr = ec->esr;
+
+    assert((esr >> 26) == 0x1c); /* EC_PACFAIL */
+    assert((esr & 3) == 2);      /* AUTDA: data=1 key=0 */
     exit(0);
 }