From e10c9fd9ca4a63d8f11e830dd0bfd506c91b88d0 Mon Sep 17 00:00:00 2001 From: IkerGalardi Date: Thu, 26 Feb 2026 11:35:55 +0100 Subject: [PATCH 1/4] Add qemu_virt_aarch64_kvm platform This board differs from the standard qemu_virt_aarch64 board in that the entry point is in EL2 instead of EL1. This is necessary due to the lack of nested virtualization support on the KVM subsystem. Signed-off-by: IkerGalardi --- build_sdk.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/build_sdk.py b/build_sdk.py index c6781ad8..56ac582a 100644 --- a/build_sdk.py +++ b/build_sdk.py @@ -259,6 +259,21 @@ class ConfigInfo: "KernelArmExportPTMRUser": True, } | DEFAULT_KERNEL_OPTIONS_AARCH64, ), + BoardInfo( + name="qemu_virt_aarch64_kvm", + arch=KernelArch.AARCH64, + gcc_cpu="cortex-a53", + loader_link_address=0x70000000, + smp_cores=4, + kernel_options={ + "KernelPlatform": "qemu-arm-virt", + "KernelArmHypervisorSupport": False, + "QEMU_MEMORY": "2048", + # There is no peripheral timer, so we use the ARM + # architectural timer + "KernelArmExportPTMRUser": True, + } | DEFAULT_KERNEL_OPTIONS_AARCH64, + ), BoardInfo( name="qemu_virt_riscv64", arch=KernelArch.RISCV64, From 8636e8b20995dfa80bd1d07b2c636c5a2544ff93 Mon Sep 17 00:00:00 2001 From: IkerGalardi Date: Thu, 26 Feb 2026 12:24:16 +0100 Subject: [PATCH 2/4] Correctly default intialize supported boards Previously the defaults where applied ALWAYS, meaning that if some board tried to specialize a kernel building parameter that the default configuration did, it would get overwriten by the default configuration. This patch applies the specialization to the default configuration instead of doing it the other way around. Signed-off-by: IkerGalardi --- build_sdk.py | 104 +++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/build_sdk.py b/build_sdk.py index 56ac582a..c300bd8e 100644 --- a/build_sdk.py +++ b/build_sdk.py @@ -147,9 +147,9 @@ class ConfigInfo: gcc_cpu="cortex-a35", loader_link_address=0x80280000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "tqma8xqp1gb", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="zcu102", @@ -157,10 +157,10 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x40000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "zynqmp", "KernelARMPlatform": "zcu102", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="maaxboard", @@ -168,9 +168,9 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x50000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "maaxboard", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="imx8mm_evk", @@ -178,9 +178,9 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x41000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "imx8mm-evk", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="imx8mp_evk", @@ -188,9 +188,9 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x41000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "imx8mp-evk", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="imx8mq_evk", @@ -198,9 +198,9 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x41000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "imx8mq-evk", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="imx8mp_iotgate", @@ -208,11 +208,11 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x50000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "imx8mp-evk", "KernelCustomDTS": "custom_dts/iot-gate.dts", "KernelCustomDTSOverlay": "src/plat/imx8m-evk/overlay-imx8mp-evk.dts", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="odroidc2", @@ -220,9 +220,9 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x20000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "odroidc2", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="odroidc4", @@ -230,9 +230,9 @@ class ConfigInfo: gcc_cpu="cortex-a55", loader_link_address=0x20000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "odroidc4", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="ultra96v2", @@ -240,10 +240,10 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x40000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "zynqmp", "KernelARMPlatform": "ultra96v2", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="qemu_virt_aarch64", @@ -251,13 +251,13 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x70000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "qemu-arm-virt", "QEMU_MEMORY": "2048", # There is no peripheral timer, so we use the ARM # architectural timer "KernelArmExportPTMRUser": True, - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="qemu_virt_aarch64_kvm", @@ -265,14 +265,14 @@ class ConfigInfo: gcc_cpu="cortex-a53", loader_link_address=0x70000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "qemu-arm-virt", "KernelArmHypervisorSupport": False, "QEMU_MEMORY": "2048", # There is no peripheral timer, so we use the ARM # architectural timer "KernelArmExportPTMRUser": True, - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="qemu_virt_riscv64", @@ -280,10 +280,10 @@ class ConfigInfo: gcc_cpu=None, loader_link_address=0x90000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_RISCV64 | { "KernelPlatform": "qemu-riscv-virt", "QEMU_MEMORY": "2048", - } | DEFAULT_KERNEL_OPTIONS_RISCV64, + }, ), BoardInfo( name="rpi4b_1gb", @@ -291,10 +291,10 @@ class ConfigInfo: gcc_cpu="cortex-a72", loader_link_address=0x10000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "bcm2711", "RPI4_MEMORY": 1024, - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="rpi4b_2gb", @@ -302,10 +302,10 @@ class ConfigInfo: gcc_cpu="cortex-a72", loader_link_address=0x10000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "bcm2711", "RPI4_MEMORY": 2048, - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="rpi4b_4gb", @@ -313,10 +313,10 @@ class ConfigInfo: gcc_cpu="cortex-a72", loader_link_address=0x10000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "bcm2711", "RPI4_MEMORY": 4096, - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="rpi4b_8gb", @@ -324,10 +324,10 @@ class ConfigInfo: gcc_cpu="cortex-a72", loader_link_address=0x10000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "bcm2711", "RPI4_MEMORY": 8192, - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="rockpro64", @@ -337,18 +337,18 @@ class ConfigInfo: # ROCKPRO64 has 4 Cortex-A53 cores and 2 Cortex-A72 cores, # we always run on the Cortex-A53s. smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "rockpro64", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="rock3b", arch=KernelArch.AARCH64, gcc_cpu="cortex-a55", loader_link_address=0x30000000, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_AARCH64 | { "KernelPlatform": "rk3568", - } | DEFAULT_KERNEL_OPTIONS_AARCH64, + }, ), BoardInfo( name="hifive_p550", @@ -356,9 +356,9 @@ class ConfigInfo: gcc_cpu=None, loader_link_address=0x90000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_RISCV64 | { "KernelPlatform": "hifive-p550", - } | DEFAULT_KERNEL_OPTIONS_RISCV64, + }, ), BoardInfo( name="star64", @@ -366,36 +366,36 @@ class ConfigInfo: gcc_cpu=None, loader_link_address=0x60000000, smp_cores=4, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_RISCV64 | { "KernelPlatform": "star64", - } | DEFAULT_KERNEL_OPTIONS_RISCV64, + }, ), BoardInfo( name="ariane", arch=KernelArch.RISCV64, gcc_cpu=None, loader_link_address=0x90000000, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_RISCV64 | { "KernelPlatform": "ariane", - } | DEFAULT_KERNEL_OPTIONS_RISCV64, + }, ), BoardInfo( name="cheshire", arch=KernelArch.RISCV64, gcc_cpu=None, loader_link_address=0x90000000, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_RISCV64 | { "KernelPlatform": "cheshire", - } | DEFAULT_KERNEL_OPTIONS_RISCV64, + }, ), BoardInfo( name="serengeti", arch=KernelArch.RISCV64, gcc_cpu=None, loader_link_address=0x90000000, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_RISCV64 | { "KernelPlatform": "cheshire", - } | DEFAULT_KERNEL_OPTIONS_RISCV64, + }, ), BoardInfo( name="x86_64_generic", @@ -403,10 +403,10 @@ class ConfigInfo: gcc_cpu="generic", loader_link_address=None, smp_cores=DEFAULT_X86_NUM_CPUS, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_X86_64 | { "KernelSupportPCID": False, "KernelVTX": False, - } | DEFAULT_KERNEL_OPTIONS_X86_64, + }, ), BoardInfo( name="x86_64_generic_vtx", @@ -414,11 +414,11 @@ class ConfigInfo: gcc_cpu="generic", loader_link_address=None, smp_cores=DEFAULT_X86_NUM_CPUS, - kernel_options={ + kernel_options=DEFAULT_KERNEL_OPTIONS_X86_64 | { "KernelSupportPCID": False, "KernelVTX": True, "KernelX86_64VTX64BitGuests": True, - } | DEFAULT_KERNEL_OPTIONS_X86_64, + }, ), ) From ee675f70a39d94af3b73c45538d0d1aef3dadc89 Mon Sep 17 00:00:00 2001 From: IkerGalardi Date: Thu, 26 Feb 2026 15:50:39 +0100 Subject: [PATCH 3/4] tool: remove arm hypervisor mode requirement Signed-off-by: IkerGalardi --- tool/microkit/src/main.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tool/microkit/src/main.rs b/tool/microkit/src/main.rs index 719ba9ab..4c04ba83 100644 --- a/tool/microkit/src/main.rs +++ b/tool/microkit/src/main.rs @@ -548,13 +548,6 @@ fn main() -> Result<(), String> { std::process::exit(1); } - if let Arch::Aarch64 = kernel_config.arch { - assert!( - kernel_config.hypervisor, - "Microkit tool expects a kernel with hypervisor mode enabled on AArch64." - ); - } - assert!( kernel_config.word_size == 64, "Microkit tool has various assumptions about the word size being 64-bits." From 751ade107da88c5379842517147ff37c25d3539c Mon Sep 17 00:00:00 2001 From: IkerGalardi Date: Mon, 2 Mar 2026 16:38:37 +0100 Subject: [PATCH 4/4] loader: only configure interrupt groups on hypervisor mode EL1 software can not access interrupt group registers on the GIC distributor. Signed-off-by: IkerGalardi --- loader/src/aarch64/init.c | 59 ++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/loader/src/aarch64/init.c b/loader/src/aarch64/init.c index 993895e4..9c676860 100644 --- a/loader/src/aarch64/init.c +++ b/loader/src/aarch64/init.c @@ -24,37 +24,40 @@ #if defined(CONFIG_PLAT_ZYNQMP_ZCU102) || defined(CONFIG_PLAT_ZYNQMP_ULTRA96V2) || defined(CONFIG_PLAT_QEMU_ARM_VIRT) static void configure_gicv2(void) { - /* The ZCU102 start in EL3, and then we drop to EL1(NS). - * - * The GICv2 supports security extensions (as does the CPU). - * - * The GIC sets any interrupt as either Group 0 or Group 1. - * A Group 0 interrupt can only be configured in secure mode, - * while Group 1 interrupts can be configured from non-secure mode. - * - * As seL4 runs in non-secure mode, and we want seL4 to have - * the ability to configure interrupts, at this point we need - * to put all interrupts into Group 1. - * - * GICD_IGROUPn starts at offset 0x80. - * - * 0xF901_0000. - * - * Future work: On multicore systems the distributor setup - * only needs to be called once, while the GICC registers - * should be set for each CPU. - */ - puts("LDR|INFO: Setting all interrupts to Group 1\n"); - uint32_t gicd_typer = *((volatile uint32_t *)(GICD_BASE + 0x4)); - uint32_t it_lines_number = gicd_typer & 0x1f; - puts("LDR|INFO: GICv2 ITLinesNumber: "); - puthex32(it_lines_number); - puts("\n"); + if (is_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) { + /* The ZCU102 start in EL3, and then we drop to EL1(NS). + * + * The GICv2 supports security extensions (as does the CPU). + * + * The GIC sets any interrupt as either Group 0 or Group 1. + * A Group 0 interrupt can only be configured in secure mode, + * while Group 1 interrupts can be configured from non-secure mode. + * + * As seL4 runs in non-secure mode, and we want seL4 to have + * the ability to configure interrupts, at this point we need + * to put all interrupts into Group 1. + * + * GICD_IGROUPn starts at offset 0x80. + * + * 0xF901_0000. + * + * Future work: On multicore systems the distributor setup + * only needs to be called once, while the GICC registers + * should be set for each CPU. + */ + puts("LDR|INFO: Setting all interrupts to Group 1\n"); + uint32_t gicd_typer = *((volatile uint32_t *)(GICD_BASE + 0x4)); + uint32_t it_lines_number = gicd_typer & 0x1f; + puts("LDR|INFO: GICv2 ITLinesNumber: "); + puthex32(it_lines_number); + puts("\n"); - for (uint32_t i = 0; i <= it_lines_number; i++) { - *((volatile uint32_t *)(GICD_BASE + 0x80 + (i * 4))) = 0xFFFFFFFF; + for (uint32_t i = 0; i <= it_lines_number; i++) { + *((volatile uint32_t *)(GICD_BASE + 0x80 + (i * 4))) = 0xFFFFFFFF; + } } + /* For any interrupts to go through the interrupt priority mask * must be set appropriately. Only interrupts with priorities less * than this mask will interrupt the CPU.