diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 347fc816d0..b9a346897e 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -1988,11 +1988,10 @@
ConditionCPUFeature=
- Verify that a given CPU feature is available via the CPUID
- instruction. This condition only does something on i386 and x86-64 processors. On other
- processors it is assumed that the CPU does not support the given feature. It checks the leaves
- 1, 7, 0x80000001, and
- 0x80000007. Valid values are:
+ On i386 and x86-64, verify that a given CPU feature is available via the
+ CPUID instruction. It checks the leaves 1,
+ 7, 0x80000001, and 0x80000007. Valid
+ values are:
fpu,
vme,
de,
@@ -2045,6 +2044,27 @@
abm,
constant_tsc.
+ On arm64, valid values are the corresponding arm64 feature names,
+ such as
+ asimd,
+ paca,
+ pacg,
+ bti,
+ mte,
+ among others. For the full list, see the documentation on
+ ARM64 ELF hwcaps.
+
+ To avoid ambiguities in mixed-architecture fleets, the value can be prefixed
+ with the architecture name using the form ARCH.FEATURE. If the
+ architecture prefix does not match the running system, the condition evaluates
+ to false. For example, one can specify arm64.bti on arm64
+ systems to check if bti is supported. In this example,
+ ConditionCPUFeature=arm64.bti and
+ ConditionCPUFeature=bti are functionally equivalent.
+ See ConditionArchitecture= for valid architecture names.
+
+ On architectures other than x86 and arm64, it is assumed that the CPU does not support the given feature.
+
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 81470c2e83..aa3f4f2b58 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -3,6 +3,9 @@
#if defined(__i386__) || defined(__x86_64__)
#include
#endif
+#if defined(__aarch64__)
+#include
+#endif
#include
#include
#include
@@ -951,9 +954,182 @@ static bool real_has_cpu_with_flag(const char *flag) {
}
#endif
+#if defined(__aarch64__)
+struct hwcap_table_entry {
+ uint64_t flag_mask;
+ const char *name;
+};
+
+static const struct hwcap_table_entry hwcap[] = {
+ { HWCAP_FP, "fp" },
+ { HWCAP_ASIMD, "asimd" },
+ { HWCAP_EVTSTRM, "evtstrm" },
+ { HWCAP_AES, "aes" },
+ { HWCAP_PMULL, "pmull" },
+ { HWCAP_SHA1, "sha1" },
+ { HWCAP_SHA2, "sha2" },
+ { HWCAP_CRC32, "crc32" },
+ { HWCAP_ATOMICS, "atomics" },
+ { HWCAP_FPHP, "fphp" },
+ { HWCAP_ASIMDHP, "asimdhp" },
+ { HWCAP_CPUID, "cpuid" },
+ { HWCAP_ASIMDRDM, "asimdrdm" },
+ { HWCAP_JSCVT, "jscvt" },
+ { HWCAP_FCMA, "fcma" },
+ { HWCAP_LRCPC, "lrcpc" },
+ { HWCAP_DCPOP, "dcpop" },
+ { HWCAP_SHA3, "sha3" },
+ { HWCAP_SM3, "sm3" },
+ { HWCAP_SM4, "sm4" },
+ { HWCAP_ASIMDDP, "asimddp" },
+ { HWCAP_SHA512, "sha512" },
+ { HWCAP_SVE, "sve" },
+ { HWCAP_ASIMDFHM, "asimdfhm" },
+ { HWCAP_DIT, "dit" },
+ { HWCAP_USCAT, "uscat" },
+ { HWCAP_ILRCPC, "ilrcpc" },
+ { HWCAP_FLAGM, "flagm" },
+ { HWCAP_SSBS, "ssbs" },
+ { HWCAP_SB, "sb" },
+ { HWCAP_PACA, "paca" },
+ { HWCAP_PACG, "pacg" },
+ { HWCAP_GCS, "gcs" },
+ { HWCAP_CMPBR, "cmpbr" },
+ { HWCAP_FPRCVT, "fprcvt" },
+ { HWCAP_F8MM8, "f8mm8" },
+ { HWCAP_F8MM4, "f8mm4" },
+ { HWCAP_SVE_F16MM, "svef16mm" },
+ { HWCAP_SVE_ELTPERM, "sveeltperm" },
+ { HWCAP_SVE_AES2, "sveaes2" },
+ { HWCAP_SVE_BFSCALE, "svebfscale" },
+ { HWCAP_SVE2P2, "sve2p2" },
+ { HWCAP_SME2P2, "sme2p2" },
+ { HWCAP_SME_SBITPERM, "smesbitperm" },
+ { HWCAP_SME_AES, "smeaes" },
+ { HWCAP_SME_SFEXPA, "smesfexpa" },
+ { HWCAP_SME_STMOP, "smestmop" },
+ { HWCAP_SME_SMOP4, "smesmop4" },
+};
+
+static const struct hwcap_table_entry hwcap2[] = {
+ { HWCAP2_DCPODP, "dcpodp" },
+ { HWCAP2_SVE2, "sve2" },
+ { HWCAP2_SVEAES, "sveaes" },
+ { HWCAP2_SVEPMULL, "svepmull" },
+ { HWCAP2_SVEBITPERM, "svebitperm" },
+ { HWCAP2_SVESHA3, "svesha3" },
+ { HWCAP2_SVESM4, "svesm4" },
+ { HWCAP2_FLAGM2, "flagm2" },
+ { HWCAP2_FRINT, "frint" },
+ { HWCAP2_SVEI8MM, "svei8mm" },
+ { HWCAP2_SVEF32MM, "svef32mm" },
+ { HWCAP2_SVEF64MM, "svef64mm" },
+ { HWCAP2_SVEBF16, "svebf16" },
+ { HWCAP2_I8MM, "i8mm" },
+ { HWCAP2_BF16, "bf16" },
+ { HWCAP2_DGH, "dgh" },
+ { HWCAP2_RNG, "rng" },
+ { HWCAP2_BTI, "bti" },
+ { HWCAP2_MTE, "mte" },
+ { HWCAP2_ECV, "ecv" },
+ { HWCAP2_AFP, "afp" },
+ { HWCAP2_RPRES, "rpres" },
+ { HWCAP2_MTE3, "mte3" },
+ { HWCAP2_SME, "sme" },
+ { HWCAP2_SME_I16I64, "smei16i64" },
+ { HWCAP2_SME_F64F64, "smef64f64" },
+ { HWCAP2_SME_I8I32, "smei8i32" },
+ { HWCAP2_SME_F16F32, "smef16f32" },
+ { HWCAP2_SME_B16F32, "smeb16f32" },
+ { HWCAP2_SME_F32F32, "smef32f32" },
+ { HWCAP2_SME_FA64, "smefa64" },
+ { HWCAP2_WFXT, "wfxt" },
+ { HWCAP2_EBF16, "ebf16" },
+ { HWCAP2_SVE_EBF16, "sveebf16" },
+ { HWCAP2_CSSC, "cssc" },
+ { HWCAP2_RPRFM, "rprfm" },
+ { HWCAP2_SVE2P1, "sve2p1" },
+ { HWCAP2_SME2, "sme2" },
+ { HWCAP2_SME2P1, "sme2p1" },
+ { HWCAP2_SME_I16I32, "smei16i32" },
+ { HWCAP2_SME_BI32I32, "smebi32i32" },
+ { HWCAP2_SME_B16B16, "smeb16b16" },
+ { HWCAP2_SME_F16F16, "smef16f16" },
+ { HWCAP2_MOPS, "mops" },
+ { HWCAP2_HBC, "hbc" },
+ { HWCAP2_SVE_B16B16, "sveb16b16" },
+ { HWCAP2_LRCPC3, "lrcpc3" },
+ { HWCAP2_LSE128, "lse128" },
+ { HWCAP2_FPMR, "fpmr" },
+ { HWCAP2_LUT, "lut" },
+ { HWCAP2_FAMINMAX, "faminmax" },
+ { HWCAP2_F8CVT, "f8cvt" },
+ { HWCAP2_F8FMA, "f8fma" },
+ { HWCAP2_F8DP4, "f8dp4" },
+ { HWCAP2_F8DP2, "f8dp2" },
+ { HWCAP2_F8E4M3, "f8e4m3" },
+ { HWCAP2_F8E5M2, "f8e5m2" },
+ { HWCAP2_SME_LUTV2, "smelutv2" },
+ { HWCAP2_SME_F8F16, "smef8f16" },
+ { HWCAP2_SME_F8F32, "smef8f32" },
+ { HWCAP2_SME_SF8FMA, "smesf8fma" },
+ { HWCAP2_SME_SF8DP4, "smesf8dp4" },
+ { HWCAP2_SME_SF8DP2, "smesf8dp2" },
+ { HWCAP2_POE, "poe" },
+};
+
+static const struct hwcap_table_entry hwcap3[] = {
+ { HWCAP3_MTE_FAR, "mtefar" },
+ { HWCAP3_MTE_STORE_ONLY, "mtestoreonly" },
+ { HWCAP3_LSFE, "lsfe" },
+ { HWCAP3_LS64, "ls64" },
+ { HWCAP3_SVE_B16MM, "sveb16mm" },
+ { HWCAP3_SVE2P3, "sve2p3" },
+ { HWCAP3_SME_LUT6, "smelut6" },
+ { HWCAP3_SME2P3, "sme2p3" },
+ { HWCAP3_F16MM, "f16mm" },
+ { HWCAP3_F16F32DOT, "f16f32dot" },
+ { HWCAP3_F16F32MM, "f16f32mm" },
+ { HWCAP3_SVE_LUT6, "svelut6" },
+};
+
+static bool given_flag_in_hwcap_set(
+ const char *flag,
+ const struct hwcap_table_entry *set,
+ size_t set_size,
+ unsigned long val) {
+
+ assert(set);
+
+ for (size_t i = 0; i < set_size; i++)
+ if ((set[i].flag_mask & val) && streq(flag, set[i].name))
+ return true;
+
+ return false;
+}
+
+static bool real_has_cpu_with_flag(const char *flag) {
+ unsigned long val;
+
+ val = getauxval(AT_HWCAP);
+ if (given_flag_in_hwcap_set(flag, hwcap, ELEMENTSOF(hwcap), val))
+ return true;
+
+ val = getauxval(AT_HWCAP2);
+ if (given_flag_in_hwcap_set(flag, hwcap2, ELEMENTSOF(hwcap2), val))
+ return true;
+
+ val = getauxval(AT_HWCAP3);
+ if (given_flag_in_hwcap_set(flag, hwcap3, ELEMENTSOF(hwcap3), val))
+ return true;
+
+ return false;
+}
+#endif
+
bool has_cpu_with_flag(const char *flag) {
- /* CPUID is an x86 specific interface. Assume on all others that no CPUs have those flags. */
-#if defined(__i386__) || defined(__x86_64__)
+ /* Check the architecture-specific CPU feature interface when available. */
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
return real_has_cpu_with_flag(flag);
#else
return false;
diff --git a/src/include/glibc/elf.h b/src/include/glibc/elf.h
new file mode 100644
index 0000000000..886e4d3528
--- /dev/null
+++ b/src/include/glibc/elf.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include_next /* IWYU pragma: export */
+
+/* AT_HWCAP3 was added in glibc 2.39. */
+#ifndef AT_HWCAP3
+#define AT_HWCAP3 29
+#endif
diff --git a/src/include/override/bits/hwcap.h b/src/include/override/bits/hwcap.h
new file mode 100644
index 0000000000..154ec71b50
--- /dev/null
+++ b/src/include/override/bits/hwcap.h
@@ -0,0 +1,229 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include_next /* IWYU pragma: export */
+
+/* All other capabilities are defined in glibc-2.34 / musl 1.2.6 or earlier */
+#if defined(__aarch64__)
+#ifndef HWCAP_GCS
+#define HWCAP_GCS (1UL << 32)
+#endif
+#ifndef HWCAP_CMPBR
+#define HWCAP_CMPBR (1UL << 33)
+#endif
+#ifndef HWCAP_FPRCVT
+#define HWCAP_FPRCVT (1UL << 34)
+#endif
+#ifndef HWCAP_F8MM8
+#define HWCAP_F8MM8 (1UL << 35)
+#endif
+#ifndef HWCAP_F8MM4
+#define HWCAP_F8MM4 (1UL << 36)
+#endif
+#ifndef HWCAP_SVE_F16MM
+#define HWCAP_SVE_F16MM (1UL << 37)
+#endif
+#ifndef HWCAP_SVE_ELTPERM
+#define HWCAP_SVE_ELTPERM (1UL << 38)
+#endif
+#ifndef HWCAP_SVE_AES2
+#define HWCAP_SVE_AES2 (1UL << 39)
+#endif
+#ifndef HWCAP_SVE_BFSCALE
+#define HWCAP_SVE_BFSCALE (1UL << 40)
+#endif
+#ifndef HWCAP_SVE2P2
+#define HWCAP_SVE2P2 (1UL << 41)
+#endif
+#ifndef HWCAP_SME2P2
+#define HWCAP_SME2P2 (1UL << 42)
+#endif
+#ifndef HWCAP_SME_SBITPERM
+#define HWCAP_SME_SBITPERM (1UL << 43)
+#endif
+#ifndef HWCAP_SME_AES
+#define HWCAP_SME_AES (1UL << 44)
+#endif
+#ifndef HWCAP_SME_SFEXPA
+#define HWCAP_SME_SFEXPA (1UL << 45)
+#endif
+#ifndef HWCAP_SME_STMOP
+#define HWCAP_SME_STMOP (1UL << 46)
+#endif
+#ifndef HWCAP_SME_SMOP4
+#define HWCAP_SME_SMOP4 (1UL << 47)
+#endif
+
+#ifndef HWCAP2_ECV
+#define HWCAP2_ECV (1 << 19)
+#endif
+#ifndef HWCAP2_AFP
+#define HWCAP2_AFP (1 << 20)
+#endif
+#ifndef HWCAP2_RPRES
+#define HWCAP2_RPRES (1 << 21)
+#endif
+#ifndef HWCAP2_MTE3
+#define HWCAP2_MTE3 (1 << 22)
+#endif
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+#ifndef HWCAP2_SME_I16I64
+#define HWCAP2_SME_I16I64 (1 << 24)
+#endif
+#ifndef HWCAP2_SME_F64F64
+#define HWCAP2_SME_F64F64 (1 << 25)
+#endif
+#ifndef HWCAP2_SME_I8I32
+#define HWCAP2_SME_I8I32 (1 << 26)
+#endif
+#ifndef HWCAP2_SME_F16F32
+#define HWCAP2_SME_F16F32 (1 << 27)
+#endif
+#ifndef HWCAP2_SME_B16F32
+#define HWCAP2_SME_B16F32 (1 << 28)
+#endif
+#ifndef HWCAP2_SME_F32F32
+#define HWCAP2_SME_F32F32 (1 << 29)
+#endif
+#ifndef HWCAP2_SME_FA64
+#define HWCAP2_SME_FA64 (1 << 30)
+#endif
+#ifndef HWCAP2_WFXT
+#define HWCAP2_WFXT (1UL << 31)
+#endif
+#ifndef HWCAP2_EBF16
+#define HWCAP2_EBF16 (1UL << 32)
+#endif
+#ifndef HWCAP2_SVE_EBF16
+#define HWCAP2_SVE_EBF16 (1UL << 33)
+#endif
+#ifndef HWCAP2_CSSC
+#define HWCAP2_CSSC (1UL << 34)
+#endif
+#ifndef HWCAP2_RPRFM
+#define HWCAP2_RPRFM (1UL << 35)
+#endif
+#ifndef HWCAP2_SVE2P1
+#define HWCAP2_SVE2P1 (1UL << 36)
+#endif
+#ifndef HWCAP2_SME2
+#define HWCAP2_SME2 (1UL << 37)
+#endif
+#ifndef HWCAP2_SME2P1
+#define HWCAP2_SME2P1 (1UL << 38)
+#endif
+#ifndef HWCAP2_SME_I16I32
+#define HWCAP2_SME_I16I32 (1UL << 39)
+#endif
+#ifndef HWCAP2_SME_BI32I32
+#define HWCAP2_SME_BI32I32 (1UL << 40)
+#endif
+#ifndef HWCAP2_SME_B16B16
+#define HWCAP2_SME_B16B16 (1UL << 41)
+#endif
+#ifndef HWCAP2_SME_F16F16
+#define HWCAP2_SME_F16F16 (1UL << 42)
+#endif
+#ifndef HWCAP2_MOPS
+#define HWCAP2_MOPS (1UL << 43)
+#endif
+#ifndef HWCAP2_HBC
+#define HWCAP2_HBC (1UL << 44)
+#endif
+#ifndef HWCAP2_SVE_B16B16
+#define HWCAP2_SVE_B16B16 (1UL << 45)
+#endif
+#ifndef HWCAP2_LRCPC3
+#define HWCAP2_LRCPC3 (1UL << 46)
+#endif
+#ifndef HWCAP2_LSE128
+#define HWCAP2_LSE128 (1UL << 47)
+#endif
+#ifndef HWCAP2_FPMR
+#define HWCAP2_FPMR (1UL << 48)
+#endif
+#ifndef HWCAP2_LUT
+#define HWCAP2_LUT (1UL << 49)
+#endif
+#ifndef HWCAP2_FAMINMAX
+#define HWCAP2_FAMINMAX (1UL << 50)
+#endif
+#ifndef HWCAP2_F8CVT
+#define HWCAP2_F8CVT (1UL << 51)
+#endif
+#ifndef HWCAP2_F8FMA
+#define HWCAP2_F8FMA (1UL << 52)
+#endif
+#ifndef HWCAP2_F8DP4
+#define HWCAP2_F8DP4 (1UL << 53)
+#endif
+#ifndef HWCAP2_F8DP2
+#define HWCAP2_F8DP2 (1UL << 54)
+#endif
+#ifndef HWCAP2_F8E4M3
+#define HWCAP2_F8E4M3 (1UL << 55)
+#endif
+#ifndef HWCAP2_F8E5M2
+#define HWCAP2_F8E5M2 (1UL << 56)
+#endif
+#ifndef HWCAP2_SME_LUTV2
+#define HWCAP2_SME_LUTV2 (1UL << 57)
+#endif
+#ifndef HWCAP2_SME_F8F16
+#define HWCAP2_SME_F8F16 (1UL << 58)
+#endif
+#ifndef HWCAP2_SME_F8F32
+#define HWCAP2_SME_F8F32 (1UL << 59)
+#endif
+#ifndef HWCAP2_SME_SF8FMA
+#define HWCAP2_SME_SF8FMA (1UL << 60)
+#endif
+#ifndef HWCAP2_SME_SF8DP4
+#define HWCAP2_SME_SF8DP4 (1UL << 61)
+#endif
+#ifndef HWCAP2_SME_SF8DP2
+#define HWCAP2_SME_SF8DP2 (1UL << 62)
+#endif
+#ifndef HWCAP2_POE
+#define HWCAP2_POE (1UL << 63)
+#endif
+
+#ifndef HWCAP3_MTE_FAR
+#define HWCAP3_MTE_FAR (1UL << 0)
+#endif
+#ifndef HWCAP3_MTE_STORE_ONLY
+#define HWCAP3_MTE_STORE_ONLY (1UL << 1)
+#endif
+#ifndef HWCAP3_LSFE
+#define HWCAP3_LSFE (1UL << 2)
+#endif
+#ifndef HWCAP3_LS64
+#define HWCAP3_LS64 (1UL << 3)
+#endif
+#ifndef HWCAP3_SVE_B16MM
+#define HWCAP3_SVE_B16MM (1UL << 4)
+#endif
+#ifndef HWCAP3_SVE2P3
+#define HWCAP3_SVE2P3 (1UL << 5)
+#endif
+#ifndef HWCAP3_SME_LUT6
+#define HWCAP3_SME_LUT6 (1UL << 6)
+#endif
+#ifndef HWCAP3_SME2P3
+#define HWCAP3_SME2P3 (1UL << 7)
+#endif
+#ifndef HWCAP3_F16MM
+#define HWCAP3_F16MM (1UL << 8)
+#endif
+#ifndef HWCAP3_F16F32DOT
+#define HWCAP3_F16F32DOT (1UL << 9)
+#endif
+#ifndef HWCAP3_F16F32MM
+#define HWCAP3_F16F32MM (1UL << 10)
+#endif
+#ifndef HWCAP3_SVE_LUT6
+#define HWCAP3_SVE_LUT6 (1UL << 11)
+#endif
+#endif
diff --git a/src/shared/condition.c b/src/shared/condition.c
index fc77d9f06e..2a831371c6 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -516,21 +516,19 @@ static int condition_test_virtualization(Condition *c, char **env) {
return v != VIRTUALIZATION_NONE && streq(c->parameter, virtualization_to_string(v));
}
-static int condition_test_architecture(Condition *c, char **env) {
+static int condition_test_architecture_parameter(const char *parameter) {
Architecture a, b;
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_ARCHITECTURE);
+ assert(parameter);
a = uname_architecture();
if (a < 0)
return a;
- if (streq(c->parameter, "native"))
+ if (streq(parameter, "native"))
b = native_architecture();
else {
- b = architecture_from_string(c->parameter);
+ b = architecture_from_string(parameter);
if (b < 0) /* unknown architecture? Then it's definitely not ours */
return false;
}
@@ -538,6 +536,14 @@ static int condition_test_architecture(Condition *c, char **env) {
return a == b;
}
+static int condition_test_architecture(Condition *c, char **env) {
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_ARCHITECTURE);
+
+ return condition_test_architecture_parameter(c->parameter);
+}
+
#define DTCOMPAT_FILE "/proc/device-tree/compatible"
static int condition_test_firmware_devicetree_compatible(const char *dtcarg) {
int r;
@@ -1080,11 +1086,26 @@ static int condition_test_path_is_read_write(Condition *c, char **env) {
}
static int condition_test_cpufeature(Condition *c, char **env) {
+ _cleanup_free_ char *cpu_arch = NULL, *feature = NULL;
+ int r;
+
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_CPU_FEATURE);
- return has_cpu_with_flag(ascii_strlower(c->parameter));
+ r = split_pair(c->parameter, ".", &cpu_arch, &feature);
+ if (r >= 0) {
+ r = condition_test_architecture_parameter(cpu_arch);
+ if (r <= 0)
+ return r;
+ } else if (r == -EINVAL) {
+ feature = strdup(c->parameter);
+ if (!feature)
+ return -ENOMEM;
+ } else
+ return r;
+
+ return has_cpu_with_flag(ascii_strlower(feature));
}
static int condition_test_path_is_encrypted(Condition *c, char **env) {
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index a35d08ef63..52990981ff 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -846,14 +846,52 @@ TEST(condition_test_credential) {
ASSERT_OK(set_unset_env("ENCRYPTED_CREDENTIALS_DIRECTORY", d2, /* overwrite= */ true));
}
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
TEST(condition_test_cpufeature) {
Condition *condition;
+#if defined(__i386__)
ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "fpu", false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "x86.fpu", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "bogus.fpu", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+#elif defined(__x86_64__)
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "fpu", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "x86-64.fpu", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "bogus.fpu", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+#elif defined(__aarch64__)
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "fp", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "asimd", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "arm64.asimd", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "bogus.asimd", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+#endif
+
ASSERT_NOT_NULL((condition = condition_new(CONDITION_CPU_FEATURE, "somecpufeaturethatreallydoesntmakesense", false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);