aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2023-11-03 10:04:12 +0800
committerStefan Hajnoczi <stefanha@redhat.com>2023-11-03 10:04:12 +0800
commitd762bf97931b58839316b68a570eecc6143c9e3e (patch)
treedd57eefc4ef077ce92ef2e8772f90072e6a3180a /tests
parent75b7b25d44a64411ea0ae792d5ebad8ddf22527e (diff)
parent1c98a821a2b3620c516f3da0d74719ed6f33bced (diff)
Merge tag 'pull-target-arm-20231102' of https://git.linaro.org/people/pmaydell/qemu-arm into staging
target-arm queue: * linux-user/elfload: Add missing arm64 hwcap values * stellaris-gamepad: Convert to qdev * docs/specs: Convert various txt docs to rST * MAINTAINERS: Make sure that gicv3_internal.h is covered, too * hw/arm/pxa2xx_gpio: Pass CPU using QOM link property * hw/watchdog/wdt_imx2: Trace MMIO access and timer activity * hw/misc/imx7_snvs: Trace MMIO access * hw/misc/imx6_ccm: Convert DPRINTF to trace events * hw/i2c/pm_smbus: Convert DPRINTF to trace events * target/arm: Enable FEAT_MOPS insns in user-mode emulation * linux-user: Report AArch64 hwcap2 fields above bit 31 * target/arm: Make FEAT_MOPS SET* insns handle Xs == XZR correctly * target/arm: Fix SVE STR increment * hw/char/stm32f2xx_usart: implement TX interrupts * target/arm: Correctly propagate stage 1 BTI guarded bit in a two-stage walk * xlnx-versal-virt: Add AMD/Xilinx TRNG device * tag 'pull-target-arm-20231102' of https://git.linaro.org/people/pmaydell/qemu-arm: (33 commits) tests/qtest: Introduce tests for AMD/Xilinx Versal TRNG device hw/arm: xlnx-versal-virt: Add AMD/Xilinx TRNG device hw/misc: Introduce AMD/Xilix Versal TRNG device target/arm: Correctly propagate stage 1 BTI guarded bit in a two-stage walk hw/char/stm32f2xx_usart: Add more definitions for CR1 register hw/char/stm32f2xx_usart: Update IRQ when DR is written hw/char/stm32f2xx_usart: Extract common IRQ update code to update_irq() target/arm: Fix SVE STR increment target/arm: Make FEAT_MOPS SET* insns handle Xs == XZR correctly linux-user: Report AArch64 hwcap2 fields above bit 31 target/arm: Enable FEAT_MOPS insns in user-mode emulation hw/i2c/pm_smbus: Convert DPRINTF to trace events hw/misc/imx6_ccm: Convert DPRINTF to trace events hw/misc/imx7_snvs: Trace MMIO access hw/watchdog/wdt_imx2: Trace timer activity hw/watchdog/wdt_imx2: Trace MMIO access hw/arm/pxa2xx_gpio: Pass CPU using QOM link property MAINTAINERS: Make sure that gicv3_internal.h is covered, too docs/specs/vmgenid: Convert to rST docs/specs/vmcoreinfo: Convert to rST ... Conflicts: hw/input/stellaris_input.c The qdev conversion in this pull request ("stellaris-gamepad: Convert to qdev") eliminates the vmstate_register() call that was converted to vmstate_register_any() in the conflicting migration pull request. vmstate_register_any() is no longer necessary now that this device has been converted to qdev, so take this pull request's version of stellaris_gamepad.c over the previous pull request's stellaris_input.c (the file was renamed). Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/qtest/meson.build2
-rw-r--r--tests/qtest/xlnx-versal-trng-test.c485
-rw-r--r--tests/tcg/aarch64/Makefile.target6
-rw-r--r--tests/tcg/aarch64/sve-str.c49
4 files changed, 540 insertions, 2 deletions
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index d6022ebd64..c9945e69b1 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -216,7 +216,7 @@ qtests_aarch64 = \
(config_all.has_key('CONFIG_TCG') and config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? \
['tpm-tis-device-test', 'tpm-tis-device-swtpm-test'] : []) + \
(config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \
- (config_all_devices.has_key('CONFIG_XLNX_VERSAL') ? ['xlnx-canfd-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_XLNX_VERSAL') ? ['xlnx-canfd-test', 'xlnx-versal-trng-test'] : []) + \
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \
(config_all.has_key('CONFIG_TCG') and \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
diff --git a/tests/qtest/xlnx-versal-trng-test.c b/tests/qtest/xlnx-versal-trng-test.c
new file mode 100644
index 0000000000..cef4e575bb
--- /dev/null
+++ b/tests/qtest/xlnx-versal-trng-test.c
@@ -0,0 +1,485 @@
+/*
+ * QTests for the Xilinx Versal True Random Number Generator device
+ *
+ * Copyright (c) 2023 Advanced Micro Devices, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+
+/* Base Address */
+#define TRNG_BASEADDR (0xf1230000)
+
+/* TRNG_INT_CTRL */
+#define R_TRNG_INT_CTRL (0x0000)
+#define TRNG_INT_CTRL_CERTF_RST_MASK (1 << 5)
+#define TRNG_INT_CTRL_DTF_RST_MASK (1 << 4)
+#define TRNG_INT_CTRL_DONE_RST_MASK (1 << 3)
+#define TRNG_INT_CTRL_CERTF_EN_MASK (1 << 2)
+#define TRNG_INT_CTRL_DTF_EN_MASK (1 << 1)
+#define TRNG_INT_CTRL_DONE_EN_MASK (1)
+
+/* TRNG_STATUS */
+#define R_TRNG_STATUS (0x0004)
+#define TRNG_STATUS_QCNT_SHIFT (9)
+#define TRNG_STATUS_QCNT_MASK (7 << TRNG_STATUS_QCNT_SHIFT)
+#define TRNG_STATUS_CERTF_MASK (1 << 3)
+#define TRNG_STATUS_DTF_MASK (1 << 1)
+#define TRNG_STATUS_DONE_MASK (1)
+
+/* TRNG_CTRL */
+#define R_TRNG_CTRL (0x0008)
+#define TRNG_CTRL_PERSODISABLE_MASK (1 << 10)
+#define TRNG_CTRL_SINGLEGENMODE_MASK (1 << 9)
+#define TRNG_CTRL_PRNGMODE_MASK (1 << 7)
+#define TRNG_CTRL_TSTMODE_MASK (1 << 6)
+#define TRNG_CTRL_PRNGSTART_MASK (1 << 5)
+#define TRNG_CTRL_PRNGXS_MASK (1 << 3)
+#define TRNG_CTRL_TRSSEN_MASK (1 << 2)
+#define TRNG_CTRL_QERTUEN_MASK (1 << 1)
+#define TRNG_CTRL_PRNGSRST_MASK (1)
+
+/* TRNG_EXT_SEED_0 ... _11 */
+#define R_TRNG_EXT_SEED_0 (0x0040)
+#define R_TRNG_EXT_SEED_11 (R_TRNG_EXT_SEED_0 + 4 * 11)
+
+/* TRNG_PER_STRNG_0 ... 11 */
+#define R_TRNG_PER_STRNG_0 (0x0080)
+#define R_TRNG_PER_STRNG_11 (R_TRNG_PER_STRNG_0 + 4 * 11)
+
+/* TRNG_CORE_OUTPUT */
+#define R_TRNG_CORE_OUTPUT (0x00c0)
+
+/* TRNG_RESET */
+#define R_TRNG_RESET (0x00d0)
+#define TRNG_RESET_VAL_MASK (1)
+
+/* TRNG_OSC_EN */
+#define R_TRNG_OSC_EN (0x00d4)
+#define TRNG_OSC_EN_VAL_MASK (1)
+
+/* TRNG_TRNG_ISR, _IMR, _IER, _IDR */
+#define R_TRNG_ISR (0x00e0)
+#define R_TRNG_IMR (0x00e4)
+#define R_TRNG_IER (0x00e8)
+#define R_TRNG_IDR (0x00ec)
+#define TRNG_IRQ_SLVERR_MASK (1 << 1)
+#define TRNG_IRQ_CORE_INT_MASK (1)
+
+/*
+ * End test with a formatted error message, by embedding the message
+ * in a GError.
+ */
+#define TRNG_FAILED(FMT, ...) \
+ do { \
+ g_autoptr(GError) err = g_error_new( \
+ g_quark_from_static_string(trng_qname), 0, \
+ FMT, ## __VA_ARGS__); \
+ g_assert_no_error(err); \
+ } while (0)
+
+static const gchar trng_qname[] = "xlnx-versal-trng-test";
+
+static const uint32_t prng_seed[12] = {
+ 0x01234567, 0x12345678, 0x23456789, 0x3456789a, 0x456789ab, 0x56789abc,
+ 0x76543210, 0x87654321, 0x98765432, 0xa9876543, 0xba987654, 0xfedcba98,
+};
+
+static const uint32_t pers_str[12] = {
+ 0x76543210, 0x87654321, 0x98765432, 0xa9876543, 0xba987654, 0xfedcba98,
+ 0x01234567, 0x12345678, 0x23456789, 0x3456789a, 0x456789ab, 0x56789abc,
+};
+
+static void trng_test_start(void)
+{
+ qtest_start("-machine xlnx-versal-virt");
+}
+
+static void trng_test_stop(void)
+{
+ qtest_end();
+}
+
+static void trng_test_set_uint_prop(const char *name, uint64_t value)
+{
+ const char *path = "/machine/xlnx-versal/trng";
+ QDict *response;
+
+ response = qmp("{ 'execute': 'qom-set',"
+ " 'arguments': {"
+ " 'path': %s,"
+ " 'property': %s,"
+ " 'value': %llu"
+ "} }", path,
+ name, (unsigned long long)value);
+ g_assert(qdict_haskey(response, "return"));
+ qobject_unref(response);
+}
+
+static void trng_write(unsigned ra, uint32_t val)
+{
+ writel(TRNG_BASEADDR + ra, val);
+}
+
+static uint32_t trng_read(unsigned ra)
+{
+ return readl(TRNG_BASEADDR + ra);
+}
+
+static void trng_bit_set(unsigned ra, uint32_t bits)
+{
+ trng_write(ra, (trng_read(ra) | bits));
+}
+
+static void trng_bit_clr(unsigned ra, uint32_t bits)
+{
+ trng_write(ra, (trng_read(ra) & ~bits));
+}
+
+static void trng_ctrl_set(uint32_t bits)
+{
+ trng_bit_set(R_TRNG_CTRL, bits);
+}
+
+static void trng_ctrl_clr(uint32_t bits)
+{
+ trng_bit_clr(R_TRNG_CTRL, bits);
+}
+
+static uint32_t trng_status(void)
+{
+ return trng_read(R_TRNG_STATUS);
+}
+
+static unsigned trng_qcnt(void)
+{
+ uint32_t sta = trng_status();
+
+ return (sta & TRNG_STATUS_QCNT_MASK) >> TRNG_STATUS_QCNT_SHIFT;
+}
+
+static const char *trng_info(void)
+{
+ uint32_t sta = trng_status();
+ uint32_t ctl = trng_read(R_TRNG_CTRL);
+
+ static char info[64];
+
+ snprintf(info, sizeof(info), "; status=0x%x, ctrl=0x%x", sta, ctl);
+ return info;
+}
+
+static void trng_check_status(uint32_t status_mask, const char *act)
+{
+ uint32_t clear_mask = 0;
+ uint32_t status;
+
+ /*
+ * Only selected bits are events in R_TRNG_STATUS, and
+ * clear them needs to go through R_INT_CTRL.
+ */
+ if (status_mask & TRNG_STATUS_CERTF_MASK) {
+ clear_mask |= TRNG_INT_CTRL_CERTF_RST_MASK;
+ }
+ if (status_mask & TRNG_STATUS_DTF_MASK) {
+ clear_mask |= TRNG_INT_CTRL_DTF_RST_MASK;
+ }
+ if (status_mask & TRNG_STATUS_DONE_MASK) {
+ clear_mask |= TRNG_INT_CTRL_DONE_RST_MASK;
+ }
+
+ status = trng_status();
+ if ((status & status_mask) != status_mask) {
+ TRNG_FAILED("%s: Status bitmask 0x%x failed to be 1%s",
+ act, status_mask, trng_info());
+ }
+
+ /* Remove event */
+ trng_bit_set(R_TRNG_INT_CTRL, clear_mask);
+
+ if (!!(trng_read(R_TRNG_STATUS) & status_mask)) {
+ TRNG_FAILED("%s: Event 0x%0x stuck at 1 after clear: %s",
+ act, status_mask, trng_info());
+ }
+}
+
+static void trng_check_done_status(const char *act)
+{
+ trng_check_status(TRNG_STATUS_DONE_MASK, act);
+}
+
+static void trng_check_dtf_status(void)
+{
+ trng_check_status(TRNG_STATUS_DTF_MASK, "DTF injection");
+}
+
+static void trng_check_certf_status(void)
+{
+ trng_check_status(TRNG_STATUS_CERTF_MASK, "CERTF injection");
+}
+
+static void trng_reset(void)
+{
+ trng_write(R_TRNG_RESET, TRNG_RESET_VAL_MASK);
+ trng_write(R_TRNG_RESET, 0);
+}
+
+static void trng_load(unsigned r0, const uint32_t *b384)
+{
+ static const uint32_t zero[12] = { 0 };
+ unsigned k;
+
+ if (!b384) {
+ b384 = zero;
+ }
+
+ for (k = 0; k < 12; k++) {
+ trng_write(r0 + 4 * k, b384[k]);
+ }
+}
+
+static void trng_reseed(const uint32_t *seed)
+{
+ const char *act;
+ uint32_t ctl;
+
+ ctl = TRNG_CTRL_PRNGSTART_MASK |
+ TRNG_CTRL_PRNGXS_MASK |
+ TRNG_CTRL_TRSSEN_MASK;
+
+ trng_ctrl_clr(ctl | TRNG_CTRL_PRNGMODE_MASK);
+
+ if (seed) {
+ trng_load(R_TRNG_EXT_SEED_0, seed);
+ act = "Reseed PRNG";
+ ctl &= ~TRNG_CTRL_TRSSEN_MASK;
+ } else {
+ trng_write(R_TRNG_OSC_EN, TRNG_OSC_EN_VAL_MASK);
+ act = "Reseed TRNG";
+ ctl &= ~TRNG_CTRL_PRNGXS_MASK;
+ }
+
+ trng_ctrl_set(ctl);
+ trng_check_done_status(act);
+ trng_ctrl_clr(TRNG_CTRL_PRNGSTART_MASK);
+}
+
+static void trng_generate(bool auto_enb)
+{
+ uint32_t ctl;
+
+ ctl = TRNG_CTRL_PRNGSTART_MASK | TRNG_CTRL_SINGLEGENMODE_MASK;
+ trng_ctrl_clr(ctl);
+
+ if (auto_enb) {
+ ctl &= ~TRNG_CTRL_SINGLEGENMODE_MASK;
+ }
+
+ trng_ctrl_set(ctl | TRNG_CTRL_PRNGMODE_MASK);
+
+ trng_check_done_status("Generate");
+ g_assert(trng_qcnt() != 7);
+}
+
+static size_t trng_collect(uint32_t *rnd, size_t cnt)
+{
+ size_t i;
+
+ for (i = 0; i < cnt; i++) {
+ if (trng_qcnt() == 0) {
+ return i;
+ }
+
+ rnd[i] = trng_read(R_TRNG_CORE_OUTPUT);
+ }
+
+ return i;
+}
+
+static void trng_test_autogen(void)
+{
+ const size_t cnt = 512 / 32;
+ uint32_t rng[cnt], prng[cnt];
+ size_t n;
+
+ trng_reset();
+
+ /* PRNG run #1 */
+ trng_reseed(prng_seed);
+ trng_generate(true);
+
+ n = trng_collect(prng, cnt);
+ if (n != cnt) {
+ TRNG_FAILED("PRNG_1 Auto-gen test failed: expected = %u, got = %u",
+ (unsigned)cnt, (unsigned)n);
+ }
+
+ /* TRNG, should not match PRNG */
+ trng_reseed(NULL);
+ trng_generate(true);
+
+ n = trng_collect(rng, cnt);
+ if (n != cnt) {
+ TRNG_FAILED("TRNG Auto-gen test failed: expected = %u, got = %u",
+ (unsigned)cnt, (unsigned)n);
+ }
+
+ /* PRNG #2: should matches run #1 */
+ trng_reseed(prng_seed);
+ trng_generate(true);
+
+ n = trng_collect(rng, cnt);
+ if (n != cnt) {
+ TRNG_FAILED("PRNG_2 Auto-gen test failed: expected = %u, got = %u",
+ (unsigned)cnt, (unsigned)n);
+ }
+
+ if (memcmp(rng, prng, sizeof(rng))) {
+ TRNG_FAILED("PRNG_2 Auto-gen test failed: does not match PRNG_1");
+ }
+}
+
+static void trng_test_oneshot(void)
+{
+ const size_t cnt = 512 / 32;
+ uint32_t rng[cnt];
+ size_t n;
+
+ trng_reset();
+
+ /* PRNG run #1 */
+ trng_reseed(prng_seed);
+ trng_generate(false);
+
+ n = trng_collect(rng, cnt);
+ if (n == cnt) {
+ TRNG_FAILED("PRNG_1 One-shot gen test failed");
+ }
+
+ /* TRNG, should not match PRNG */
+ trng_reseed(NULL);
+ trng_generate(false);
+
+ n = trng_collect(rng, cnt);
+ if (n == cnt) {
+ TRNG_FAILED("TRNG One-shot test failed");
+ }
+}
+
+static void trng_test_per_str(void)
+{
+ const size_t cnt = 512 / 32;
+ uint32_t rng[cnt], prng[cnt];
+ size_t n;
+
+ trng_reset();
+
+ /* #1: disabled */
+ trng_ctrl_set(TRNG_CTRL_PERSODISABLE_MASK);
+ trng_reseed(prng_seed);
+ trng_ctrl_clr(TRNG_CTRL_PERSODISABLE_MASK);
+
+ trng_generate(true);
+ n = trng_collect(prng, cnt);
+ g_assert_cmpuint(n, ==, cnt);
+
+ /* #2: zero string should match personalization disabled */
+ trng_load(R_TRNG_PER_STRNG_0, NULL);
+ trng_reseed(prng_seed);
+
+ trng_generate(true);
+ n = trng_collect(rng, cnt);
+ g_assert_cmpuint(n, ==, cnt);
+
+ if (memcmp(rng, prng, sizeof(rng))) {
+ TRNG_FAILED("Failed: PER_DISABLE != PER_STRNG_ALL_ZERO");
+ }
+
+ /* #3: non-zero string should not match personalization disabled */
+ trng_load(R_TRNG_PER_STRNG_0, pers_str);
+ trng_reseed(prng_seed);
+
+ trng_generate(true);
+ n = trng_collect(rng, cnt);
+ g_assert_cmpuint(n, ==, cnt);
+
+ if (!memcmp(rng, prng, sizeof(rng))) {
+ TRNG_FAILED("Failed: PER_DISABLE == PER_STRNG_NON_ZERO");
+ }
+}
+
+static void trng_test_forced_prng(void)
+{
+ const char *prop = "forced-prng";
+ const uint64_t seed = 0xdeadbeefbad1bad0ULL;
+
+ const size_t cnt = 512 / 32;
+ uint32_t rng[cnt], prng[cnt];
+ size_t n;
+
+ trng_reset();
+ trng_test_set_uint_prop(prop, seed);
+
+ /* TRNG run #1 */
+ trng_reset();
+ trng_reseed(NULL);
+ trng_generate(true);
+
+ n = trng_collect(prng, cnt);
+ g_assert_cmpuint(n, ==, cnt);
+
+ /* TRNG run #2 should match run #1 */
+ trng_reset();
+ trng_reseed(NULL);
+ trng_generate(true);
+
+ n = trng_collect(rng, cnt);
+ g_assert_cmpuint(n, ==, cnt);
+
+ if (memcmp(rng, prng, sizeof(rng))) {
+ TRNG_FAILED("Forced-prng test failed: results do not match");
+ }
+}
+
+static void trng_test_fault_events(void)
+{
+ const char *prop = "fips-fault-events";
+
+ trng_reset();
+
+ /* Fault events only when TRSS is enabled */
+ trng_write(R_TRNG_OSC_EN, TRNG_OSC_EN_VAL_MASK);
+ trng_ctrl_set(TRNG_CTRL_TRSSEN_MASK);
+
+ trng_test_set_uint_prop(prop, TRNG_STATUS_CERTF_MASK);
+ trng_check_certf_status();
+
+ trng_test_set_uint_prop(prop, TRNG_STATUS_DTF_MASK);
+ trng_check_dtf_status();
+
+ trng_reset();
+}
+
+int main(int argc, char **argv)
+{
+ int rc;
+
+ g_test_init(&argc, &argv, NULL);
+
+ #define TRNG_TEST_ADD(n) \
+ qtest_add_func("/hw/misc/xlnx-versal-trng/" #n, trng_test_ ## n);
+ TRNG_TEST_ADD(autogen);
+ TRNG_TEST_ADD(oneshot);
+ TRNG_TEST_ADD(per_str);
+ TRNG_TEST_ADD(forced_prng);
+ TRNG_TEST_ADD(fault_events);
+ #undef TRNG_TEST_ADD
+
+ trng_test_start();
+ rc = g_test_run();
+ trng_test_stop();
+
+ return rc;
+}
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 0c84b61ae0..cded1d01fc 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -103,7 +103,11 @@ sha512-sve: CFLAGS=-O3 -march=armv8.1-a+sve
sha512-sve: sha512.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
-TESTS += sha512-sve
+sve-str: CFLAGS=-O1 -march=armv8.1-a+sve
+sve-str: sve-str.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+
+TESTS += sha512-sve sve-str
ifneq ($(GDB),)
GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py
diff --git a/tests/tcg/aarch64/sve-str.c b/tests/tcg/aarch64/sve-str.c
new file mode 100644
index 0000000000..ae271c9d87
--- /dev/null
+++ b/tests/tcg/aarch64/sve-str.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <sys/prctl.h>
+
+#define N (256 + 16)
+
+static int __attribute__((noinline)) test(int vl)
+{
+ unsigned char buf[N];
+ int err = 0;
+
+ for (int i = 0; i < N; ++i) {
+ buf[i] = (unsigned char)i;
+ }
+
+ asm volatile (
+ "mov z0.b, #255\n\t"
+ "str z0, %0"
+ : : "m" (buf) : "z0", "memory");
+
+ for (int i = 0; i < vl; ++i) {
+ if (buf[i] != 0xff) {
+ fprintf(stderr, "vl %d, index %d, expected 255, got %d\n",
+ vl, i, buf[i]);
+ err = 1;
+ }
+ }
+
+ for (int i = vl; i < N; ++i) {
+ if (buf[i] != (unsigned char)i) {
+ fprintf(stderr, "vl %d, index %d, expected %d, got %d\n",
+ vl, i, (unsigned char)i, buf[i]);
+ err = 1;
+ }
+ }
+
+ return err;
+}
+
+int main()
+{
+ int err = 0;
+
+ for (int i = 16; i <= 256; i += 16) {
+ if (prctl(PR_SVE_SET_VL, i, 0, 0, 0, 0) == i) {
+ err |= test(i);
+ }
+ }
+ return err;
+}