From nobody Tue Aug 25 23:53:52 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1783353557; cv=none; d=zohomail.com; s=zohoarc; b=REQFadaRvu4TiHGLaP+sA/z1V4D+Bed75Z41+NcZna2WBcOUIprEXxL2MZubf7NT1KfYkEBEMDgds5qusCWaSTqm+JjPr6fPT9Um8lUavXu9/VciemAXR7J7RKe/RVFrVcMfeFsvzralX5BsSDAiNuCHeSmn8v9qisI9kHjU0G8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783353557; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=2hkhMYTJKPM49ZEEfJBa6VK+y/dGsOiFIcDLfi+stU0=; b=aRq9/x2dUtHQZwld0JtD8oO7CjKxLMavS3kN4/BALtbUd+6dRdo/VDNMXqMltPAXVUZC0C5qq9bz988N8WstgfOHtPhyEwi8tR36FPWXUUUzeNffdKZjpOF7fuBuSbBsUS0vryx2D9CgxcBjLBNesBmEUI8CGT5+34RBGfFn5lU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1783353557081595.9351084185494; Mon, 6 Jul 2026 08:59:17 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1355536.1610420 (Exim 4.92) (envelope-from ) id 1wglid-0003iS-8B; Mon, 06 Jul 2026 15:58:51 +0000 Received: by outflank-mailman (output) from mailman id 1355536.1610420; Mon, 06 Jul 2026 15:58:51 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wglic-0003di-7f; Mon, 06 Jul 2026 15:58:50 +0000 Received: by outflank-mailman (input) for mailman id 1355536; Mon, 06 Jul 2026 15:58:46 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) id 1wgliX-0002cM-By for xen-devel@lists.xenproject.org; Mon, 06 Jul 2026 15:58:45 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wgliW-00AcWu-Lk for xen-devel@lists.xenproject.org; Mon, 06 Jul 2026 17:58:44 +0200 Received: from [10.42.69.2] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4bd0b2-bab6-0a2a0a5309dd-0a2a45029ce2-12 for ; Mon, 06 Jul 2026 17:58:44 +0200 Received: from [209.85.128.42] (helo=mail-wm1-f42.google.com) by tlsNG-720697.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4bd0b4-5a27-0a2a45020019-d155802ac031-3 for ; Mon, 06 Jul 2026 17:58:44 +0200 Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-493d3135f62so11376875e9.2 for ; Mon, 06 Jul 2026 08:58:44 -0700 (PDT) Received: from fedora (user-109-243-144-234.play-internet.pl. [109.243.144.234]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-493cce03fa1sm284910325e9.11.2026.07.06.08.58.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jul 2026 08:58:43 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=20251104 header.d=gmail.com header.i="@gmail.com" header.h="Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783353524; x=1783958324; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=2hkhMYTJKPM49ZEEfJBa6VK+y/dGsOiFIcDLfi+stU0=; b=R96QsvSAZOs9WHEYW2wjikor/ZoVVidqEoWaHjWBzWSFZeR5bIqBrAHn5albQsjvrW WTO7eKuARi3KBdWRUsaXvn/bPSajIhgiJE9PkS4a+cfjz/G+NxHxuT1vQvoGutLxixt1 BkibH5mQ37KBZjZODnSQ0z7fcxXZnjK9W0yuP0iiTjEexUlPgF50vrbUB8pg+UDevyFY WYQuZ62yyiNb074Jo5FO/rVNs40gYRjtYtn9u85pHLrgrGpsiwDe61wZKuQeCG+V3lv8 y4voyQFlnI1JKEnDH9A363uYJ3PTVc4SBC6b5Wi0QoFG+l5DTLWO3rgNzPE5YoR1Umk5 X13A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783353524; x=1783958324; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=2hkhMYTJKPM49ZEEfJBa6VK+y/dGsOiFIcDLfi+stU0=; b=G3peeIxPSk175/+SK6KowJglpHoLRIbhB7tDaTFD10qBQiQrU1KW/uNAOOFnWvsgzW FJxGHf8rKdwX9PScWR9WDM2Ezb0SyL0oSGlpUGyYBC70NfFarkerlQyxsOFgGBfTDkkF aFayab0uLnZANHYvg4TKMaJSIzuD5OC+zjMQQIg3yyKzHS+lnDbvOPq2lBvFjPvynvhj tKCjFPfgyP+o7xCD6LyhPIy/Ja3210Jj0zziWb1l4GT4U4g3RWZsAxAoOHSGaT7jBGud JnVKCtvA+ZoV8tWUAapzeWRSE1jv19XYtfQm3ee1NwJ1DSxe5Ol7io5gBKuR3ZBm7WOm O6Og== X-Gm-Message-State: AOJu0YxZAj/OKavNi3Y+xwJkHf+zRcvgMue0N6bENY+s9c2fnsaOVb+Z uStsdyL9OQYbphFGLs100yXcJkig3q28icTSZFBGdjk7Gi2LN0tuo7GDcxaATw== X-Gm-Gg: AfdE7cnu5m0E+pWdjIyHx2bk4yZnu1WPakat+owGC/YQCbdfPHH2CoD813PWwRS4Ujt GTApQ5fvTLDH4ENp/Z+ebr0jQtjnUmKvyb2aIFiDfZjtJv3dFOYbHFTii3pbqLvlsgRkXMQ+0Cf UK/jN/P9JEfJfmSUQ5u4tYPw1HNDOaBtlXwJPFXKuU2QckjTu0jodZXSHNTAlQlVSioWnnMUZ17 Uv+7crd8nlZ3K72AsV3PTdKm6s0Zn5LZAu2Y3hUKQSUWHHgzmvim1JHDv9Yqx9t+E280Zy2pAwJ f34HPUyZPmqAPBzRhlqIU+OOB+PpvTAuEU6gH6G/JPZuaIAmsN3Ck5NqCXqAMzTpnzxvTqGauGQ 7RVKPWD6UMNX83C4jXShPlhfxdwJR+Eg3HO5QsqHwe01MFLQC6qxOooaTQS3b8wQs6g+BzWa6Wt BDOyyoIz36wYarDZ7WVssjQ/3QcQrn4MebhCwRxVCLZjqATqWeQj7p0wl09g== X-Received: by 2002:a05:600c:584c:b0:493:df11:eab4 with SMTP id 5b1f17b1804b1-493df11ebcdmr9153605e9.8.1783353523915; Mon, 06 Jul 2026 08:58:43 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Romain Caritey , Baptiste Le Duc , Oleksii Kurochko , Alistair Francis , Connor Davis , Andrew Cooper , Anthony PERARD , Michal Orzel , Jan Beulich , Julien Grall , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Stefano Stabellini Subject: [PATCH v5 19/26] xen/riscv: generate IMSIC DT node for guest domains Date: Mon, 6 Jul 2026 17:58:00 +0200 Message-ID: <7af5bcc9ef818926f02244f5d566541da06a0a16.1783331040.git.oleksii.kurochko@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-purgate-ID: tlsNG-720697/1783353524-5491A7C5-89C5769C/10/73395122804 X-purgate-type: spam X-purgate-size: 10372 X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1783353558928158500 Guests using the IMSIC interrupt controller require a corresponding Device Tree description. Add support for generating an IMSIC node when building the guest DT. This allows guests to discover and use the IMSIC interrupt controller. The value choosen for GUEST_IMSIC_S_BASE is an address which is typically used for IMSIC and QEMU. DT-building functions are marked __init because domain creation happens at boot time, before the init sections are freed. In a typical deployment libxl creates the interrupt controller node in userspace and hands the complete FDT to Xen, so these functions are only called during early domain construction. Co-developed-by: Romain Caritey Signed-off-by: Oleksii Kurochko --- Changes in v5: - s/GUEST_IMSIC_NUM_MSIS/GUEST_IMSIC_MAX_MSIS throughout. - Changed __read_mostly =E2=86=92 __ro_after_init on guest_num_msis, since= the value is set once during __init and never again. - Made imsic_parse_node() __init. - Moved the min(GUEST_IMSIC_MAX_MSIS, ...) cap into imsic_parse_node() rig= ht after guest_num_msis is assigned, so the bound is applied once at init time rather than on every DT node construction call. - Removed the now-unnecessary num_msis local variable from vimsic_make_domu_dt_node(); guest_num_msis is used directly. - s/snprintf(buf, sizeof(buf), ...)/snprintf(buf, ARRAY_SIZE(buf), ...) in guest_imsic_set_interrupt_extended_prop(). - Added decl. of vimsic_make_domu_dt_node() in this patch instead of next. --- Changes in v4: - Add a comment for guest_num_msis explaining that it is host-dependent and therefore identical for every domain, which is why a single global is used instead of a per-domain value. - Reduce vimsic_name[] from 128 to 32 bytes, which is enough to hold "/soc/imsic@" plus a 64-bit hex address. - Add a comment before GUEST_IMSIC_S_BASE noting that the value is the address typically used for IMSIC by QEMU. - s/__ULL/_UL for defintion of GUEST_IMSIC_S_BASE. --- Changes in v3: - s/__ro_after_init/__read_mostly for guest_num_msis. - Use IMSIC_MAX_ID as default for guest_num_msis instead of imsic_cfg.nr_i= ds. - Drop base_addr local variable in guest_imsic_make_reg_property(); use GUEST_IMSIC_S_BASE directly and introduce size to avoid spelling IMSIC_MMIO_PAGE_SZ * d->max_vcpus twice. - Change irq_ext type from uint32_t * to __be32 * in guest_imsic_set_interrupt_extended_prop(). - Move phandle declaration into the loop body. - Extend commit message to explain why __init is used for DT-building functions: libxl creates the interrupt controller node before handing the FDT to Xen, so these functions are only invoked during boot-time domain construction. - Re-order patch before APLIC DT node creation patch. - Update commit message. --- Changes in v2: - s/imsic_make_reg_property/guest_imsic_make_reg_property. - s/imsic_set_interrupt_extended_prop/guest_imsic_set_interrupt_extended_p= rop. - Use initalizer for regs[] array in imsic_make_reg_property(). - Move buf[] insde the for() loop. - Correct check of returned phandle. - Drop local variable len. - /s/XVFREE/xvfree in imsic_set_interrupt_extended_prop(). - Drop initializer for local variable data. - s/uint32_t/unsinged int for pos and cpu in imsic_set_interrupt_extended_= prop(). - Drop next_phandle as it is now in common code. - Introduce vcpu_imsic_deinit. - Refactor vimsic_make_domu_dt_node() to avoid usage of host IMSIC dt node. --- --- xen/arch/riscv/imsic.c | 144 +++++++++++++++++++++- xen/arch/riscv/include/asm/guest-layout.h | 6 + xen/arch/riscv/include/asm/imsic.h | 3 + 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c index 5a5758e45dc2..8966362fb149 100644 --- a/xen/arch/riscv/imsic.c +++ b/xen/arch/riscv/imsic.c @@ -13,8 +13,12 @@ #include #include #include +#include #include +#include +#include #include +#include #include #include #include @@ -34,6 +38,21 @@ static struct imsic_config imsic_cfg =3D { .lock =3D SPIN_LOCK_UNLOCKED, }; =20 +/* + * Number of MSIs available to a guest. Determined by the host interrupt + * controller, so it is identical for every domain -- hence a single global + * rather than a per-domain value. + */ +static unsigned int __ro_after_init guest_num_msis; + +#define GUEST_IMSIC_COMPATIBLE "riscv,imsics" + +/* + * Value is inspired by what QEMU is using for riscv,num-ids property for = IMSIC + * node. + */ +#define GUEST_IMSIC_MAX_MSIS 255 + #define IMSIC_DISABLE_EIDELIVERY 0 #define IMSIC_ENABLE_EIDELIVERY 1 #define IMSIC_DISABLE_EITHRESHOLD 1 @@ -182,7 +201,7 @@ static int __init imsic_get_parent_hartid(const struct = dt_device_node *node, * or IRQ_M_EXT if the IMSIC node corresponds to a machine-mode IMSIC, * which should be ignored by the hypervisor. */ -static int imsic_parse_node(const struct dt_device_node *node, +static int __init imsic_parse_node(const struct dt_device_node *node, unsigned int *nr_parent_irqs, unsigned int *nr_mmios) { @@ -285,6 +304,13 @@ static int imsic_parse_node(const struct dt_device_nod= e *node, return -ENOENT; } =20 + if ( dt_property_read_u32(node, "riscv,num-guest-ids", &tmp) ) + guest_num_msis =3D tmp; + else + guest_num_msis =3D IMSIC_MAX_ID; + + guest_num_msis =3D min(GUEST_IMSIC_MAX_MSIS + 0U, guest_num_msis); + if ( (imsic_cfg.nr_ids < IMSIC_MIN_ID) || (imsic_cfg.nr_ids > IMSIC_MAX_ID) ) { @@ -522,3 +548,119 @@ int __init imsic_init(const struct dt_device_node *no= de) =20 return rc; } + +static int __init guest_imsic_make_reg_property(struct domain *d, void *fd= t) +{ + paddr_t size =3D IMSIC_MMIO_PAGE_SZ * d->max_vcpus; + __be32 regs[4] =3D { + cpu_to_be32(GUEST_IMSIC_S_BASE >> 32), + cpu_to_be32(GUEST_IMSIC_S_BASE), + cpu_to_be32(size >> 32), + cpu_to_be32(size), + }; + + return fdt_property(fdt, "reg", regs, sizeof(regs)); +} + +static int __init guest_imsic_set_interrupt_extended_prop(struct domain *d, + void *fdt) +{ + unsigned int cpu, pos =3D 0; + __be32 *irq_ext; + int res; + + irq_ext =3D xvzalloc_array(__be32, d->max_vcpus * 2); + if ( !irq_ext ) + return -ENOMEM; + + for ( cpu =3D 0; cpu < d->max_vcpus; cpu++ ) + { + char buf[64]; + uint32_t phandle; + + snprintf(buf, ARRAY_SIZE(buf), "/cpus/cpu@%u/interrupt-controller"= , cpu); + phandle =3D fdt_get_phandle(fdt, fdt_path_offset(fdt, buf)); + + if ( !phandle ) + { + res =3D -ENODEV; + goto out; + } + + irq_ext[pos++] =3D cpu_to_be32(phandle); + irq_ext[pos++] =3D cpu_to_be32(IRQ_S_EXT); + } + + res =3D fdt_property(fdt, "interrupts-extended", irq_ext, + d->max_vcpus * 2 * sizeof(*irq_ext)); + + out: + xvfree(irq_ext); + + return res; +} + +int __init vimsic_make_domu_dt_node(struct kernel_info *kinfo, + unsigned int *phandle) +{ + int res; + void *fdt =3D kinfo->fdt; + char vimsic_name[32]; + unsigned int vimsic_phandle; + res =3D snprintf(vimsic_name, sizeof(vimsic_name), "/soc/imsic@%lx", + GUEST_IMSIC_S_BASE); + if ( res >=3D sizeof(vimsic_name) ) + { + dprintk(XENLOG_DEBUG, "vimsic name is truncated\n"); + return -ENOBUFS; + } + + res =3D fdt_begin_node(fdt, vimsic_name); + if ( res ) + return res; + + res =3D fdt_property_string(fdt, "compatible", GUEST_IMSIC_COMPATIBLE); + if ( res ) + return res; + + res =3D guest_imsic_make_reg_property(kinfo->bd.d, fdt); + if ( res ) + return res; + + res =3D guest_imsic_set_interrupt_extended_prop(kinfo->bd.d, fdt); + if ( res ) + return res; + + res =3D fdt_property_u32(fdt, "riscv,num-ids", guest_num_msis); + if ( res ) + return res; + + res =3D fdt_property(fdt, "msi-controller", NULL, 0); + if ( res ) + return res; + + res =3D fdt_property_u32(fdt, "#msi-cells", 0); + if ( res ) + return res; + + res =3D fdt_property(fdt, "interrupt-controller", NULL, 0); + if ( res ) + return res; + + res =3D fdt_property_u32(fdt, "#interrupt-cells", 0); + if ( res ) + return res; + + vimsic_phandle =3D alloc_phandle(kinfo); + if ( !vimsic_phandle ) + return -EOVERFLOW; + + res =3D fdt_property_cell(fdt, "phandle", vimsic_phandle); + if ( res ) + return res; + + if ( phandle ) + *phandle =3D vimsic_phandle; + + return fdt_end_node(fdt); +} diff --git a/xen/arch/riscv/include/asm/guest-layout.h b/xen/arch/riscv/inc= lude/asm/guest-layout.h index 68d95a09394c..5e566450bdfa 100644 --- a/xen/arch/riscv/include/asm/guest-layout.h +++ b/xen/arch/riscv/include/asm/guest-layout.h @@ -3,6 +3,12 @@ =20 #include =20 +/* + * Base address of the guest's supervisor-mode IMSIC. The value is the add= ress + * typically used for IMSIC by QEMU. + */ +#define GUEST_IMSIC_S_BASE _UL(0x28000000) + #define GUEST_RAM_BANKS 2 =20 /* diff --git a/xen/arch/riscv/include/asm/imsic.h b/xen/arch/riscv/include/as= m/imsic.h index e2c413487d24..e1ec3d03c4e9 100644 --- a/xen/arch/riscv/include/asm/imsic.h +++ b/xen/arch/riscv/include/asm/imsic.h @@ -78,6 +78,7 @@ struct vimsic_state { }; =20 struct dt_device_node; +struct kernel_info; struct vcpu; =20 int imsic_init(const struct dt_device_node *node); @@ -93,4 +94,6 @@ int vcpu_imsic_init(struct vcpu *v); void vcpu_imsic_deinit(struct vcpu *v); unsigned int vcpu_guest_file_id(const struct vcpu *v); =20 +int vimsic_make_domu_dt_node(struct kernel_info *kinfo, unsigned int *phan= dle); + #endif /* ASM_RISCV_IMSIC_H */ --=20 2.54.0