diff mbox series

[3/3] linux-user/aarch64: Add ESR signal frame for PACFAIL

Message ID 20230822170209.1130173-4-richard.henderson@linaro.org
State Superseded
Headers show
Series linux-user/aarch64: Add ESR signal frame record | expand

Commit Message

Richard Henderson Aug. 22, 2023, 5:02 p.m. UTC
The PACFAIL fault uses ILL_ILLOPN and includes ESR.

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(-)

Comments

Peter Maydell Aug. 29, 2023, 2:46 p.m. UTC | #1
On Tue, 22 Aug 2023 at 18:02, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> The PACFAIL fault uses ILL_ILLOPN and includes ESR.
>
> 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 --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 b2280fa9e3..bcdd796cc2 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;
> @@ -592,6 +593,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;
> +    }

This works, but we'll need to do something else if the kernel adds
some other fault later that is reported as ILLOPN but without
an ESR record...

> +
>      return false;
>  }

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM
Richard Henderson Aug. 29, 2023, 9:04 p.m. UTC | #2
On 8/29/23 07:46, Peter Maydell wrote:
>> +    /* See arch/arm64/kernel/traps.c, do_el0_fpac, and our cpu_loop(). */
>> +    if (sig == TARGET_SIGILL && code == TARGET_ILL_ILLOPN) {
>> +        return true;
>> +    }
> 
> This works, but we'll need to do something else if the kernel adds
> some other fault later that is reported as ILLOPN but without
> an ESR record...

Yes.  I'm not happy about the separation in logic, but I can't think of a better way at 
present.


r~
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 b2280fa9e3..bcdd796cc2 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;
@@ -592,6 +593,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 d498d7dd8b..62b39af3d0 100644
--- a/tests/tcg/aarch64/pauth-2.c
+++ b/tests/tcg/aarch64/pauth-2.c
@@ -4,14 +4,37 @@ 
 #include <assert.h>
 #include <sys/auxv.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);
 }