automation/gitlab-ci/build.yaml | 8 ++ automation/gitlab-ci/test.yaml | 8 ++ .../scripts/qemu-boot-selftest-arm64.sh | 72 +++++++++++++ docs/misc/xen-command-line.pandoc | 10 ++ xen/arch/arm/Kconfig | 13 +++ xen/arch/arm/Makefile | 1 + xen/arch/arm/gic-test.c | 102 ++++++++++++++++++ xen/arch/arm/gic.c | 5 + xen/arch/arm/include/asm/gic.h | 8 ++ xen/arch/arm/include/asm/setup.h | 9 ++ xen/arch/arm/setup.c | 20 ++++ xen/arch/arm/smpboot.c | 3 + xen/arch/arm/xen.lds.S | 4 + 13 files changed, 263 insertions(+) create mode 100755 automation/scripts/qemu-boot-selftest-arm64.sh create mode 100644 xen/arch/arm/gic-test.c
Boot self-tests (also referred to as boot-time tests or power-on
self-tests) are intended to check that Xen has configured the hardware
correctly before bringing up any domains.
Introduce tests to confirm that, using a dedicated SGI (GIC_SGI_TEST):
1. A cpu can send the SGI to itself
2. A cpu can send the SGI to another specific CPU (CPU0)
3. A cpu can send the SGI to all the other CPUs
Each CPU counts the test SGIs it takes. A sender samples those counters
before sending and then waits for the count of every CPU it targeted to
change, which is how it tells that the SGI was really delivered. The
counters are never reset, so comparing against a sample rather than an
absolute value keeps concurrent senders from disturbing each other.
A test reports a failure by panic(), so Xen never continues on a
platform where SGI delivery is broken. When the tests pass, Xen carries
on booting normally.
Also introduce a config CONFIG_BOOT_SELFTEST which enables these
tests. It depends on DEBUG and is off unless explicitly enabled.
Also introduce a boolean command line parameter "gic-test", so that a
build with CONFIG_BOOT_SELFTEST enabled can be shipped but the tests
selected at boot. It is documented in
docs/misc/xen-command-line.pandoc.
In order to keep all the boot self-tests together in the binary, a
separate section "initcallboottest" is introduced. Tests are registered
using __initcallboottest() and run once on every CPU by
do_init_boottests(), bracketed by begin/end messages. They run before
any domain is created on the primary core, and before the idle loop is
entered on a secondary core.
Signed-off-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
---
Link to v3:
https://www.mail-archive.com/xen-devel@lists.xenproject.org/msg215355.html
Upstream CI run:
https://gitlab.com/xen-project/people/ayankuma/xen/-/pipelines/2853709475
Changes in v4:
- gic-test.c is SPDX GPL-2.0-only; COPYING states v2-only is the only
valid version. v3 had changed this to GPL-2.0-or-later to match the
neighbouring GIC files, which was wrong (Julien).
- The SGI handler uses ACCESS_ONCE() for the increment as well as the
read, since the counter is published to another CPU. Not an atomic:
only the receiving CPU writes its own counter (Julien).
- Dropped the file name from the gic_sgi_test_interrupt() comment in
asm/gic.h (Julien).
- asm/setup.h is included after asm/tee/tee.h in smpboot.c (Julien).
- Sent as a new thread rather than in-reply-to v3 (Julien).
- Rebased onto current staging (adbbbd47a1); applied unchanged.
automation/gitlab-ci/build.yaml | 8 ++
automation/gitlab-ci/test.yaml | 8 ++
.../scripts/qemu-boot-selftest-arm64.sh | 72 +++++++++++++
docs/misc/xen-command-line.pandoc | 10 ++
xen/arch/arm/Kconfig | 13 +++
xen/arch/arm/Makefile | 1 +
xen/arch/arm/gic-test.c | 102 ++++++++++++++++++
xen/arch/arm/gic.c | 5 +
xen/arch/arm/include/asm/gic.h | 8 ++
xen/arch/arm/include/asm/setup.h | 9 ++
xen/arch/arm/setup.c | 20 ++++
xen/arch/arm/smpboot.c | 3 +
xen/arch/arm/xen.lds.S | 4 +
13 files changed, 263 insertions(+)
create mode 100755 automation/scripts/qemu-boot-selftest-arm64.sh
create mode 100644 xen/arch/arm/gic-test.c
diff --git a/automation/gitlab-ci/build.yaml b/automation/gitlab-ci/build.yaml
index 27eefec5f9..3d37e0b572 100644
--- a/automation/gitlab-ci/build.yaml
+++ b/automation/gitlab-ci/build.yaml
@@ -420,6 +420,14 @@ alpine-3.24-arm64-gcc-debug:
CONFIG_UBSAN=y
CONFIG_UBSAN_FATAL=y
+alpine-3.24-arm64-gcc-debug-boot-selftest:
+ extends: .gcc-arm64-build-debug
+ <<: *build-test
+ variables:
+ CONTAINER: alpine:3.24-arm64v8
+ EXTRA_XEN_CONFIG: |
+ CONFIG_BOOT_SELFTEST=y
+
alpine-3.24-arm64-gcc-randconfig:
extends: .gcc-arm64-build
variables:
diff --git a/automation/gitlab-ci/test.yaml b/automation/gitlab-ci/test.yaml
index 61adc1baff..96127995d7 100644
--- a/automation/gitlab-ci/test.yaml
+++ b/automation/gitlab-ci/test.yaml
@@ -605,6 +605,14 @@ qemu-smoke-dom0less-arm64-gcc-debug-gicv3:
- *arm64-test-needs
- alpine-3.24-arm64-gcc-debug
+qemu-smoke-boot-selftest-arm64-gcc-debug:
+ extends: .qemu-arm64
+ script:
+ - ./automation/scripts/qemu-boot-selftest-arm64.sh 2>&1 | tee ${LOGFILE}
+ needs:
+ - *arm64-test-needs
+ - alpine-3.24-arm64-gcc-debug-boot-selftest
+
qemu-smoke-dom0less-arm64-gcc-debug-staticmem:
extends: .qemu-arm64
script:
diff --git a/automation/scripts/qemu-boot-selftest-arm64.sh b/automation/scripts/qemu-boot-selftest-arm64.sh
new file mode 100755
index 0000000000..e36bd8d94a
--- /dev/null
+++ b/automation/scripts/qemu-boot-selftest-arm64.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+set -ex -o pipefail
+
+# Boot Xen under QEMU with gic-test in xen,xen-bootargs and check that every
+# self-test reported OK and that Xen carried on booting.
+
+XEN=binaries/xen
+# qemu-system-aarch64 comes from the debian:13-arm64v8 test container, the
+# same way the other qemu-smoke-*-arm64 scripts get it.
+QEMU=qemu-system-aarch64
+DTB_RAW=binaries/virt.dtb
+DTB=binaries/virt-bootselftest.dtb
+LOG=smoke.serial
+
+NR_CPUS=4
+
+test -f ${XEN}
+
+${QEMU} \
+ -machine virt,virtualization=true,gic-version=3,dumpdtb=${DTB_RAW} \
+ -cpu cortex-a57 -m 1024 -smp ${NR_CPUS} -display none -net none
+
+cp ${DTB_RAW} ${DTB}
+fdtput -t s ${DTB} /chosen xen,xen-bootargs \
+ "gic-test console=dtuart sync_console"
+
+rm -f ${LOG}
+timeout 60 ${QEMU} \
+ -machine virt,virtualization=true,gic-version=3 \
+ -cpu cortex-a57 -m 1024 -smp ${NR_CPUS} \
+ -serial file:${LOG} \
+ -monitor none -display none -no-reboot -net none \
+ -dtb ${DTB} \
+ -kernel ${XEN} || true
+
+fail=0
+
+check() {
+ local what=$1
+ local expected=$2
+ local got
+
+ got=$(grep -c -- "${what}" ${LOG} || true)
+ if [ "${got}" -ne "${expected}" ]; then
+ echo "FAIL: '${what}': expected ${expected}, got ${got}"
+ fail=1
+ return
+ fi
+
+ echo "OK: '${what}' x${expected}"
+}
+
+# Every CPU sends an SGI to itself...
+check "GIC selftest: CPU[0-9]*: SGI to self: OK" ${NR_CPUS}
+# ...every secondary CPU sends one to CPU0...
+check "GIC selftest: CPU[0-9]*: SGI to CPU0: OK" $((NR_CPUS - 1))
+# ...and whichever CPU runs last sends one to all the others.
+check "GIC selftest: CPU[0-9]*: SGI to all but self: OK" 1
+
+check "boot self-tests done" ${NR_CPUS}
+check "GIC selftest: .*did not receive" 0
+
+# A passing self-test must leave Xen booting normally.
+check "LOADING DOMAIN 0\|Xen dom0less mode detected" 1
+
+if [ ${fail} -ne 0 ]; then
+ echo "FAILED"
+ exit 1
+fi
+
+echo "PASSED"
diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc
index b2c94ae56d..ea0e3368b1 100644
--- a/docs/misc/xen-command-line.pandoc
+++ b/docs/misc/xen-command-line.pandoc
@@ -1282,6 +1282,16 @@ available on Intel Panther Lake and Diamond Rapids CPUs, and AMD Zen6 CPUs.
FRED is fully supported on AMD hardware. On Intel hardware it is still tech
preview, and in particular not security supported.
+### gic-test (arm)
+> `= <boolean>`
+
+> Default: `false`
+
+Only available when `CONFIG_BOOT_SELFTEST` is enabled.
+
+Run the GIC SGI boot self-tests while each CPU is brought up. Xen panics if
+an SGI is not delivered; otherwise it carries on booting normally.
+
### gnttab
> `= List of [ max-ver:<integer>, transitive=<bool>, transfer=<bool> ]`
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 843a43897e..92a1788854 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -498,6 +498,19 @@ config ARM64_HARDEN_BRANCH_PREDICTOR
config ARM32_HARDEN_BRANCH_PREDICTOR
def_bool y if ARM_32 && HARDEN_BRANCH_PREDICTOR
+config BOOT_SELFTEST
+ bool "Enable boot self-tests"
+ depends on DEBUG
+ help
+ This option enables boot self-tests. They are intended to check that
+ Xen has configured the hardware correctly before bringing up any
+ domains. A failure is reported by panic(); when the tests pass, Xen
+ boots normally.
+
+ Selected at boot with the "gic-test" command line option.
+
+ If unsure, say N.
+
source "arch/arm/platforms/Kconfig"
source "common/Kconfig"
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index b7afd3e58c..71f177824b 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -24,6 +24,7 @@ obj-y += domctl.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-y += efi/
obj-y += gic.o
+obj-$(CONFIG_BOOT_SELFTEST) += gic-test.o
obj-$(CONFIG_GICV2) += gic-v2.o
obj-$(CONFIG_GICV3) += gic-v3.o
obj-$(CONFIG_HAS_ITS) += gic-v3-its.o
diff --git a/xen/arch/arm/gic-test.c b/xen/arch/arm/gic-test.c
new file mode 100644
index 0000000000..c2ffe2e9b9
--- /dev/null
+++ b/xen/arch/arm/gic-test.c
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/atomic.h>
+#include <xen/cpumask.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/param.h>
+#include <xen/percpu.h>
+#include <xen/smp.h>
+#include <xen/time.h>
+#include <asm/gic.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+
+static bool __initdata opt_gic_test;
+boolean_param("gic-test", opt_gic_test);
+
+static DEFINE_PER_CPU(unsigned int, sgi_test_count);
+
+void gic_sgi_test_interrupt(void)
+{
+ ACCESS_ONCE(this_cpu(sgi_test_count))++;
+}
+
+static unsigned int __init sgi_count(unsigned int cpu)
+{
+ return ACCESS_ONCE(per_cpu(sgi_test_count, cpu));
+}
+
+static void __init snapshot_sgi(unsigned int *before)
+{
+ unsigned int cpu;
+
+ for_each_online_cpu ( cpu )
+ before[cpu] = sgi_count(cpu);
+}
+
+/*
+ * Wait for every CPU in @mask to take one more GIC_SGI_TEST than the count
+ * recorded in @before.
+ */
+static void __init expect_sgi(const cpumask_t *mask,
+ const unsigned int *before, const char *what)
+{
+ s_time_t deadline = NOW() + MILLISECS(100);
+ unsigned int cpu;
+
+ for_each_cpu ( cpu, mask )
+ {
+ while ( sgi_count(cpu) == before[cpu] )
+ {
+ if ( NOW() > deadline )
+ panic("GIC selftest: %s: CPU%u did not receive GIC_SGI_TEST\n",
+ what, cpu);
+ cpu_relax();
+ }
+ }
+
+ printk("GIC selftest: CPU%u: %s: OK\n", smp_processor_id(), what);
+}
+
+/*
+ * "All but self" is only meaningful once every CPU can take an SGI, so it is
+ * run by whichever CPU observes that it is the last one to get here.
+ */
+static int __init gic_sgi_selftest(void)
+{
+ static atomic_t __initdata seen = ATOMIC_INIT(0);
+ unsigned int before[NR_CPUS] = { };
+ unsigned int cpu = smp_processor_id();
+
+ if ( !opt_gic_test )
+ return 0;
+
+ snapshot_sgi(before);
+ send_SGI_self(GIC_SGI_TEST);
+ expect_sgi(cpumask_of(cpu), before, "SGI to self");
+
+ if ( cpu != 0 )
+ {
+ snapshot_sgi(before);
+ send_SGI_one(0, GIC_SGI_TEST);
+ expect_sgi(cpumask_of(0), before, "SGI to CPU0");
+ }
+
+ if ( atomic_add_return(1, &seen) == num_online_cpus() )
+ {
+ cpumask_t target;
+
+ cpumask_andnot(&target, &cpu_online_map, cpumask_of(cpu));
+
+ if ( !cpumask_empty(&target) )
+ {
+ snapshot_sgi(before);
+ send_SGI_allbutself(GIC_SGI_TEST);
+ expect_sgi(&target, before, "SGI to all but self");
+ }
+ }
+
+ return 0;
+}
+__initcallboottest(gic_sgi_selftest);
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 078049e741..6a132c64e1 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -330,6 +330,11 @@ static void do_static_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
case GIC_SGI_CALL_FUNCTION:
smp_call_function_interrupt();
break;
+#ifdef CONFIG_BOOT_SELFTEST
+ case GIC_SGI_TEST:
+ gic_sgi_test_interrupt();
+ break;
+#endif
default:
panic("Unhandled SGI %d on CPU%d\n", sgi, smp_processor_id());
break;
diff --git a/xen/arch/arm/include/asm/gic.h b/xen/arch/arm/include/asm/gic.h
index ee2c26adb4..33dca9dcc6 100644
--- a/xen/arch/arm/include/asm/gic.h
+++ b/xen/arch/arm/include/asm/gic.h
@@ -306,6 +306,9 @@ enum gic_sgi {
GIC_SGI_EVENT_CHECK,
GIC_SGI_DUMP_STATE,
GIC_SGI_CALL_FUNCTION,
+#ifdef CONFIG_BOOT_SELFTEST
+ GIC_SGI_TEST,
+#endif
GIC_SGI_STATIC_MAX,
};
@@ -321,6 +324,11 @@ extern void send_SGI_one(unsigned int cpu, enum gic_sgi sgi);
extern void send_SGI_self(enum gic_sgi sgi);
extern void send_SGI_allbutself(enum gic_sgi sgi);
+#ifdef CONFIG_BOOT_SELFTEST
+/* Record a GIC_SGI_TEST delivered to this CPU. */
+void gic_sgi_test_interrupt(void);
+#endif
+
/* print useful debug info */
extern void gic_dump_info(struct vcpu *v);
extern void gic_dump_vgic_info(struct vcpu *v);
diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
index 2af7805125..c491c56729 100644
--- a/xen/arch/arm/include/asm/setup.h
+++ b/xen/arch/arm/include/asm/setup.h
@@ -48,6 +48,15 @@ void setup_mm(void);
extern uint32_t hyp_traps_vector[];
void init_traps(void);
+#ifdef CONFIG_BOOT_SELFTEST
+#define __initcallboottest(fn) \
+ static const initcall_t __initcall_##fn __init_call("boottest") = (fn)
+
+void do_init_boottests(void);
+#else
+static inline void do_init_boottests(void) {}
+#endif
+
int handle_device(struct domain *d, struct dt_device_node *dev, p2m_type_t p2mt,
struct rangeset *iomem_ranges, struct rangeset *irq_ranges);
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 79bbf24305..16f899dff5 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -81,6 +81,24 @@ static void __init init_idle_domain(void)
/* TODO: setup_idle_pagetable(); */
}
+#ifdef CONFIG_BOOT_SELFTEST
+extern const initcall_t __initcall_boot_test_start[],
+ __initcall_boot_test_end[];
+
+void do_init_boottests(void)
+{
+ const initcall_t *call;
+
+ printk("CPU%u: boot self-tests start\n", smp_processor_id());
+
+ for ( call = __initcall_boot_test_start; call < __initcall_boot_test_end;
+ call++ )
+ (*call)();
+
+ printk("CPU%u: boot self-tests done\n", smp_processor_id());
+}
+#endif /* CONFIG_BOOT_SELFTEST */
+
static const char * __initdata processor_implementers[] = {
['A'] = "ARM Limited",
['B'] = "Broadcom Corporation",
@@ -471,6 +489,8 @@ void asmlinkage __init noreturn start_xen(unsigned long fdt_paddr)
enable_errata_workarounds();
enable_cpu_features();
+ do_init_boottests();
+
/* Create initial domain 0. */
if ( !is_dom0less_mode() )
create_dom0();
diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
index 1806c47a08..8c9072f3c1 100644
--- a/xen/arch/arm/smpboot.c
+++ b/xen/arch/arm/smpboot.c
@@ -30,6 +30,7 @@
#include <asm/psci.h>
#include <asm/acpi.h>
#include <asm/tee/tee.h>
+#include <asm/setup.h>
/* Override macros from asm/page.h to make them work with mfn_t */
#undef virt_to_mfn
@@ -413,6 +414,8 @@ void asmlinkage noreturn start_secondary(void)
printk(XENLOG_DEBUG "CPU %u booted.\n", smp_processor_id());
+ do_init_boottests();
+
startup_cpu_idle_loop();
}
diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S
index d4d9594033..7399ef4804 100644
--- a/xen/arch/arm/xen.lds.S
+++ b/xen/arch/arm/xen.lds.S
@@ -146,6 +146,10 @@ SECTIONS
*(.initcall1.init)
__initcall_end = .;
+ __initcall_boot_test_start = .;
+ *(.initcallboottest.init)
+ __initcall_boot_test_end = .;
+
. = ALIGN(4);
__alt_instructions = .;
*(.altinstructions)
--
2.25.1
Hi Ayan,
On 16/09/2026 12:35, Ayan Kumar Halder wrote:
> +static void __init expect_sgi(const cpumask_t *mask,
> + const unsigned int *before, const char *what)
> +{
> + s_time_t deadline = NOW() + MILLISECS(100);
> + unsigned int cpu;
> +
> + for_each_cpu ( cpu, mask )
> + {
> + while ( sgi_count(cpu) == before[cpu] )
> + {
> + if ( NOW() > deadline )
> + panic("GIC selftest: %s: CPU%u did not receive GIC_SGI_TEST\n",
> + what, cpu);
> + cpu_relax();
> + }
> + }
> +
> + printk("GIC selftest: CPU%u: %s: OK\n", smp_processor_id(), what);
> +}
> +
> +/*
> + * "All but self" is only meaningful once every CPU can take an SGI, so it is
> + * run by whichever CPU observes that it is the last one to get here.
> + */
> +static int __init gic_sgi_selftest(void)
> +{
> + static atomic_t __initdata seen = ATOMIC_INIT(0);
> + unsigned int before[NR_CPUS] = { };
Sorry I didn't spot this earlier. NR_CPUS can be quite large (up to
16K). So this will blow up the stack.
There are two options:
1) Use static
2) Temporarily allocate "before"
I don't have a strong opinion on which way to go with.
Cheers,
--
Julien Grall
On 17/09/2026 08:57, Grall, Julien wrote:
> Hi Ayan,
Hi Julien,
>
> On 16/09/2026 12:35, Ayan Kumar Halder wrote:
>> +static void __init expect_sgi(const cpumask_t *mask,
>> + const unsigned int *before, const char
>> *what)
>> +{
>> + s_time_t deadline = NOW() + MILLISECS(100);
>> + unsigned int cpu;
>> +
>> + for_each_cpu ( cpu, mask )
>> + {
>> + while ( sgi_count(cpu) == before[cpu] )
>> + {
>> + if ( NOW() > deadline )
>> + panic("GIC selftest: %s: CPU%u did not receive
>> GIC_SGI_TEST\n",
>> + what, cpu);
>> + cpu_relax();
>> + }
>> + }
>> +
>> + printk("GIC selftest: CPU%u: %s: OK\n", smp_processor_id(), what);
>> +}
>> +
>> +/*
>> + * "All but self" is only meaningful once every CPU can take an SGI,
>> so it is
>> + * run by whichever CPU observes that it is the last one to get here.
>> + */
>> +static int __init gic_sgi_selftest(void)
>> +{
>> + static atomic_t __initdata seen = ATOMIC_INIT(0);
>> + unsigned int before[NR_CPUS] = { };
>
> Sorry I didn't spot this earlier. NR_CPUS can be quite large (up to
> 16K). So this will blow up the stack.
As this is a test, we have hardcoded NR_CPUS = 4 in
automation/scripts/qemu-boot-selftest-arm64.sh.
If there are 16K CPUs, our test only checks for 4 cpus only.
However if there is still a concern ....
>
> There are two options:
> 1) Use static
> 2) Temporarily allocate "before"
>
> I don't have a strong opinion on which way to go with.
I can use static.
- Ayan
>
> Cheers,
>
Hi Ayan,
On 17/09/2026 14:13, Halder, Ayan Kumar wrote:
> On 17/09/2026 08:57, Grall, Julien wrote:
>> On 16/09/2026 12:35, Ayan Kumar Halder wrote:
>>> +static void __init expect_sgi(const cpumask_t *mask,
>>> + const unsigned int *before, const char
>>> *what)
>>> +{
>>> + s_time_t deadline = NOW() + MILLISECS(100);
>>> + unsigned int cpu;
>>> +
>>> + for_each_cpu ( cpu, mask )
>>> + {
>>> + while ( sgi_count(cpu) == before[cpu] )
>>> + {
>>> + if ( NOW() > deadline )
>>> + panic("GIC selftest: %s: CPU%u did not receive
>>> GIC_SGI_TEST\n",
>>> + what, cpu);
>>> + cpu_relax();
>>> + }
>>> + }
>>> +
>>> + printk("GIC selftest: CPU%u: %s: OK\n", smp_processor_id(), what);
>>> +}
>>> +
>>> +/*
>>> + * "All but self" is only meaningful once every CPU can take an SGI,
>>> so it is
>>> + * run by whichever CPU observes that it is the last one to get here.
>>> + */
>>> +static int __init gic_sgi_selftest(void)
>>> +{
>>> + static atomic_t __initdata seen = ATOMIC_INIT(0);
>>> + unsigned int before[NR_CPUS] = { };
>>
>> Sorry I didn't spot this earlier. NR_CPUS can be quite large (up to
>> 16K). So this will blow up the stack.
We discussed this offline at Xen Summit. But I will answer here as well.
>
> As this is a test, we have hardcoded NR_CPUS = 4 in automation/scripts/
> qemu-boot-selftest-arm64.sh.
I agree with your current test harness we only test 4 CPUs. However,
this is not enforced by the Kconfig in Xen. So anyone could modify the
script (or write their own) with a much higher number of NR_CPUS
(possibly to match the number of pCPUs on their hardware).
Depending on the value, they could face a stack overflow.
>
> If there are 16K CPUs, our test only checks for 4 cpus only.
>
> However if there is still a concern ....
I would preferred if this is solved. Assuming this is fixed:
Reviewed-by: Julien Grall <julien@xen.org>
Cheers,
--
Julien Grall
© 2016 - 2026 Red Hat, Inc.