[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v2 2/6] automation/qtb: add jinja2 device trees for riscv64 smoke tests


  • To: Baptiste Le Duc <baptiste.le-duc@xxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
  • Date: Thu, 22 Oct 2026 16:01:59 +0200
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=20251104 header.d=gmail.com header.i="@gmail.com" header.h="Content-Transfer-Encoding:Content-Type:In-Reply-To:From:Content-Language:References:Cc:To:Subject:User-Agent:MIME-Version:Date:Message-ID"
  • Cc: Doug Goldstein <cardoe@xxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>
  • Delivery-date: Thu, 22 Oct 2026 14:02:10 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>



On 8/27/26 11:42 AM, Baptiste Le Duc wrote:
The dom0less RISC-V smoke tests need a host device tree describing the
platform (CPUs, APLIC/IMSIC, uart). It varies per machine (hart count, MMU
type), so a single static .dts cannot cover the test matrix.

Add dts/qemu-host.dts.j2, a template of the QEMU virt platform in
aia=aplic-imsic mode: per-hart cpu/cpu-intc nodes, the M- and S-mode APLIC
and IMSIC pairs, CLINT and the ns16550a uart. It takes ncpus, mmu_type and
xen_bootargs as arguments.

Values QEMU hardcodes are set as named constants matching their source
symbols (QEMU_UART0_IRQ, QEMU_IRQCHIP_NUM_SOURCES, ...) rather than
open-coded, so a QEMU-side change is easy to trace.

We want to have more strong position why we need a template for host instead of using what QEMU could provide with --machinedump. Probably we want to double check again if --machinedump isn't enough... But I am okay to proceed with template too.

The template is inert on its own: the generated dtb will be used in next
patch.

Please describe what the template is for instead of referring to the
next patch: the commit message should stand on its own.


Assisted-by: Claude:claude-opus-5
Signed-off-by: Baptiste Le Duc <baptiste.le-duc@xxxxxxxxxx>
---
  .../scripts/qtb/riscv/dts/qemu-host.dts.j2    | 160 ++++++++++++++++++
  1 file changed, 160 insertions(+)
  create mode 100644 automation/scripts/qtb/riscv/dts/qemu-host.dts.j2

diff --git a/automation/scripts/qtb/riscv/dts/qemu-host.dts.j2 
b/automation/scripts/qtb/riscv/dts/qemu-host.dts.j2
new file mode 100644
index 0000000000..13a8e983ce
--- /dev/null
+++ b/automation/scripts/qtb/riscv/dts/qemu-host.dts.j2
@@ -0,0 +1,160 @@
+/dts-v1/;
+
+{#-
+ * Jinja2 QEMU "virt" platform device tree for Xen RISC-V tests.
+ *
+ * Interrupt controller: APLIC in MSI mode + IMSIC
+ * (QEMU -M virt,aia=aplic-imsic).
+ *
+ * Rendered by xen_dt.py.
+ *
+ * Variables:
+ *   ncpus        - number of physical harts                (int, >= 1)
+ *   mmu_type     - Xen host MMU type, e.g. "sv39"          (string)
+ *   xen_bootargs - Xen command line                        (string)
+ *
+ * Per-hart nodes are labelled cpu<i> / cpu<i>_intc and referenced with &label.
+ *
+ * No `aia-guests=N`, so no VS-mode guest files: IMSIC reg size is
+ * ncpus * page size.
+-#}
+{#- Values QEMU hardcodes, need to be described to Xen -#}
+{%- set QEMU_TIMEBASE_FREQUENCY = 10000000 %}   {#- 
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ -#}
+{%- set QEMU_IRQCHIP_NUM_SOURCES = 96 %}        {#- VIRT_IRQCHIP_NUM_SOURCES 
(virt.h) -#}

What if virt.h here?

+{%- set QEMU_IRQCHIP_NUM_MSIS = 255 %}          {#- VIRT_IRQCHIP_NUM_MSIS -#}
+{%- set QEMU_UART_CLOCK_FREQUENCY = 3686400 %}  {#- create_fdt_uart() -#}
+{%- set QEMU_UART0_IRQ = 10 %}                  {#- UART0_IRQ -#}
+{%- set QEMU_IMSIC_PAGE_SZ = 0x1000 %}          {#- IMSIC_MMIO_PAGE_SZ -#}
+
+{%- set IRQ_TYPE_LEVEL_HIGH = 4 %}
+{%- set APLIC_IRQ_CELLS = 2 %}
+
+{%- set IRQ_M_SOFT = 3 %}
+{%- set IRQ_M_TIMER = 7 %}
+{%- set IRQ_S_EXT = 9 %}
+{%- set IRQ_M_EXT = 11 %}
+
+/ {
+    #address-cells = <0x02>;
+    #size-cells = <0x02>;
+    compatible = "riscv-virtio";
+    model = "riscv-virtio,qemu";
+
+    memory@80000000 {
+        device_type = "memory";
+        reg = <0x00 0x80000000 0x00 0x80000000>;
+    };
+
+    cpus {
+        #address-cells = <0x01>;
+        #size-cells = <0x00>;
+        timebase-frequency = <{{ QEMU_TIMEBASE_FREQUENCY }}>;
+{% for i in range(ncpus) %}
+        cpu{{ i }}: cpu@{{ i }} {
+            device_type = "cpu";
+            reg = <0x{{ '%x' % i }}>;
+            status = "okay";
+            compatible = "riscv";
+            riscv,cbop-block-size = <0x40>;
+            riscv,cboz-block-size = <0x40>;
+            riscv,cbom-block-size = <0x40>;
+            riscv,isa = 
"rv64imafdch_zicntr_zicsr_zifencei_zihintpause_zihpm_zba_zbb_zbs_smstateen_svpbmt_smaia_ssaia";

Probably, it could also make sense to not hard-code isa property as potentiall we could have tests with different set of extensions.

Also, this is a hand-picked subset: Zicbom/Zicboz/Zicbop are missing although their block sizes are set just above. I haven't checked what will be needed in Xen to support this extension (or if we could count them as supported...) until this isn't clarified it seems like it will be better to drop:
+            riscv,cbop-block-size = <0x40>;
+            riscv,cboz-block-size = <0x40>;
+            riscv,cbom-block-size = <0x40>;

+            mmu-type = "riscv,{{ mmu_type }}";

Xen doesn't read mmu-type from the host CPU nodes: it is parsed only
from dom0less domain nodes (arch_parse_dom0less_node()). The host
stage-1 mode is fixed at build time (RV_STAGE1_MODE), and the G-stage
mode is detected at runtime by probing hgatp. So mmu_type has no effect
on Xen, and "It varies per machine (hart count, MMU type)" doesn't hold
for the MMU type.

It also makes the DT inaccurate: per the binding, mmu-type is the
largest translation mode the hart supports, which is sv57 for QEMU's
rv64 (that's what QEMU puts there), while the default here is sv48. If
the intent is to choose a guest's MMU mode, it belongs to the DomU
node.

+
+            cpu{{ i }}_intc: interrupt-controller@{{ i }} {

The node has a unit address but no reg, which makes dtc warn
(unit_address_vs_reg). QEMU and the binding use plain
"interrupt-controller".

It seems like removing of "@{{ i }}" could be enough.

+                #interrupt-cells = <0x01>;
+                interrupt-controller;
+                compatible = "riscv,cpu-intc";
+            };
+        };
+{% endfor %}
+        cpu-map {
+
+            cluster0 {
+{% for i in range(ncpus) %}
+                core{{ i }} {
+                    cpu = <&cpu{{ i }}>;
+                };
+{% endfor %}
+            };
+        };
+    };
+
+    soc {
+        #address-cells = <0x02>;
+        #size-cells = <0x02>;
+        compatible = "simple-bus";
+        ranges;
+
+        serial@10000000 {
+            interrupts = <{{ QEMU_UART0_IRQ }} {{ IRQ_TYPE_LEVEL_HIGH }}>;
+            interrupt-parent = <&aplic_s>;
+            clock-frequency = <{{ QEMU_UART_CLOCK_FREQUENCY }}>;
+            reg = <0x00 0x10000000 0x00 0x100>;
+            compatible = "ns16550a";
+        };
+
+        aplic_s: aplic@d000000 {
+            riscv,num-sources = <{{ QEMU_IRQCHIP_NUM_SOURCES }}>;
+            reg = <0x00 0xd000000 0x00 0x8000>;
+            msi-parent = <&imsic_s>;
+            interrupt-controller;
+            #interrupt-cells = <{{ APLIC_IRQ_CELLS }}>;
+            compatible = "riscv,aplic";

The binding requires compatible = "qemu,aplic", "riscv,aplic", which is
also what QEMU generates. The same applies to both APLICs, and to the
IMSICs below ("qemu,imsics", "riscv,imsics").

+        };
+
+        aplic@c000000 {
+            riscv,delegate = <&aplic_s 0x01 {{ QEMU_IRQCHIP_NUM_SOURCES }}>;

The binding names this property riscv,delegation. QEMU emits both
riscv,delegate and riscv,delegation, while the template has only the
former.

~ Oleksii

+            riscv,children = <&aplic_s>;
+            riscv,num-sources = <{{ QEMU_IRQCHIP_NUM_SOURCES }}>;
+            reg = <0x00 0xc000000 0x00 0x8000>;
+            msi-parent = <&imsic_m>;
+            interrupt-controller;
+            #interrupt-cells = <{{ APLIC_IRQ_CELLS }}>;
+            compatible = "riscv,aplic";
+        };
+
+        imsic_s: imsics@28000000 {
+            riscv,num-ids = <{{ QEMU_IRQCHIP_NUM_MSIS }}>;
+            reg = <0x00 0x28000000 0x00 0x{{ '%x' % (ncpus * QEMU_IMSIC_PAGE_SZ) 
}}>;
+            interrupts-extended = <
+                {%- for i in range(ncpus) %}
+                    &cpu{{ i }}_intc {{ IRQ_S_EXT }}
+                {%- endfor %}
+            >;
+            msi-controller;
+            interrupt-controller;
+            #interrupt-cells = <0x00>;
+            compatible = "riscv,imsics";
+        };
+
+        imsic_m: imsics@24000000 {
+            riscv,num-ids = <{{ QEMU_IRQCHIP_NUM_MSIS }}>;
+            reg = <0x00 0x24000000 0x00 0x{{ '%x' % (ncpus * QEMU_IMSIC_PAGE_SZ) 
}}>;
+            interrupts-extended = <
+                {%- for i in range(ncpus) %}
+                    &cpu{{ i }}_intc {{ IRQ_M_EXT }}
+                {%- endfor %}
+            >;
+            msi-controller;
+            interrupt-controller;
+            #interrupt-cells = <0x00>;
+            compatible = "riscv,imsics";
+        };
+
+        clint@2000000 {
+            interrupts-extended = <
+                {%- for i in range(ncpus) %}
+                    &cpu{{ i }}_intc {{ IRQ_M_SOFT }} &cpu{{ i }}_intc {{ 
IRQ_M_TIMER }}
+                {%- endfor %}
+            >;
+            reg = <0x00 0x2000000 0x00 0x10000>;
+            compatible = "sifive,clint0", "riscv,clint0";
+        };
+    };
+
+    chosen {
+        stdout-path = "/soc/serial@10000000";
+        xen,xen-bootargs = "{{ xen_bootargs }}";
+    };
+};




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.