summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/arm64/abi/hwcap.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/arm64/abi/hwcap.c')
-rw-r--r--tools/testing/selftests/arm64/abi/hwcap.c212
1 files changed, 207 insertions, 5 deletions
diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c
index 35f521e5f41c..19fca95f7c22 100644
--- a/tools/testing/selftests/arm64/abi/hwcap.c
+++ b/tools/testing/selftests/arm64/abi/hwcap.c
@@ -11,16 +11,24 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <linux/auxvec.h>
+#include <linux/compiler.h>
#include <sys/auxv.h>
#include <sys/prctl.h>
#include <asm/hwcap.h>
#include <asm/sigcontext.h>
#include <asm/unistd.h>
-#include "../../kselftest.h"
+#include <linux/auxvec.h>
+
+#include "kselftest.h"
#define TESTS_PER_HWCAP 3
+#ifndef AT_HWCAP3
+#define AT_HWCAP3 29
+#endif
+
/*
* Function expected to generate exception when the feature is not
* supported and return when it is supported. If the specific exception
@@ -48,10 +56,10 @@ static void atomics_sigill(void)
static void cmpbr_sigill(void)
{
- /* Not implemented, too complicated and unreliable anyway */
+ asm volatile(".inst 0x74C00040\n" /* CBEQ w0, w0, +8 */
+ "udf #0" : : : "cc"); /* UDF #0 */
}
-
static void crc32_sigill(void)
{
/* CRC32W W0, W0, W1 */
@@ -100,6 +108,24 @@ static void f8mm8_sigill(void)
asm volatile(".inst 0x6e80ec00");
}
+static void f16f32dot_sigill(void)
+{
+ /* FDOT V0.2S, V0.4H, V0.2H[0] */
+ asm volatile(".inst 0xf409000");
+}
+
+static void f16f32mm_sigill(void)
+{
+ /* FMMLA V0.4S, V0.8H, V0.8H */
+ asm volatile(".inst 0x4e40ec00");
+}
+
+static void f16mm_sigill(void)
+{
+ /* FMMLA V0.8H, V0.8H, V0.8H */
+ asm volatile(".inst 0x4ec0ec00");
+}
+
static void faminmax_sigill(void)
{
/* FAMIN V0.4H, V0.4H, V0.4H */
@@ -165,12 +191,30 @@ static void lse128_sigill(void)
: "cc", "memory");
}
+static void lsfe_sigill(void)
+{
+ float __attribute__ ((aligned (16))) mem;
+ register float *memp asm ("x0") = &mem;
+
+ /* STFADD H0, [X0] */
+ asm volatile(".inst 0x7c20801f"
+ : "+r" (memp)
+ :
+ : "memory");
+}
+
static void lut_sigill(void)
{
/* LUTI2 V0.16B, { V0.16B }, V[0] */
asm volatile(".inst 0x4e801000");
}
+static void sve_lut6_sigill(void)
+{
+ /* LUTI6 Z0.H, { Z0.H, Z1.H }, Z0[0] */
+ asm volatile(".inst 0x4560ac00");
+}
+
static void mops_sigill(void)
{
char dst[1], src[1];
@@ -262,6 +306,18 @@ static void sme2p2_sigill(void)
asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
}
+static void sme2p3_sigill(void)
+{
+ /* SMSTART SM */
+ asm volatile("msr S0_3_C4_C3_3, xzr" : : : );
+
+ /* ADDQP Z0.B, Z0.B, Z0.B */
+ asm volatile(".inst 0x4207800" : : : "z0");
+
+ /* SMSTOP */
+ asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
+}
+
static void sme_aes_sigill(void)
{
/* SMSTART SM */
@@ -358,6 +414,18 @@ static void smef8f32_sigill(void)
asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
}
+static void smelut6_sigill(void)
+{
+ /* SMSTART */
+ asm volatile("msr S0_3_C4_C7_3, xzr" : : : );
+
+ /* LUTI6 { Z0.B-Z3.B }, ZT0, { Z0-Z2 } */
+ asm volatile(".inst 0xc08a0000" : : : );
+
+ /* SMSTOP */
+ asm volatile("msr S0_3_C4_C6_3, xzr" : : : );
+}
+
static void smelutv2_sigill(void)
{
/* SMSTART */
@@ -456,8 +524,8 @@ static void sve2_sigill(void)
static void sve2p1_sigill(void)
{
- /* BFADD Z0.H, Z0.H, Z0.H */
- asm volatile(".inst 0x65000000" : : : "z0");
+ /* LD1Q {Z0.Q}, P0/Z, [Z0.D, X0] */
+ asm volatile(".inst 0xC400A000" : : : "z0");
}
static void sve2p2_sigill(void)
@@ -466,6 +534,12 @@ static void sve2p2_sigill(void)
asm volatile(".inst 0x4cea000" : : : "z0");
}
+static void sve2p3_sigill(void)
+{
+ /* ADDQP Z0.B, Z0.B, Z0.B */
+ asm volatile(".inst 0x4207800" : : : "z0");
+}
+
static void sveaes_sigill(void)
{
/* AESD z0.b, z0.b, z0.b */
@@ -484,6 +558,12 @@ static void sveb16b16_sigill(void)
asm volatile(".inst 0x65000000" : : : );
}
+static void sveb16mm_sigill(void)
+{
+ /* BFMMLA Z0.H, Z0.H, Z0.H */
+ asm volatile(".inst 0x64e0e000" : : : );
+}
+
static void svebfscale_sigill(void)
{
/* BFSCALE Z0.H, P0/M, Z0.H, Z0.H */
@@ -578,6 +658,45 @@ static void lrcpc3_sigill(void)
: "=r" (data0), "=r" (data1) : "r" (src) :);
}
+static void ignore_signal(int sig, siginfo_t *info, void *context)
+{
+ ucontext_t *uc = context;
+
+ uc->uc_mcontext.pc += 4;
+}
+
+static void ls64_sigill(void)
+{
+ struct sigaction ign, old;
+ char src[64] __aligned(64) = { 1 };
+
+ /*
+ * LS64 requires target memory to be Device/Non-cacheable (if
+ * FEAT_LS64WB not supported) and the completer supports these
+ * instructions, otherwise we'll receive a SIGBUS. Since we are only
+ * testing the ABI here, so just ignore the SIGBUS and see if we can
+ * execute the instructions without receiving a SIGILL. Restore the
+ * handler of SIGBUS after this test.
+ */
+ ign.sa_sigaction = ignore_signal;
+ ign.sa_flags = SA_SIGINFO | SA_RESTART;
+ sigemptyset(&ign.sa_mask);
+ sigaction(SIGBUS, &ign, &old);
+
+ register void *xn asm ("x8") = src;
+ register u64 xt_1 asm ("x0");
+
+ /* LD64B x0, [x8] */
+ asm volatile(".inst 0xf83fd100" : "=r" (xt_1) : "r" (xn)
+ : "x1", "x2", "x3", "x4", "x5", "x6", "x7");
+
+ /* ST64B x0, [x8] */
+ asm volatile(".inst 0xf83f9100" : : "r" (xt_1), "r" (xn)
+ : "x1", "x2", "x3", "x4", "x5", "x6", "x7");
+
+ sigaction(SIGBUS, &old, NULL);
+}
+
static const struct hwcap_data {
const char *name;
unsigned long at_hwcap;
@@ -671,6 +790,27 @@ static const struct hwcap_data {
.sigill_fn = f8mm4_sigill,
},
{
+ .name = "F16MM",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_F16MM,
+ .cpuinfo = "f16mm",
+ .sigill_fn = f16mm_sigill,
+ },
+ {
+ .name = "F16F32DOT",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_F16F32DOT,
+ .cpuinfo = "f16f32dot",
+ .sigill_fn = f16f32dot_sigill,
+ },
+ {
+ .name = "F16F32MM",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_F16F32MM,
+ .cpuinfo = "f16f32mm",
+ .sigill_fn = f16f32mm_sigill,
+ },
+ {
.name = "FAMINMAX",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_FAMINMAX,
@@ -759,6 +899,13 @@ static const struct hwcap_data {
.sigill_fn = lse128_sigill,
},
{
+ .name = "LSFE",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_LSFE,
+ .cpuinfo = "lsfe",
+ .sigill_fn = lsfe_sigill,
+ },
+ {
.name = "LUT",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_LUT,
@@ -853,6 +1000,13 @@ static const struct hwcap_data {
.sigill_fn = sme2p2_sigill,
},
{
+ .name = "SME 2.3",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_SME2P3,
+ .cpuinfo = "sme2p3",
+ .sigill_fn = sme2p3_sigill,
+ },
+ {
.name = "SME AES",
.at_hwcap = AT_HWCAP,
.hwcap_bit = HWCAP_SME_AES,
@@ -902,6 +1056,13 @@ static const struct hwcap_data {
.sigill_fn = smef8f32_sigill,
},
{
+ .name = "SME LUT6",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_SME_LUT6,
+ .cpuinfo = "smelut6",
+ .sigill_fn = smelut6_sigill,
+ },
+ {
.name = "SME LUTV2",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SME_LUTV2,
@@ -987,6 +1148,13 @@ static const struct hwcap_data {
.sigill_fn = sve2p2_sigill,
},
{
+ .name = "SVE 2.3",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_SVE2P3,
+ .cpuinfo = "sve2p3",
+ .sigill_fn = sve2p3_sigill,
+ },
+ {
.name = "SVE AES",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVEAES,
@@ -1001,6 +1169,13 @@ static const struct hwcap_data {
.sigill_fn = sveaes2_sigill,
},
{
+ .name = "SVE B16MM",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_SVE_B16MM,
+ .cpuinfo = "sveb16mm",
+ .sigill_fn = sveb16mm_sigill,
+ },
+ {
.name = "SVE BFSCALE",
.at_hwcap = AT_HWCAP,
.hwcap_bit = HWCAP_SVE_BFSCALE,
@@ -1022,6 +1197,13 @@ static const struct hwcap_data {
.sigill_fn = svef16mm_sigill,
},
{
+ .name = "SVE_LUT6",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_SVE_LUT6,
+ .cpuinfo = "svelut6",
+ .sigill_fn = sve_lut6_sigill,
+ },
+ {
.name = "SVE2 B16B16",
.at_hwcap = AT_HWCAP2,
.hwcap_bit = HWCAP2_SVE_B16B16,
@@ -1098,6 +1280,26 @@ static const struct hwcap_data {
.sigill_fn = hbc_sigill,
.sigill_reliable = true,
},
+ {
+ .name = "MTE_FAR",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_MTE_FAR,
+ .cpuinfo = "mtefar",
+ },
+ {
+ .name = "MTE_STOREONLY",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_MTE_STORE_ONLY,
+ .cpuinfo = "mtestoreonly",
+ },
+ {
+ .name = "LS64",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_LS64,
+ .cpuinfo = "ls64",
+ .sigill_fn = ls64_sigill,
+ .sigill_reliable = true,
+ },
};
typedef void (*sighandler_fn)(int, siginfo_t *, void *);