diff mbox series

[v4,1/9] tests/tcg/aarch64: Adjust pauth tests for FEAT_FPAC

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

Commit Message

Richard Henderson Aug. 22, 2023, 4:25 a.m. UTC
With FEAT_FPAC, AUT* instructions that fail authentication
do not produce an error value but instead fault.

For pauth-2, install a signal handler and verify it gets called.

For pauth-4 and pauth-5, we are explicitly testing the error value,
so there's nothing to test with FEAT_FPAC, so exit early.
Adjust the makefile to use -cpu neoverse-v1, which has FEAT_EPAC
but not FEAT_FPAC.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 tests/tcg/aarch64/pauth-2.c       | 61 +++++++++++++++++++++++++++----
 tests/tcg/aarch64/pauth-4.c       | 28 ++++++++++++--
 tests/tcg/aarch64/pauth-5.c       | 20 ++++++++++
 tests/tcg/aarch64/Makefile.target |  5 ++-
 4 files changed, 101 insertions(+), 13 deletions(-)

Comments

Peter Maydell Aug. 29, 2023, 12:52 p.m. UTC | #1
On Tue, 22 Aug 2023 at 05:27, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> With FEAT_FPAC, AUT* instructions that fail authentication
> do not produce an error value but instead fault.
>
> For pauth-2, install a signal handler and verify it gets called.
>
> For pauth-4 and pauth-5, we are explicitly testing the error value,
> so there's nothing to test with FEAT_FPAC, so exit early.
> Adjust the makefile to use -cpu neoverse-v1, which has FEAT_EPAC
> but not FEAT_FPAC.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  tests/tcg/aarch64/pauth-2.c       | 61 +++++++++++++++++++++++++++----
>  tests/tcg/aarch64/pauth-4.c       | 28 ++++++++++++--
>  tests/tcg/aarch64/pauth-5.c       | 20 ++++++++++
>  tests/tcg/aarch64/Makefile.target |  5 ++-
>  4 files changed, 101 insertions(+), 13 deletions(-)


>  int main()
>  {
> +    static const struct sigaction sa = {
> +        .sa_sigaction = sigill,
> +        .sa_flags = SA_SIGINFO
> +    };
> +    unsigned long isar1, isar2;
> +
> +    assert(getauxval(AT_HWCAP) & HWCAP_CPUID);
> +
> +    asm("mrs %0, id_aa64isar1_el1" : "=r"(isar1));
> +    asm("mrs %0, id_aa64isar2_el1" : "=r"(isar2));

You need to use the S3_n_Cn_Cn_n encoding for
ID_AA64ISAR2_EL1 in this test and the others,
to avoid problems with older binutils. Compare
how tests/tcg/aarch64/sysregs.c does it.

> diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
> index 681dfa077c..780ab3f183 100644
> --- a/tests/tcg/aarch64/Makefile.target
> +++ b/tests/tcg/aarch64/Makefile.target
> @@ -42,7 +42,10 @@ endif
>  ifneq ($(CROSS_CC_HAS_ARMV8_3),)
>  AARCH64_TESTS += pauth-1 pauth-2 pauth-4 pauth-5
>  pauth-%: CFLAGS += -march=armv8.3-a
> -run-pauth-%: QEMU_OPTS += -cpu max
> +run-pauth-1: QEMU_OPTS += -cpu max
> +run-pauth-2: QEMU_OPTS += -cpu max
> +run-pauth-4: QEMU_OPTS += -cpu neoverse-v1
> +run-pauth-5: QEMU_OPTS += -cpu neoverse-v1

Why do we need to specify neoverse-v1 here ? A comment
would help.

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

thanks
-- PMM
Richard Henderson Aug. 29, 2023, 10:05 p.m. UTC | #2
On 8/29/23 05:52, Peter Maydell wrote:
>> -run-pauth-%: QEMU_OPTS += -cpu max
>> +run-pauth-1: QEMU_OPTS += -cpu max
>> +run-pauth-2: QEMU_OPTS += -cpu max
>> +run-pauth-4: QEMU_OPTS += -cpu neoverse-v1
>> +run-pauth-5: QEMU_OPTS += -cpu neoverse-v1
> 
> Why do we need to specify neoverse-v1 here ? A comment
> would help.

neoverse-v1 has FEAT_EPAC, but not FEAT_FPAC.


r~
diff mbox series

Patch

diff --git a/tests/tcg/aarch64/pauth-2.c b/tests/tcg/aarch64/pauth-2.c
index 978652ede3..d498d7dd8b 100644
--- a/tests/tcg/aarch64/pauth-2.c
+++ b/tests/tcg/aarch64/pauth-2.c
@@ -1,5 +1,21 @@ 
 #include <stdint.h>
+#include <signal.h>
+#include <stdlib.h>
 #include <assert.h>
+#include <sys/auxv.h>
+
+static void sigill(int sig, siginfo_t *info, void *vuc)
+{
+    ucontext_t *uc = vuc;
+    uint64_t test;
+
+    /* 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);
+    exit(0);
+}
+
+static int pac_feature;
 
 void do_test(uint64_t value)
 {
@@ -27,31 +43,60 @@  void do_test(uint64_t value)
      * An invalid salt usually fails authorization, but again there
      * is a chance of choosing another salt that works.
      * Iterate until we find another salt which does fail.
+     *
+     * With FEAT_FPAC, this will SIGILL instead of producing a result.
      */
     for (salt2 = salt1 + 1; ; salt2++) {
-        asm volatile("autda %0, %2" : "=r"(decode) : "0"(encode), "r"(salt2));
+        asm volatile("auth2_insn: autda %0, %2"
+                     : "=r"(decode) : "0"(encode), "r"(salt2));
         if (decode != value) {
             break;
         }
     }
 
+    assert(pac_feature < 4);  /* No FEAT_FPAC */
+
     /* The VA bits, bit 55, and the TBI bits, should be unchanged.  */
     assert(((decode ^ value) & 0xff80ffffffffffffull) == 0);
 
     /*
-     * Bits [54:53] are an error indicator based on the key used;
-     * the DA key above is keynumber 0, so error == 0b01.  Otherwise
-     * bit 55 of the original is sign-extended into the rest of the auth.
+     * Without FEAT_Pauth2, bits [54:53] are an error indicator based on
+     * the key used; the DA key above is keynumber 0, so error == 0b01.
+     * Otherwise * bit 55 of the original is sign-extended into the rest
+     * of the auth.
      */
-    if ((value >> 55) & 1) {
-        assert(((decode >> 48) & 0xff) == 0b10111111);
-    } else {
-        assert(((decode >> 48) & 0xff) == 0b00100000);
+    if (pac_feature < 3) {
+        if ((value >> 55) & 1) {
+            assert(((decode >> 48) & 0xff) == 0b10111111);
+        } else {
+            assert(((decode >> 48) & 0xff) == 0b00100000);
+        }
     }
 }
 
 int main()
 {
+    static const struct sigaction sa = {
+        .sa_sigaction = sigill,
+        .sa_flags = SA_SIGINFO
+    };
+    unsigned long isar1, isar2;
+
+    assert(getauxval(AT_HWCAP) & HWCAP_CPUID);
+
+    asm("mrs %0, id_aa64isar1_el1" : "=r"(isar1));
+    asm("mrs %0, id_aa64isar2_el1" : "=r"(isar2));
+
+    pac_feature = ((isar1 >> 4) & 0xf)   /* APA */
+                | ((isar1 >> 8) & 0xf)   /* API */
+                | ((isar2 >> 12) & 0xf); /* APA3 */
+    assert(pac_feature != 0);
+
+    if (pac_feature >= 4) {
+        /* FEAT_FPAC */
+        sigaction(SIGILL, &sa, NULL);
+    }
+
     do_test(0);
     do_test(0xda004acedeadbeefull);
     return 0;
diff --git a/tests/tcg/aarch64/pauth-4.c b/tests/tcg/aarch64/pauth-4.c
index 24a639e36c..0d79ef21ea 100644
--- a/tests/tcg/aarch64/pauth-4.c
+++ b/tests/tcg/aarch64/pauth-4.c
@@ -2,14 +2,34 @@ 
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/auxv.h>
 
 #define TESTS 1000
 
 int main()
 {
+    char base[TESTS];
     int i, count = 0;
     float perc;
-    void *base = malloc(TESTS);
+    unsigned long isar1, isar2;
+    int pac_feature;
+
+    assert(getauxval(AT_HWCAP) & HWCAP_CPUID);
+
+    asm("mrs %0, id_aa64isar1_el1" : "=r"(isar1));
+    asm("mrs %0, id_aa64isar2_el1" : "=r"(isar2));
+
+    pac_feature = ((isar1 >> 4) & 0xf)   /* APA */
+                | ((isar1 >> 8) & 0xf)   /* API */
+                | ((isar2 >> 12) & 0xf); /* APA3 */
+
+    /*
+     * Exit if no PAuth or FEAT_FPAC, which will SIGILL on AUTIA failure
+     * rather than return an error for us to check below.
+     */
+    if (pac_feature == 0 || pac_feature >= 4) {
+        return 0;
+    }
 
     for (i = 0; i < TESTS; i++) {
         uintptr_t in, x, y;
@@ -17,7 +37,7 @@  int main()
         in = i + (uintptr_t) base;
 
         asm("mov %0, %[in]\n\t"
-            "pacia %0, sp\n\t"        /* sigill if pauth not supported */
+            "pacia %0, sp\n\t"
             "eor %0, %0, #4\n\t"      /* corrupt single bit */
             "mov %1, %0\n\t"
             "autia %1, sp\n\t"        /* validate corrupted pointer */
@@ -36,10 +56,10 @@  int main()
         if (x != y) {
             count++;
         }
-
     }
+
     perc = (float) count / (float) TESTS;
-    printf("Checks Passed: %0.2f%%", perc * 100.0);
+    printf("Checks Passed: %0.2f%%\n", perc * 100.0);
     assert(perc > 0.95);
     return 0;
 }
diff --git a/tests/tcg/aarch64/pauth-5.c b/tests/tcg/aarch64/pauth-5.c
index 67c257918b..5dbfb14768 100644
--- a/tests/tcg/aarch64/pauth-5.c
+++ b/tests/tcg/aarch64/pauth-5.c
@@ -1,4 +1,5 @@ 
 #include <assert.h>
+#include <sys/auxv.h>
 
 static int x;
 
@@ -6,6 +7,25 @@  int main()
 {
     int *p0 = &x, *p1, *p2, *p3;
     unsigned long salt = 0;
+    unsigned long isar1, isar2;
+    int pac_feature;
+
+    assert(getauxval(AT_HWCAP) & HWCAP_CPUID);
+
+    asm("mrs %0, id_aa64isar1_el1" : "=r"(isar1));
+    asm("mrs %0, id_aa64isar2_el1" : "=r"(isar2));
+
+    pac_feature = ((isar1 >> 4) & 0xf)   /* APA */
+                | ((isar1 >> 8) & 0xf)   /* API */
+                | ((isar2 >> 12) & 0xf); /* APA3 */
+
+    /*
+     * Exit if no PAuth or FEAT_FPAC, which will SIGILL on AUTDA failure
+     * rather than return an error for us to check below.
+     */
+    if (pac_feature == 0 || pac_feature >= 4) {
+        return 0;
+    }
 
     /*
      * With TBI enabled and a 48-bit VA, there are 7 bits of auth, and so
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 681dfa077c..780ab3f183 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -42,7 +42,10 @@  endif
 ifneq ($(CROSS_CC_HAS_ARMV8_3),)
 AARCH64_TESTS += pauth-1 pauth-2 pauth-4 pauth-5
 pauth-%: CFLAGS += -march=armv8.3-a
-run-pauth-%: QEMU_OPTS += -cpu max
+run-pauth-1: QEMU_OPTS += -cpu max
+run-pauth-2: QEMU_OPTS += -cpu max
+run-pauth-4: QEMU_OPTS += -cpu neoverse-v1
+run-pauth-5: QEMU_OPTS += -cpu neoverse-v1
 endif
 
 # BTI Tests