* [PATCH v3 00/23] Introduce enablemenant of dom0less
@ 2026-06-17 11:17 Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 01/23] xen: arm: move declaration of map_device_irqs_to_domain() to common header Oleksii Kurochko
` (22 more replies)
0 siblings, 23 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Stefano Stabellini,
Julien Grall, Bertrand Marquis, Michal Orzel, Volodymyr Babchuk,
Andrew Cooper, Anthony PERARD, Jan Beulich, Roger Pau Monné,
Alistair Francis, Connor Davis
This patch series reprensent a bunch of patches necessary to enable common part
of Dom0less.
The stuff necessary to start/launch domains will be introduced separately.
---
Changes in v3:
- Drop dependency from other patch series
([1] https://lore.kernel.org/xen-devel/cover.1778140240.git.oleksii.kurochko@gmail.com/T/#t)
as it was merged.
- Reorder patches:
- move common patches to the start.
- Move some patches to separate patch series (will be introduced later)
- Address comments from ML.
---
Changes in v2:
- Move patch "[PATCH v1 04/27] xen/riscv: rework G-stage mode handling" to
patch series [1]
- Address the comments from ML.
- The following patches were folded into one:
# xen/riscv: implement init_intc_phandle()
# xen/riscv: call do_initcalls() in start_xen()
# xen/riscv: setup system domains
- The following patch were folded into one:
# xen/riscv: add vaplic access check
# xen/riscv: emulate guest writes to virtual APLIC MMIO
# xen/riscv: emulate guest reads from virtual APLIC MMIO
- Add new bug fix, not really necessary to this patch series:
xen/riscv: manage IRQ_DISABLED flag in APLIC irq enable/disable callbacks
---
Oleksii Kurochko (23):
xen: arm: move declaration of map_device_irqs_to_domain() to common
header
xen: arm: update p2m_set_allocation() prototype
xen/riscv: Implement ARCH_PAGING_MEMPOOL
xen/riscv: Implement construct_domain()
xen/riscv: implement prerequisites for domain_create()
xen/riscv: introduce guest riscv,isa string
xen/riscv: implement make_cpus_node()
xen/riscv: implement make_timer_node()
xen/riscv: implement make_arch_nodes()
xen/riscv: introduce init interrupt controller operations
xen/riscv: implement make_intc_domU_node()
xen/riscv: introduce aia_init() and aia_usable()
xen/riscv: introduce per-vCPU IMSIC state
xen/riscv: add very early virtual APLIC (vAPLIC) initialization
support
xen/riscv: introduce (de)initialization helpers for vINTC
xen/riscv: generate IMSIC DT node for guest domains
xen/riscv: create APLIC DT node for guest domains
xen/riscv: implement IRQ routing for device passthrough
xen/riscv: implement init_intc_phandle()
xen/riscv: initialize RCU, scheduler, and system domains in
start_xen()
xen/riscv: provide init_vuart()
xen/Kconfig: introduce HAS_STATIC_MEMORY
xen/riscv: add initial dom0less infrastructure support
...asic-VGEIN-management-for-AIA-guests.patch | 273 ++++++++++++++++++
xen/arch/arm/Kconfig | 1 +
xen/arch/arm/include/asm/p2m.h | 1 -
xen/arch/arm/include/asm/setup.h | 3 -
xen/arch/arm/mmu/p2m.c | 22 +-
xen/arch/riscv/Kconfig | 3 +
xen/arch/riscv/Makefile | 4 +
xen/arch/riscv/aia.c | 23 ++
xen/arch/riscv/aplic.c | 14 +-
xen/arch/riscv/cpufeature.c | 85 +++++-
xen/arch/riscv/device.c | 102 +++++++
xen/arch/riscv/dom0less-build.c | 40 +++
xen/arch/riscv/domain-build.c | 177 ++++++++++++
xen/arch/riscv/domain.c | 46 ++-
xen/arch/riscv/imsic.c | 167 +++++++++++
xen/arch/riscv/include/asm/aia.h | 10 +
xen/arch/riscv/include/asm/aplic.h | 9 +
xen/arch/riscv/include/asm/cpufeature.h | 4 +
xen/arch/riscv/include/asm/domain.h | 8 +
xen/arch/riscv/include/asm/guest-layout.h | 7 +
xen/arch/riscv/include/asm/imsic.h | 25 ++
xen/arch/riscv/include/asm/intc.h | 46 ++-
xen/arch/riscv/include/asm/irq.h | 5 +
xen/arch/riscv/include/asm/paging.h | 2 +-
xen/arch/riscv/include/asm/setup.h | 4 +-
xen/arch/riscv/include/asm/vaplic.h | 34 +++
xen/arch/riscv/intc.c | 103 ++++++-
xen/arch/riscv/irq.c | 203 +++++++++++++
xen/arch/riscv/p2m.c | 31 +-
xen/arch/riscv/paging.c | 7 +-
xen/arch/riscv/setup.c | 14 +
xen/arch/riscv/stubs.c | 17 --
xen/arch/riscv/vaplic.c | 141 +++++++++
xen/common/Kconfig | 5 +-
xen/common/device-tree/dom0less-build.c | 2 +-
xen/include/xen/fdt-domain-build.h | 13 +
xen/include/xen/p2m-common.h | 2 +
37 files changed, 1587 insertions(+), 66 deletions(-)
create mode 100644 0001-xen-riscv-add-basic-VGEIN-management-for-AIA-guests.patch
create mode 100644 xen/arch/riscv/aia.c
create mode 100644 xen/arch/riscv/device.c
create mode 100644 xen/arch/riscv/domain-build.c
create mode 100644 xen/arch/riscv/include/asm/aia.h
create mode 100644 xen/arch/riscv/include/asm/vaplic.h
create mode 100644 xen/arch/riscv/vaplic.c
--
2.54.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v3 01/23] xen: arm: move declaration of map_device_irqs_to_domain() to common header
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 02/23] xen: arm: update p2m_set_allocation() prototype Oleksii Kurochko
` (21 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Stefano Stabellini,
Julien Grall, Bertrand Marquis, Michal Orzel, Volodymyr Babchuk,
Andrew Cooper, Anthony PERARD, Jan Beulich, Roger Pau Monné
As map_device_irqs_to_domain() is used unconditionally by common part of
dom0less code it is moved to common header.
fdt-domain-build.h is chosen as map_device_irqs_to_domain() could be
also called indirectly in Arm's DOM0-related code.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Add tag arm and move this patch earlier before RISC-V-related patches.
---
Changes in v2:
- New patch.
---
xen/arch/arm/include/asm/setup.h | 3 ---
xen/include/xen/fdt-domain-build.h | 13 +++++++++++++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
index 0d29b46ea52b..0adfa4993a8f 100644
--- a/xen/arch/arm/include/asm/setup.h
+++ b/xen/arch/arm/include/asm/setup.h
@@ -53,9 +53,6 @@ void init_traps(void);
int handle_device(struct domain *d, struct dt_device_node *dev, p2m_type_t p2mt,
struct rangeset *iomem_ranges, struct rangeset *irq_ranges);
-int map_device_irqs_to_domain(struct domain *d, struct dt_device_node *dev,
- bool need_mapping, struct rangeset *irq_ranges);
-
int map_irq_to_domain(struct domain *d, unsigned int irq,
bool need_mapping, const char *devname);
diff --git a/xen/include/xen/fdt-domain-build.h b/xen/include/xen/fdt-domain-build.h
index 671486c1c837..8612e98dfda5 100644
--- a/xen/include/xen/fdt-domain-build.h
+++ b/xen/include/xen/fdt-domain-build.h
@@ -12,6 +12,7 @@
struct domain;
struct page_info;
+struct rangeset;
struct membanks;
typedef bool (*alloc_domheap_mem_cb)(struct domain *d, struct page_info *pg,
@@ -79,6 +80,18 @@ static inline void set_domain_type(struct domain *d, const struct kernel_info *k
#endif
}
+/*
+ * Retrieves the interrupts configuration from a device tree node and maps
+ * those interrupts to the target domain.
+ *
+ * Returns:
+ * < 0 error
+ * 0 success
+ */
+int map_device_irqs_to_domain(struct domain *d, struct dt_device_node *dev,
+ bool need_mapping,
+ struct rangeset *irq_ranges);
+
#endif /* __XEN_FDT_DOMAIN_BUILD_H__ */
/*
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 02/23] xen: arm: update p2m_set_allocation() prototype
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 01/23] xen: arm: move declaration of map_device_irqs_to_domain() to common header Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 03/23] xen/riscv: Implement ARCH_PAGING_MEMPOOL Oleksii Kurochko
` (20 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Stefano Stabellini,
Julien Grall, Bertrand Marquis, Michal Orzel, Volodymyr Babchuk,
Andrew Cooper, Anthony PERARD, Jan Beulich, Roger Pau Monné,
Alistair Francis, Connor Davis
p2m_set_allocation() signals preemption redundantly: via a bool *preempted
out-argument (set to true) and via -ERESTART return code, both at the same
time. This led to the caller-side ASSERT(preempted == (rc == -ERESTART))
added solely to document their agreement.
Drop the out-argument entirely. The return code alone is sufficient to
distinguish preemption (-ERESTART) from success (0) or other failures.
Replace the pointer with a plain bool can_preempt that controls whether
the preemption check is performed at all, making the previous
NULL-to-suppress-preemption calling convention explicit and type-safe.
Since p2m_set_allocation() is called by the common dom0less build code,
move its declaration from the ARM-specific asm/p2m.h to xen/p2m-common.h.
Reported-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Nothing changed. Only rebase.
---
Changes in v2:
- new patch
---
---
xen/arch/arm/include/asm/p2m.h | 1 -
xen/arch/arm/mmu/p2m.c | 22 ++++++++--------------
xen/arch/riscv/include/asm/paging.h | 2 +-
xen/arch/riscv/p2m.c | 7 ++++---
xen/arch/riscv/paging.c | 7 ++-----
xen/common/device-tree/dom0less-build.c | 2 +-
xen/include/xen/p2m-common.h | 2 ++
7 files changed, 18 insertions(+), 25 deletions(-)
diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h
index 4a4913716bdd..737da60dcf58 100644
--- a/xen/arch/arm/include/asm/p2m.h
+++ b/xen/arch/arm/include/asm/p2m.h
@@ -238,7 +238,6 @@ void p2m_restore_state(struct vcpu *n);
/* Print debugging/statistial info about a domain's p2m */
void p2m_dump_info(struct domain *d);
-int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted);
int p2m_teardown_allocation(struct domain *d);
static inline void p2m_write_lock(struct p2m_domain *p2m)
diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c
index 51abf3504fcf..e5c6be7c0890 100644
--- a/xen/arch/arm/mmu/p2m.c
+++ b/xen/arch/arm/mmu/p2m.c
@@ -67,10 +67,11 @@ int arch_get_paging_mempool_size(struct domain *d, uint64_t *size)
/*
* Set the pool of pages to the required number of pages.
- * Returns 0 for success, non-zero for failure.
+ * Returns 0 for success, -ERESTART if preempted, or a negative error code on
+ * failure.
* Call with d->arch.paging.lock held.
*/
-int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted)
+int p2m_set_allocation(struct domain *d, unsigned long pages, bool can_preempt)
{
struct page_info *pg;
@@ -112,11 +113,8 @@ int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted)
break;
/* Check to see if we need to yield and try again */
- if ( preempted && general_preempt_check() )
- {
- *preempted = true;
+ if ( can_preempt && general_preempt_check() )
return -ERESTART;
- }
}
return 0;
@@ -125,7 +123,6 @@ int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted)
int arch_set_paging_mempool_size(struct domain *d, uint64_t size)
{
unsigned long pages = size >> PAGE_SHIFT;
- bool preempted = false;
int rc;
if ( (size & ~PAGE_MASK) || /* Non page-sized request? */
@@ -133,27 +130,24 @@ int arch_set_paging_mempool_size(struct domain *d, uint64_t size)
return -EINVAL;
spin_lock(&d->arch.paging.lock);
- rc = p2m_set_allocation(d, pages, &preempted);
+ rc = p2m_set_allocation(d, pages, true);
spin_unlock(&d->arch.paging.lock);
- ASSERT(preempted == (rc == -ERESTART));
-
return rc;
}
int p2m_teardown_allocation(struct domain *d)
{
int ret = 0;
- bool preempted = false;
spin_lock(&d->arch.paging.lock);
if ( d->arch.paging.p2m_total_pages != 0 )
{
- ret = p2m_set_allocation(d, 0, &preempted);
- if ( preempted )
+ ret = p2m_set_allocation(d, 0, true);
+ if ( ret == -ERESTART )
{
spin_unlock(&d->arch.paging.lock);
- return -ERESTART;
+ return ret;
}
ASSERT(d->arch.paging.p2m_total_pages == 0);
}
diff --git a/xen/arch/riscv/include/asm/paging.h b/xen/arch/riscv/include/asm/paging.h
index e487c89a4ccd..103384723dc5 100644
--- a/xen/arch/riscv/include/asm/paging.h
+++ b/xen/arch/riscv/include/asm/paging.h
@@ -9,7 +9,7 @@ struct page_info;
int paging_domain_init(struct domain *d);
int paging_freelist_adjust(struct domain *d, unsigned long pages,
- bool *preempted);
+ bool can_preempt);
int paging_ret_to_domheap(struct domain *d, unsigned int nr_pages);
int paging_refill_from_domheap(struct domain *d, unsigned int nr_pages);
diff --git a/xen/arch/riscv/p2m.c b/xen/arch/riscv/p2m.c
index 703b9f4d2540..41d6d3d5e699 100644
--- a/xen/arch/riscv/p2m.c
+++ b/xen/arch/riscv/p2m.c
@@ -430,15 +430,16 @@ int p2m_init(struct domain *d, const struct xen_domctl_createdomain *config)
/*
* Set the pool of pages to the required number of pages.
- * Returns 0 for success, non-zero for failure.
+ * Returns 0 for success, -ERESTART if preempted, or a negative error code on
+ * failure.
* Call with d->arch.paging.lock held.
*/
-int p2m_set_allocation(struct domain *d, unsigned long pages, bool *preempted)
+int p2m_set_allocation(struct domain *d, unsigned long pages, bool can_preempt)
{
struct p2m_domain *p2m = p2m_get_hostp2m(d);
int rc;
- if ( (rc = paging_freelist_adjust(d, pages, preempted)) )
+ if ( (rc = paging_freelist_adjust(d, pages, can_preempt)) )
return rc;
/*
diff --git a/xen/arch/riscv/paging.c b/xen/arch/riscv/paging.c
index 76a203edbb0c..35f572689a7c 100644
--- a/xen/arch/riscv/paging.c
+++ b/xen/arch/riscv/paging.c
@@ -47,7 +47,7 @@ static int _paging_add_to_freelist(struct domain *d)
}
int paging_freelist_adjust(struct domain *d, unsigned long pages,
- bool *preempted)
+ bool can_preempt)
{
ASSERT(spin_is_locked(&d->arch.paging.lock));
@@ -66,11 +66,8 @@ int paging_freelist_adjust(struct domain *d, unsigned long pages,
return rc;
/* Check to see if we need to yield and try again */
- if ( preempted && general_preempt_check() )
- {
- *preempted = true;
+ if ( can_preempt && general_preempt_check() )
return -ERESTART;
- }
}
return 0;
diff --git a/xen/common/device-tree/dom0less-build.c b/xen/common/device-tree/dom0less-build.c
index eacfd93087ae..c3818ffed45f 100644
--- a/xen/common/device-tree/dom0less-build.c
+++ b/xen/common/device-tree/dom0less-build.c
@@ -747,7 +747,7 @@ static int __init domain_p2m_set_allocation(struct domain *d, uint64_t mem,
domain_p2m_pages(mem, d->max_vcpus);
spin_lock(&d->arch.paging.lock);
- rc = p2m_set_allocation(d, p2m_pages, NULL);
+ rc = p2m_set_allocation(d, p2m_pages, false);
spin_unlock(&d->arch.paging.lock);
return rc;
diff --git a/xen/include/xen/p2m-common.h b/xen/include/xen/p2m-common.h
index f0bd9a6b9896..1b44ec8ce36c 100644
--- a/xen/include/xen/p2m-common.h
+++ b/xen/include/xen/p2m-common.h
@@ -43,5 +43,7 @@ int __must_check check_get_page_from_gfn(struct domain *d, gfn_t gfn,
bool readonly, p2m_type_t *p2mt_p,
struct page_info **page_p);
+int p2m_set_allocation(struct domain *d, unsigned long pages,
+ bool can_preempt);
#endif /* _XEN_P2M_COMMON_H */
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 03/23] xen/riscv: Implement ARCH_PAGING_MEMPOOL
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 01/23] xen: arm: move declaration of map_device_irqs_to_domain() to common header Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 02/23] xen: arm: update p2m_set_allocation() prototype Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 04/23] xen/riscv: Implement construct_domain() Oleksii Kurochko
` (19 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
The p2m_freelist is used to allocate pages for the P2M. To initialize
this list, domain_p2m_set_allocation() may be called from construct_domU()
in the common Dom0less code, so RISC-V provides an implementation and
enables CONFIG_ARCH_PAGING_MEMPOOL unconditionally.
Additionally, implement arch_{set,get}_paging_mempool_size(). They are
not directly used yet, but are required to support the
XEN_DOMCTL_{get,set}_paging_mempool_size hypercalls.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
Changes in v3:
- Drop stray blank space in arch_get_paging_mempool_size().
- Add Acked-by: Jan Beulich <jbeulich@suse.com>.
---
Changes in v2:
- Turn on CONFIG_ARCH_PAGING_MEMPOOL=y unconditionally and drop all ifdef-s
related to this config.
- Optimize check inside arch_set_paging_mempool_size which verify size
argument.
- Use pfn_to_paddr() inside arch_get_paging_mempool_size() instead of open
coding the stuff.
- Drop ASSERT() from arch_set_paging_mempool_size() as it is impossible to
have here preempted = true and rc != -ERESTART.
---
---
xen/arch/riscv/Kconfig | 1 +
xen/arch/riscv/p2m.c | 24 ++++++++++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/xen/arch/riscv/Kconfig b/xen/arch/riscv/Kconfig
index 41426c205292..48520588fe40 100644
--- a/xen/arch/riscv/Kconfig
+++ b/xen/arch/riscv/Kconfig
@@ -1,5 +1,6 @@
config RISCV
def_bool y
+ select ARCH_PAGING_MEMPOOL
select DOMAIN_BUILD_HELPERS
select FUNCTION_ALIGNMENT_16B
select GENERIC_BUG_FRAME
diff --git a/xen/arch/riscv/p2m.c b/xen/arch/riscv/p2m.c
index 41d6d3d5e699..9bf80d38979f 100644
--- a/xen/arch/riscv/p2m.c
+++ b/xen/arch/riscv/p2m.c
@@ -1606,3 +1606,27 @@ struct page_info *get_page_from_gfn(struct domain *d, unsigned long gfn,
return p2m_get_page_from_gfn(p2m_get_hostp2m(d), _gfn(gfn), t);
}
+
+int arch_set_paging_mempool_size(struct domain *d, uint64_t size)
+{
+ unsigned long pages = PFN_DOWN(size);
+ int rc;
+
+ /* Non page-sized request or 32-bit overflow? */
+ if ( pfn_to_paddr(pages) != size )
+ return -EINVAL;
+
+ spin_lock(&d->arch.paging.lock);
+ rc = p2m_set_allocation(d, pages, true);
+ spin_unlock(&d->arch.paging.lock);
+
+ return rc;
+}
+
+/* Return the size of the pool, in bytes. */
+int arch_get_paging_mempool_size(struct domain *d, uint64_t *size)
+{
+ *size = pfn_to_paddr(ACCESS_ONCE(d->arch.paging.total_pages));
+
+ return 0;
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 04/23] xen/riscv: Implement construct_domain()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (2 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 03/23] xen/riscv: Implement ARCH_PAGING_MEMPOOL Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:26 ` Jan Beulich
2026-06-17 11:17 ` [PATCH v3 05/23] xen/riscv: implement prerequisites for domain_create() Oleksii Kurochko
` (18 subsequent siblings)
22 siblings, 1 reply; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Implement construct_domain() function for RISC-V, which performs initial setup
for the domain's first vCPU, loads the kernel, initrd, and device tree,
and sets up guest CPU registers for boot.
It also creates additional vCPUs up to max_vcpus and assigns the device tree
address and boot cpuid in registers.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- s/%d/%u for printing vCPU index in the failure message.
- Drop dprintk() for successful vCPU creation.
---
Changes in v2:
- Rework construct_domain() to print that vCPU1...n are created using %pv.
- Use true instead of 1 for initialization of v->is_initialised.
- Drop unnessary BUG_ON() in construct_domain().
- Add TODO comment above *_load() functions.
---
---
xen/arch/riscv/Makefile | 1 +
xen/arch/riscv/domain-build.c | 50 +++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
create mode 100644 xen/arch/riscv/domain-build.c
diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
index 8f7fd625dddd..fd5e499eb4b9 100644
--- a/xen/arch/riscv/Makefile
+++ b/xen/arch/riscv/Makefile
@@ -1,6 +1,7 @@
obj-y += aplic.o
obj-y += cpufeature.o
obj-y += domain.o
+obj-y += domain-build.init.o
obj-$(CONFIG_DOM0LESS_BOOT) += dom0less-build.init.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-y += entry.o
diff --git a/xen/arch/riscv/domain-build.c b/xen/arch/riscv/domain-build.c
new file mode 100644
index 000000000000..72cccb2c5c22
--- /dev/null
+++ b/xen/arch/riscv/domain-build.c
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <xen/fdt-domain-build.h>
+#include <xen/fdt-kernel.h>
+#include <xen/init.h>
+#include <xen/sched.h>
+
+#include <asm/current.h>
+#include <asm/guest_access.h>
+
+int __init construct_domain(struct domain *d, struct kernel_info *kinfo)
+{
+ struct vcpu *v = d->vcpu[0];
+ struct cpu_user_regs *regs = vcpu_guest_cpu_user_regs(v);
+
+ BUG_ON(v->is_initialised);
+
+ /*
+ * At the moment *_load() don't return value and will just panic()
+ * inside.
+ * TODO: it will be good to change that.
+ */
+ kernel_load(kinfo);
+ initrd_load(kinfo, copy_to_guest_phys);
+ dtb_load(kinfo, copy_to_guest_phys);
+
+ regs->sepc = kinfo->entry;
+
+ /* Guest boot cpuid = 0 */
+ regs->a0 = 0;
+ regs->a1 = kinfo->dtb_paddr;
+
+ for ( unsigned int i = 1; i < d->max_vcpus; i++ )
+ {
+ const struct vcpu *tmp_v = vcpu_create(d, i);
+
+ if ( !tmp_v )
+ {
+ printk("Failed to allocate %pd v%u\n", d, i);
+ break;
+ }
+ }
+
+ domain_update_node_affinity(d);
+
+ v->is_initialised = true;
+ clear_bit(_VPF_down, &v->pause_flags);
+
+ return 0;
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 05/23] xen/riscv: implement prerequisites for domain_create()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (3 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 04/23] xen/riscv: Implement construct_domain() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 06/23] xen/riscv: introduce guest riscv,isa string Oleksii Kurochko
` (17 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
arch_domain_create() and arch_sanitise_domain_config() are prerequisites for
domain_create().
arch_sanitise_domain_config() currently returns 0, as there is no specific
work required at this stage.
arch_domain_create() performs basic initialization, such as setting up the P2M
and initializing of next unused phandle.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Move arch_domain_destroy() from stubs.c to domain.c next to arch_domain_create().
- Drop d->is_dying = DOMDYING_dead from arch_domain_create()'s fail label as domain_create() already does it.
- Replace BUG_ON("unimplemented") with printk() in arch_domain_destroy().
---
Changes in v2:
- update the commit message.
- Drop vcpu_switch_to_aarch64_mode() from riscv/stubs. It shouldn't be under
riscv/ at all.
- Drop next_phandle as it is now in common code.
---
---
xen/arch/riscv/domain.c | 29 +++++++++++++++++++++++++++++
xen/arch/riscv/stubs.c | 17 -----------------
2 files changed, 29 insertions(+), 17 deletions(-)
diff --git a/xen/arch/riscv/domain.c b/xen/arch/riscv/domain.c
index c77be3b827eb..2819ff4e7c92 100644
--- a/xen/arch/riscv/domain.c
+++ b/xen/arch/riscv/domain.c
@@ -289,6 +289,35 @@ void sync_vcpu_execstate(struct vcpu *v)
/* Nothing to do -- no lazy switching */
}
+int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
+{
+ return 0;
+}
+
+void arch_domain_destroy(struct domain *d)
+{
+ printk(XENLOG_WARNING "%s: unimplemented\n", __func__);
+}
+
+int arch_domain_create(struct domain *d,
+ struct xen_domctl_createdomain *config,
+ unsigned int flags)
+{
+ int rc = 0;
+
+ if ( is_idle_domain(d) )
+ return 0;
+
+ if ( (rc = p2m_init(d, config)) != 0)
+ goto fail;
+
+ return rc;
+
+ fail:
+ arch_domain_destroy(d);
+ return rc;
+}
+
static void __init __maybe_unused build_assertions(void)
{
/*
diff --git a/xen/arch/riscv/stubs.c b/xen/arch/riscv/stubs.c
index acbb5b9123ea..3a7953593d93 100644
--- a/xen/arch/riscv/stubs.c
+++ b/xen/arch/riscv/stubs.c
@@ -101,28 +101,11 @@ void dump_pageframe_info(struct domain *d)
BUG_ON("unimplemented");
}
-int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
-{
- BUG_ON("unimplemented");
-}
-
-int arch_domain_create(struct domain *d,
- struct xen_domctl_createdomain *config,
- unsigned int flags)
-{
- BUG_ON("unimplemented");
-}
-
int arch_domain_teardown(struct domain *d)
{
BUG_ON("unimplemented");
}
-void arch_domain_destroy(struct domain *d)
-{
- BUG_ON("unimplemented");
-}
-
void arch_domain_shutdown(struct domain *d)
{
BUG_ON("unimplemented");
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 06/23] xen/riscv: introduce guest riscv,isa string
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (4 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 05/23] xen/riscv: implement prerequisites for domain_create() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 07/23] xen/riscv: implement make_cpus_node() Oleksii Kurochko
` (16 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Introduce generation of the riscv,isa string passed to the guest via the
Device Tree riscv,isa property.
Introduce the per-domain isa string and guest isa bitmap, populated
during domain creation by calling init_guest_isa().
Introduce guest_unsupp to filter out ISA extensions that should not be
exposed to guests:
- f/d/q/v: FPU and vector context save/restore are not yet implemented
for guests.
- h: Nested virtualisation is not supported.
- sstc: Xen owns the supervisor timer; guests must use SBI.
- svade: Xen manages hardware A/D bit updates in stage-2 page tables.
- svpbmt: Page-based memory types are not yet wired up in stage-2 code.
Drop __initconst for riscv_isa_ext() as it can be used after init stage
by init_guest_isa().
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- s/set_bit/__set_bit in init_guest_unsupp() as atomicity isn't needed at
init time.
- Drop RISCV_GUEST_ISA_STR_MAX; allocate isa_str dynamically with
xvmalloc_array().
- Drop "guest" prefix from d->arch.guest_isa and d->arch.guest_isa_str.
- Introduce build_guest_isa_str() using snprintf(NULL, 0, ...) to determine
the needed buffer size; init_guest_isa() calls it once for sizing and once
to fill, keeping both in a single function so they can't go out of sync.
- Scope ret inside the loop; initialize total directly from the prefix
snprintf().
- Merge "_" separator and extension name into a single snprintf() with
"%s%s".
- Replace ASSERT with an explicit error check: if the fill call returns a
different length, free isa_str and return -EINVAL.
---
Changes in v2:
- s/guest_unsupp_bmp/guest_unsupp.
- Drop guest_isa_str.
- Provide init_guest_isa() instead of polluting match_isa_ext().
- Drop xlen.
- Add the comment about guest_unsupp.
- Update the way how guest_unsupp is init-ed.
- Drop __initconst for riscv_isa_ext[] as it is used in init_guest_isa()
which isn't marked as __init as it could be used after init stage.
---
---
xen/arch/riscv/cpufeature.c | 85 ++++++++++++++++++++++++-
xen/arch/riscv/domain.c | 3 +
xen/arch/riscv/include/asm/cpufeature.h | 4 ++
xen/arch/riscv/include/asm/domain.h | 4 ++
4 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/xen/arch/riscv/cpufeature.c b/xen/arch/riscv/cpufeature.c
index 92235fdfd5ab..a56c28b6c99f 100644
--- a/xen/arch/riscv/cpufeature.c
+++ b/xen/arch/riscv/cpufeature.c
@@ -14,7 +14,9 @@
#include <xen/errno.h>
#include <xen/init.h>
#include <xen/lib.h>
+#include <xen/sched.h>
#include <xen/sections.h>
+#include <xen/xvmalloc.h>
#include <asm/cpufeature.h>
#include <asm/csr.h>
@@ -120,7 +122,7 @@ static int __init dt_get_cpuid_from_node(const struct dt_device_node *cpu,
* and strncmp() is used in match_isa_ext() to compare extension names instead
* of strncasecmp().
*/
-const struct riscv_isa_ext_data __initconst riscv_isa_ext[] = {
+const struct riscv_isa_ext_data riscv_isa_ext[] = {
RISCV_ISA_EXT_DATA(i),
RISCV_ISA_EXT_DATA(m),
RISCV_ISA_EXT_DATA(a),
@@ -128,6 +130,7 @@ const struct riscv_isa_ext_data __initconst riscv_isa_ext[] = {
RISCV_ISA_EXT_DATA(d),
RISCV_ISA_EXT_DATA(q),
RISCV_ISA_EXT_DATA(c),
+ RISCV_ISA_EXT_DATA(v),
RISCV_ISA_EXT_DATA(h),
RISCV_ISA_EXT_DATA(zicntr),
RISCV_ISA_EXT_DATA(zicsr),
@@ -160,6 +163,12 @@ static const struct riscv_isa_ext_data __initconst required_extensions[] = {
RISCV_ISA_EXT_DATA(svpbmt),
};
+/*
+ * Everything in riscv_isa_ext[] which shouldn't be exposed to guests should
+ * appear here.
+ */
+static __ro_after_init DECLARE_BITMAP(guest_unsupp, RISCV_ISA_EXT_MAX);
+
static bool __init is_lowercase_extension_name(const char *str)
{
/*
@@ -480,6 +489,78 @@ bool riscv_isa_extension_available(const unsigned long *isa_bitmap,
return test_bit(id, isa_bitmap);
}
+static int build_guest_isa_str(char *buf, size_t size,
+ const unsigned long *isa_bitmap)
+{
+ int total;
+
+#if defined(CONFIG_RISCV_32)
+ total = snprintf(buf, size, "rv32");
+#elif defined(CONFIG_RISCV_64)
+ total = snprintf(buf, size, "rv64");
+#else
+# error "Unsupported RISC-V bitness"
+#endif
+
+ if ( total < 0 )
+ return total;
+
+ for ( unsigned int i = 0; i < ARRAY_SIZE(riscv_isa_ext); i++ )
+ {
+ const struct riscv_isa_ext_data *ext = &riscv_isa_ext[i];
+ int ret;
+
+ if ( !riscv_isa_extension_available(isa_bitmap, ext->id) )
+ continue;
+
+ ret = snprintf(buf ? buf + total : NULL,
+ buf ? size - total : 0, "%s%s",
+ ext->id >= RISCV_ISA_EXT_BASE ? "_" : "",
+ ext->name);
+ if ( ret < 0 )
+ return ret;
+ total += ret;
+ }
+
+ return total;
+}
+
+int init_guest_isa(struct domain *d)
+{
+ int len;
+
+ bitmap_andnot(d->arch.isa, riscv_isa, guest_unsupp,
+ RISCV_ISA_EXT_MAX);
+
+ len = build_guest_isa_str(NULL, 0, d->arch.isa);
+ if ( len < 0 )
+ return len;
+
+ d->arch.isa_str = xvmalloc_array(char, len + 1);
+ if ( !d->arch.isa_str )
+ return -ENOMEM;
+
+ if ( build_guest_isa_str(d->arch.isa_str, len + 1, d->arch.isa) != len )
+ {
+ XVFREE(d->arch.isa_str);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void __init init_guest_unsupp(void)
+{
+ __set_bit(RISCV_ISA_EXT_f, guest_unsupp);
+ __set_bit(RISCV_ISA_EXT_d, guest_unsupp);
+ __set_bit(RISCV_ISA_EXT_q, guest_unsupp);
+ __set_bit(RISCV_ISA_EXT_v, guest_unsupp);
+ __set_bit(RISCV_ISA_EXT_h, guest_unsupp);
+ __set_bit(RISCV_ISA_EXT_sstc, guest_unsupp);
+ __set_bit(RISCV_ISA_EXT_svade, guest_unsupp);
+ __set_bit(RISCV_ISA_EXT_svpbmt, guest_unsupp);
+}
+
void __init riscv_fill_hwcap(void)
{
unsigned int i;
@@ -527,4 +608,6 @@ void __init riscv_fill_hwcap(void)
if ( !all_extns_available )
panic("Look why the extensions above are needed in "
"https://xenbits.xenproject.org/docs/unstable/misc/riscv/booting.txt\n");
+
+ init_guest_unsupp();
}
diff --git a/xen/arch/riscv/domain.c b/xen/arch/riscv/domain.c
index 2819ff4e7c92..e4a8c27ea9cb 100644
--- a/xen/arch/riscv/domain.c
+++ b/xen/arch/riscv/domain.c
@@ -308,6 +308,9 @@ int arch_domain_create(struct domain *d,
if ( is_idle_domain(d) )
return 0;
+ if ( (rc = init_guest_isa(d)) != 0 )
+ goto fail;
+
if ( (rc = p2m_init(d, config)) != 0)
goto fail;
diff --git a/xen/arch/riscv/include/asm/cpufeature.h b/xen/arch/riscv/include/asm/cpufeature.h
index 0c48d57a03bb..866e0f6e7bb7 100644
--- a/xen/arch/riscv/include/asm/cpufeature.h
+++ b/xen/arch/riscv/include/asm/cpufeature.h
@@ -17,6 +17,7 @@
*/
#define RISCV_ISA_EXT_BASE 26
+
enum riscv_isa_ext_id {
RISCV_ISA_EXT_a,
RISCV_ISA_EXT_c,
@@ -44,7 +45,10 @@ enum riscv_isa_ext_id {
RISCV_ISA_EXT_MAX
};
+struct domain;
+
void riscv_fill_hwcap(void);
+int init_guest_isa(struct domain *d);
bool riscv_isa_extension_available(const unsigned long *isa_bitmap,
enum riscv_isa_ext_id id);
diff --git a/xen/arch/riscv/include/asm/domain.h b/xen/arch/riscv/include/asm/domain.h
index 6044ce0feee0..459896c04b41 100644
--- a/xen/arch/riscv/include/asm/domain.h
+++ b/xen/arch/riscv/include/asm/domain.h
@@ -7,6 +7,7 @@
#include <xen/xmalloc.h>
#include <public/hvm/params.h>
+#include <asm/cpufeature.h>
#include <asm/guest-layout.h>
#include <asm/p2m.h>
#include <asm/vtimer.h>
@@ -94,6 +95,9 @@ struct arch_domain {
struct p2m_domain p2m;
struct paging_domain paging;
+
+ DECLARE_BITMAP(isa, RISCV_ISA_EXT_MAX);
+ char *isa_str;
};
#include <xen/sched.h>
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 07/23] xen/riscv: implement make_cpus_node()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (5 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 06/23] xen/riscv: introduce guest riscv,isa string Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 08/23] xen/riscv: implement make_timer_node() Oleksii Kurochko
` (15 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Implement make_cpus_node() to create cpus node for a guest domain.
This function is going to be use by common dom0less code during
construction domain.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Add blank line above make_cpus_node() function definition.
- Move 'unsigned int cpu' from function-level declarations into the for loop.
- Drop 'uint32_t reg = cpu_to_fdt32(cpu)'; use fdt_property_cell(fdt, "reg", cpu)
instead of fdt_property(fdt, "reg", ®, sizeof(reg)) so byte-order adjustment
is handled internally.
- Add matching /* interrupt-controller */ start comment; fix end comment to
/* end interrupt-controller */.
- Update d->arch.guest_isa_str to ->isa_str in make_cpus_node() function.
---
Changes in v2:
- s/u32/uint32_t for timebase_frequency local variable.
- Drop +1 from BUILD_BUG_ON().
- return fdt_end_node(fdt); instead of res at the end of the function.
---
---
xen/arch/riscv/domain-build.c | 106 ++++++++++++++++++++++++++++++++++
1 file changed, 106 insertions(+)
diff --git a/xen/arch/riscv/domain-build.c b/xen/arch/riscv/domain-build.c
index 72cccb2c5c22..c1cbc4386312 100644
--- a/xen/arch/riscv/domain-build.c
+++ b/xen/arch/riscv/domain-build.c
@@ -3,8 +3,10 @@
#include <xen/fdt-domain-build.h>
#include <xen/fdt-kernel.h>
#include <xen/init.h>
+#include <xen/libfdt/libfdt.h>
#include <xen/sched.h>
+#include <asm/cpufeature.h>
#include <asm/current.h>
#include <asm/guest_access.h>
@@ -48,3 +50,107 @@ int __init construct_domain(struct domain *d, struct kernel_info *kinfo)
return 0;
}
+
+int __init make_cpus_node(const struct domain *d, struct kernel_info *kinfo)
+{
+ int res;
+ const struct dt_device_node *cpus = dt_find_node_by_path("/cpus");
+ uint32_t timebase_frequency;
+ bool frequency_valid;
+ void *fdt = kinfo->fdt;
+
+ dt_dprintk("Create cpus node\n");
+
+ if ( !cpus )
+ {
+ dprintk(XENLOG_ERR, "Missing /cpus node in the device tree?\n");
+ return -ENOENT;
+ }
+
+ frequency_valid = dt_property_read_u32(cpus, "timebase-frequency",
+ &timebase_frequency);
+
+ res = fdt_begin_node(fdt, "cpus");
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "#address-cells", 1);
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "#size-cells", 0);
+ if ( res )
+ return res;
+
+ if ( frequency_valid )
+ res = fdt_property_cell(fdt, "timebase-frequency", timebase_frequency);
+
+ for ( unsigned int cpu = 0; cpu < d->max_vcpus; cpu++ )
+ {
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), "cpu@%u", cpu);
+ res = fdt_begin_node(fdt, buf);
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "reg", cpu);
+ if ( res )
+ return res;
+
+ res = fdt_property_string(fdt, "status", "okay");
+ if ( res )
+ return res;
+
+ res = fdt_property_string(fdt, "compatible", "riscv");
+ if ( res )
+ return res;
+
+ BUILD_BUG_ON((sizeof("riscv,") +
+ sizeof_field(struct gstage_mode_desc, name)) >= sizeof(buf));
+ snprintf(buf, sizeof(buf), "riscv,%s", max_gstage_mode->name);
+ res = fdt_property_string(fdt, "mmu-type", buf);
+ if ( res )
+ return res;
+
+ res = fdt_property_string(fdt, "riscv,isa", d->arch.isa_str);
+ if ( res )
+ return res;
+
+ res = fdt_property_string(fdt, "device_type", "cpu");
+ if ( res )
+ return res;
+
+ /* interrupt-controller */
+ res = fdt_begin_node(fdt, "interrupt-controller");
+ if ( res )
+ return res;
+
+ res = fdt_property_string(fdt, "compatible", "riscv,cpu-intc");
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "#interrupt-cells", 1);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "interrupt-controller", NULL, 0);
+ if ( res )
+ return res;
+
+ res = fdt_property_u32(fdt, "phandle", alloc_phandle(kinfo));
+ if ( res )
+ return res;
+
+ /* end interrupt-controller */
+ res = fdt_end_node(fdt);
+ if ( res )
+ return res;
+
+ res = fdt_end_node(fdt);
+ if ( res )
+ return res;
+ }
+
+ return fdt_end_node(fdt);
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 08/23] xen/riscv: implement make_timer_node()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (6 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 07/23] xen/riscv: implement make_cpus_node() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 09/23] xen/riscv: implement make_arch_nodes() Oleksii Kurochko
` (14 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Generally, in DT for RISC-V there is a document which describes a timer
node (riscv,timer.yaml or sifive,clint.yaml), but the Linux timer driver
is declared with TIMER_OF_DECLARE(riscv_timer, "riscv", ...).
It matches the CPU node (compatible "riscv"), not the timer node itself.
It then calls of_find_compatible_node(NULL, NULL, "riscv,timer") only to
read the optional riscv,timer-cannot-wake-cpu property.
Since Xen does not care about that property for now, make_timer_node() is
implemented to return 0, as no timer node needs to be created for RISC-V
guests.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
Changes in v3:
- Nothing changed. Only rebase.
---
Changes in v2:
- Acked-by: Jan Beulich <jbeulich@suse.com>
- Update the commit message.
---
---
xen/arch/riscv/domain-build.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/xen/arch/riscv/domain-build.c b/xen/arch/riscv/domain-build.c
index c1cbc4386312..4c21ef37a6e1 100644
--- a/xen/arch/riscv/domain-build.c
+++ b/xen/arch/riscv/domain-build.c
@@ -3,6 +3,7 @@
#include <xen/fdt-domain-build.h>
#include <xen/fdt-kernel.h>
#include <xen/init.h>
+#include <xen/fdt-kernel.h>
#include <xen/libfdt/libfdt.h>
#include <xen/sched.h>
@@ -154,3 +155,10 @@ int __init make_cpus_node(const struct domain *d, struct kernel_info *kinfo)
return fdt_end_node(fdt);
}
+
+int __init make_timer_node(const struct kernel_info *kinfo)
+{
+ /* There is no need for timer node for RISC-V. */
+
+ return 0;
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 09/23] xen/riscv: implement make_arch_nodes()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (7 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 08/23] xen/riscv: implement make_timer_node() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:30 ` Jan Beulich
2026-06-17 11:17 ` [PATCH v3 10/23] xen/riscv: introduce init interrupt controller operations Oleksii Kurochko
` (13 subsequent siblings)
22 siblings, 1 reply; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
No RISC-V-specific nodes need to be created at the moment,
so make_arch_nodes() is implemented to simply return 0.
It is placed in dom0less-build.c as make_arch_nodes() is
only used in the dom0less code path. In the future, it will
be extended to create an emulated UART node.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Add Acked-by: Jan Beulich <jbeulich@suse.com>.
---
Changes in v2:
- Update the commit message.
---
---
xen/arch/riscv/dom0less-build.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/xen/arch/riscv/dom0less-build.c b/xen/arch/riscv/dom0less-build.c
index a683972e9235..4cc00012aa8d 100644
--- a/xen/arch/riscv/dom0less-build.c
+++ b/xen/arch/riscv/dom0less-build.c
@@ -2,10 +2,18 @@
#include <xen/bootfdt.h>
#include <xen/device_tree.h>
+#include <xen/fdt-kernel.h>
#include <xen/init.h>
#include <asm/p2m.h>
+int __init make_arch_nodes(struct kernel_info *kinfo)
+{
+ /* No RISC-V specific nodes need to be made, at the moment. */
+
+ return 0;
+}
+
int __init arch_parse_dom0less_node(struct dt_device_node *node,
struct boot_domain *bd)
{
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 10/23] xen/riscv: introduce init interrupt controller operations
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (8 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 09/23] xen/riscv: implement make_arch_nodes() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 11/23] xen/riscv: implement make_intc_domU_node() Oleksii Kurochko
` (12 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Introduce intc_hw_init_ops structure to avoid risky mix of init
function and non-init function.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Use __initconst instead of __initdata for const intc_hw_init_ops.
- Embed const struct intc_hw_operations *ops into intc_hw_init_ops so
register_intc_ops() takes a single pointer argument.
---
Changes in v2:
- New patch.
---
---
xen/arch/riscv/aplic.c | 8 ++++++--
xen/arch/riscv/include/asm/intc.h | 10 +++++++---
xen/arch/riscv/intc.c | 11 ++++++++---
3 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/xen/arch/riscv/aplic.c b/xen/arch/riscv/aplic.c
index 739e8dab3498..620768fb6164 100644
--- a/xen/arch/riscv/aplic.c
+++ b/xen/arch/riscv/aplic.c
@@ -306,12 +306,16 @@ static const hw_irq_controller aplic_xen_irq_type = {
static const struct intc_hw_operations aplic_ops = {
.info = &aplic_info,
- .init = aplic_init,
.host_irq_type = &aplic_xen_irq_type,
.handle_interrupt = aplic_handle_interrupt,
.set_irq_type = aplic_set_irq_type,
};
+static const struct intc_hw_init_ops __initconst aplic_init_ops = {
+ .ops = &aplic_ops,
+ .init = aplic_init,
+};
+
static int cf_check aplic_irq_xlate(const uint32_t *intspec,
unsigned int intsize,
unsigned int *out_hwirq,
@@ -347,7 +351,7 @@ static int __init aplic_preinit(struct dt_device_node *node, const void *dat)
dt_irq_xlate = aplic_irq_xlate;
- register_intc_ops(&aplic_ops);
+ register_intc_ops(&aplic_init_ops);
/* Enable supervisor external interrupt */
csr_set(CSR_SIE, BIT(IRQ_S_EXT, UL));
diff --git a/xen/arch/riscv/include/asm/intc.h b/xen/arch/riscv/include/asm/intc.h
index ecdc8a5e6577..3d84fcc51d1a 100644
--- a/xen/arch/riscv/include/asm/intc.h
+++ b/xen/arch/riscv/include/asm/intc.h
@@ -28,8 +28,6 @@ struct intc_info {
struct intc_hw_operations {
/* Hold intc hw information */
const struct intc_info *info;
- /* Initialize the intc and the boot CPU */
- int (*init)(void);
/* hw_irq_controller to enable/disable/eoi host irq */
const struct hw_interrupt_type *host_irq_type;
@@ -43,9 +41,15 @@ struct intc_hw_operations {
void (*handle_interrupt)(struct cpu_user_regs *regs);
};
+struct intc_hw_init_ops {
+ const struct intc_hw_operations *ops;
+ /* Initialize the intc and the boot CPU */
+ int (*init)(void);
+};
+
void intc_preinit(void);
-void register_intc_ops(const struct intc_hw_operations *ops);
+void register_intc_ops(const struct intc_hw_init_ops *init_ops);
void intc_init(void);
diff --git a/xen/arch/riscv/intc.c b/xen/arch/riscv/intc.c
index ea317aea5ad8..3600d23bdb5b 100644
--- a/xen/arch/riscv/intc.c
+++ b/xen/arch/riscv/intc.c
@@ -12,9 +12,12 @@
static const struct intc_hw_operations *__ro_after_init intc_hw_ops;
-void __init register_intc_ops(const struct intc_hw_operations *ops)
+static const struct intc_hw_init_ops *__initdata intc_hw_init_ops;
+
+void __init register_intc_ops(const struct intc_hw_init_ops *init_ops)
{
- intc_hw_ops = ops;
+ intc_hw_ops = init_ops->ops;
+ intc_hw_init_ops = init_ops;
}
void __init intc_preinit(void)
@@ -27,7 +30,9 @@ void __init intc_preinit(void)
void __init intc_init(void)
{
- if ( intc_hw_ops->init() )
+ ASSERT(intc_hw_init_ops && intc_hw_init_ops->init);
+
+ if ( intc_hw_init_ops->init() )
panic("Failed to initialize the interrupt controller drivers\n");
}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 11/23] xen/riscv: implement make_intc_domU_node()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (9 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 10/23] xen/riscv: introduce init interrupt controller operations Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 12/23] xen/riscv: introduce aia_init() and aia_usable() Oleksii Kurochko
` (11 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Introduce a RISC-V specific function to create an interrupt controller
Device Tree node for DomU domains during dom0less build.
Add make_intc_domU_node() to the dom0less build path and wire it to
a new generic helper, intc_make_domu_dt_node(), which delegates DT
node creation to the active interrupt controller implementation via
vintc_init_ops.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Use const struct vintc_init_ops *init_ops in struct vintc.
- Drop redundant intc_hw_ops check in make_intc_domU_node().
- Drop NULL pointer checks in make_intc_domU_node() as we can't start domU
without properly created interrupt contoller node.
---
Changes in v2:
- s/intc_make_domu_dt_node/make_intc_domU_node.
- introduce separate intc_hw_init_ops structure for init operations.
- Return -EOPNOTSUPP instead of -ENOSYS.
- Drop const for kinfo argument as it could be changed by interrupt
controller node creation code.
- Refactor make_domu_dt_node().
- Make make_domu_dt_node part of vintc structure as it looks more logical to be
there.
---
---
xen/arch/riscv/include/asm/domain.h | 2 ++
xen/arch/riscv/include/asm/intc.h | 12 ++++++++++--
xen/arch/riscv/intc.c | 8 ++++++++
3 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/xen/arch/riscv/include/asm/domain.h b/xen/arch/riscv/include/asm/domain.h
index 459896c04b41..8e597e231ee7 100644
--- a/xen/arch/riscv/include/asm/domain.h
+++ b/xen/arch/riscv/include/asm/domain.h
@@ -98,6 +98,8 @@ struct arch_domain {
DECLARE_BITMAP(isa, RISCV_ISA_EXT_MAX);
char *isa_str;
+
+ struct vintc *vintc;
};
#include <xen/sched.h>
diff --git a/xen/arch/riscv/include/asm/intc.h b/xen/arch/riscv/include/asm/intc.h
index 3d84fcc51d1a..9b701445179f 100644
--- a/xen/arch/riscv/include/asm/intc.h
+++ b/xen/arch/riscv/include/asm/intc.h
@@ -8,14 +8,13 @@
#ifndef ASM__RISCV__INTERRUPT_CONTOLLER_H
#define ASM__RISCV__INTERRUPT_CONTOLLER_H
-struct dt_device_node;
-
enum intc_version {
INTC_APLIC,
};
struct cpu_user_regs;
struct irq_desc;
+struct kernel_info;
struct intc_info {
enum intc_version hw_version;
@@ -47,6 +46,15 @@ struct intc_hw_init_ops {
int (*init)(void);
};
+struct vintc_init_ops {
+ /* Create interrupt controller node for domain */
+ int (*make_domu_dt_node)(struct kernel_info *kinfo);
+};
+
+struct vintc {
+ const struct vintc_init_ops *init_ops;
+};
+
void intc_preinit(void);
void register_intc_ops(const struct intc_hw_init_ops *init_ops);
diff --git a/xen/arch/riscv/intc.c b/xen/arch/riscv/intc.c
index 3600d23bdb5b..31e08e3a1b65 100644
--- a/xen/arch/riscv/intc.c
+++ b/xen/arch/riscv/intc.c
@@ -3,6 +3,7 @@
#include <xen/acpi.h>
#include <xen/bug.h>
#include <xen/device_tree.h>
+#include <xen/fdt-kernel.h>
#include <xen/init.h>
#include <xen/irq.h>
#include <xen/lib.h>
@@ -72,3 +73,10 @@ void intc_route_irq_to_xen(struct irq_desc *desc, unsigned int priority)
intc_set_irq_type(desc, desc->arch.type);
intc_set_irq_priority(desc, priority);
}
+
+int __init make_intc_domU_node(struct kernel_info *kinfo)
+{
+ struct vintc *vintc = kinfo->bd.d->arch.vintc;
+
+ return vintc->init_ops->make_domu_dt_node(kinfo);
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 12/23] xen/riscv: introduce aia_init() and aia_usable()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (10 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 11/23] xen/riscv: implement make_intc_domU_node() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 13/23] xen/riscv: introduce per-vCPU IMSIC state Oleksii Kurochko
` (10 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
aia_init() is going to contain all the logic related to AIA initialization.
At the moment, it only checks whether the SSAIA extension is available,
and if so, sets is_aia_usable (which indicates more than just the
availability of the extension) to true; it also signifies that the necessary
components (to be introduced in follow-up patches) have been initialized.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- s/is_aia_usable/_aia_usable to drop the is_ prefix while avoiding
conflict with the aia_usable() function name.
---
Changes in v2:
- s/is_aia_available/is_aia_usable.
- Drop return value for aia_init().
- s/aia_available()/aia_usable().
---
---
xen/arch/riscv/Makefile | 1 +
xen/arch/riscv/aia.c | 23 +++++++++++++++++++++++
xen/arch/riscv/include/asm/aia.h | 10 ++++++++++
xen/arch/riscv/intc.c | 3 +++
4 files changed, 37 insertions(+)
create mode 100644 xen/arch/riscv/aia.c
create mode 100644 xen/arch/riscv/include/asm/aia.h
diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
index fd5e499eb4b9..9df8b72b5494 100644
--- a/xen/arch/riscv/Makefile
+++ b/xen/arch/riscv/Makefile
@@ -1,3 +1,4 @@
+obj-y += aia.o
obj-y += aplic.o
obj-y += cpufeature.o
obj-y += domain.o
diff --git a/xen/arch/riscv/aia.c b/xen/arch/riscv/aia.c
new file mode 100644
index 000000000000..e31c9c2d24b6
--- /dev/null
+++ b/xen/arch/riscv/aia.c
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/sections.h>
+#include <xen/types.h>
+
+#include <asm/cpufeature.h>
+
+static bool __ro_after_init _aia_usable;
+
+bool aia_usable(void)
+{
+ return _aia_usable;
+}
+
+void __init aia_init(void)
+{
+ if ( !riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ssaia) )
+ return;
+
+ _aia_usable = true;
+}
diff --git a/xen/arch/riscv/include/asm/aia.h b/xen/arch/riscv/include/asm/aia.h
new file mode 100644
index 000000000000..ca42c3086126
--- /dev/null
+++ b/xen/arch/riscv/include/asm/aia.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef ASM__RISCV__AIA_H
+#define ASM__RISCV__AIA_H
+
+bool aia_usable(void);
+
+void aia_init(void);
+
+#endif /* ASM__RISCV__ACPI_H */
diff --git a/xen/arch/riscv/intc.c b/xen/arch/riscv/intc.c
index 31e08e3a1b65..f0ce27a96c1d 100644
--- a/xen/arch/riscv/intc.c
+++ b/xen/arch/riscv/intc.c
@@ -9,6 +9,7 @@
#include <xen/lib.h>
#include <xen/spinlock.h>
+#include <asm/aia.h>
#include <asm/intc.h>
static const struct intc_hw_operations *__ro_after_init intc_hw_ops;
@@ -33,6 +34,8 @@ void __init intc_init(void)
{
ASSERT(intc_hw_init_ops && intc_hw_init_ops->init);
+ aia_init();
+
if ( intc_hw_init_ops->init() )
panic("Failed to initialize the interrupt controller drivers\n");
}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 13/23] xen/riscv: introduce per-vCPU IMSIC state
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (11 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 12/23] xen/riscv: introduce aia_init() and aia_usable() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 14/23] xen/riscv: add very early virtual APLIC (vAPLIC) initialization support Oleksii Kurochko
` (9 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Each vCPU interacting with the IMSIC requires state to track the
associated guest interrupt file and its backing context.
Introduce a per-vCPU structure to hold IMSIC-related state, including
the guest interrupt file identifier and the CPU providing the backing
VS-file. Access to the guest file identifier is protected by a lock.
Initialize this structure during vCPU setup and store it in arch_vcpu.
The initial state marks the VS-file as software-backed until it becomes
associated with a physical CPU.
Add helper to retrieve the guest interrupt file identifier:
- vcpu_guest_file_id() is going to be used during update of APLIC's
target register with the pair of information <guest_file_id, cpu_id>
(to have MSI delivery mode work properly) when guest is trying to
access vAPLIC's target register.
It will be used in the follow up patches.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Drop const from imsic_set_guest_file_id() and vcpu_imsic_deinit() as
it only works due to vimsic_state being a pointer member.
- Use XVFREE() in vcpu_imsic_deinit() to make it idempotent.
- Fix SW-file typo in struct vimsic_state comments; should be VS-file.
- Drop imsic_set_guest_file_id() here, it will be added later when it
will be nessary to initialise guest file id as the correspondendt code
in this patch series was reworked and there is no need to use this
function in arch_vcpu_create().
- Introduce IMPOSSIBLE_GUEST_FILE_ID and init with it ->guest_file_id.
---
Changes in v2:
- Rename imsic_state to vimsic_state.
- Use 'unsigned int' for vsfile_pcpu.
- Drop initialzation of ->guest_file_id as it will be by default zero.
- Add the comment about ->guest_file_id field.
- Drop __init for vcpu_imsic_init() as it could be used during post-boot
vCPU creation.
- Update the commit message.
- Drop locks around ->guest_file_id() in vcpu_guest_file_id() and imsic_set_guest_file_id().
---
---
xen/arch/riscv/imsic.c | 34 +++++++++++++++++++++++++++++
xen/arch/riscv/include/asm/domain.h | 2 ++
xen/arch/riscv/include/asm/imsic.h | 22 +++++++++++++++++++
3 files changed, 58 insertions(+)
diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c
index f7b70a8da09e..59c7556327da 100644
--- a/xen/arch/riscv/imsic.c
+++ b/xen/arch/riscv/imsic.c
@@ -16,12 +16,15 @@
#include <xen/errno.h>
#include <xen/init.h>
#include <xen/macros.h>
+#include <xen/sched.h>
#include <xen/smp.h>
#include <xen/spinlock.h>
#include <xen/xvmalloc.h>
#include <asm/imsic.h>
+#define IMPOSSIBLE_GUEST_FILE_ID UINT32_MAX
+
#define IMSIC_HART_SIZE(guest_bits) (BIT(guest_bits, U) * IMSIC_MMIO_PAGE_SZ)
struct imsic_mmios {
@@ -56,6 +59,11 @@ do { \
csr_clear(CSR_SIREG, v); \
} while (0)
+unsigned int vcpu_guest_file_id(const struct vcpu *v)
+{
+ return ACCESS_ONCE(v->arch.vimsic_state->guest_file_id);
+}
+
void __init imsic_ids_local_delivery(bool enable)
{
if ( enable )
@@ -312,6 +320,32 @@ static int imsic_parse_node(const struct dt_device_node *node,
return 0;
}
+int vcpu_imsic_init(struct vcpu *v)
+{
+ struct vimsic_state *imsic_state;
+
+ /* Allocate IMSIC context */
+ imsic_state = xvzalloc(struct vimsic_state);
+ if ( !imsic_state )
+ return -ENOMEM;
+
+ v->arch.vimsic_state = imsic_state;
+
+ /* Setup IMSIC context */
+ rwlock_init(&imsic_state->vsfile_lock);
+
+ imsic_state->vsfile_pcpu = NR_CPUS;
+
+ imsic_state->guest_file_id = IMPOSSIBLE_GUEST_FILE_ID;
+
+ return 0;
+}
+
+void vcpu_imsic_deinit(struct vcpu *v)
+{
+ XVFREE(v->arch.vimsic_state);
+}
+
/*
* Initialize the imsic_cfg structure based on the IMSIC DT node.
*
diff --git a/xen/arch/riscv/include/asm/domain.h b/xen/arch/riscv/include/asm/domain.h
index 8e597e231ee7..bbeac7518a85 100644
--- a/xen/arch/riscv/include/asm/domain.h
+++ b/xen/arch/riscv/include/asm/domain.h
@@ -54,6 +54,8 @@ struct arch_vcpu {
struct vtimer vtimer;
+ struct vimsic_state *vimsic_state;
+
register_t hcounteren;
register_t hedeleg;
register_t hideleg;
diff --git a/xen/arch/riscv/include/asm/imsic.h b/xen/arch/riscv/include/asm/imsic.h
index c6c59215df20..316fe5423c48 100644
--- a/xen/arch/riscv/include/asm/imsic.h
+++ b/xen/arch/riscv/include/asm/imsic.h
@@ -11,6 +11,7 @@
#ifndef ASM_RISCV_IMSIC_H
#define ASM_RISCV_IMSIC_H
+#include <xen/rwlock.h>
#include <xen/spinlock.h>
#include <xen/stdbool.h>
#include <xen/types.h>
@@ -61,7 +62,24 @@ struct imsic_config {
spinlock_t lock;
};
+struct vimsic_state {
+ /* IMSIC VS-file */
+ rwlock_t vsfile_lock;
+ /*
+ * (guest_file_id == 0) -> s/w IMSIC VS-file
+ * (guest_file_id > 0) -> h/w IMSIC VS-file
+ */
+ unsigned int guest_file_id;
+ /*
+ * (vsfile_pcpu >= 0) => h/w IMSIC VS-file
+ * (vsfile_pcpu == NR_CPUS) => s/w IMSIC VS-file
+ */
+ unsigned int vsfile_pcpu;
+};
+
struct dt_device_node;
+struct vcpu;
+
int imsic_init(const struct dt_device_node *node);
const struct imsic_config *imsic_get_config(void);
@@ -71,4 +89,8 @@ void imsic_irq_disable(unsigned int hwirq);
void imsic_ids_local_delivery(bool enable);
+int vcpu_imsic_init(struct vcpu *v);
+void vcpu_imsic_deinit(struct vcpu *v);
+unsigned int vcpu_guest_file_id(const struct vcpu *v);
+
#endif /* ASM_RISCV_IMSIC_H */
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 14/23] xen/riscv: add very early virtual APLIC (vAPLIC) initialization support
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (12 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 13/23] xen/riscv: introduce per-vCPU IMSIC state Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 15/23] xen/riscv: introduce (de)initialization helpers for vINTC Oleksii Kurochko
` (8 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
At the current development stage, only domain vINTC init and deinit
operations are required, so implement those first.
Initialize vAPLIC's domaincfg to with the interrupt-enable bit set and
MSI delivery mode selected as the current solution is exepcted to have
always IMSIC, and initialize vintc->ops.
Other operations such as emulate_load(), emulate_store(), and is_access()
will be needed once guests are running and MMIO accesses to APLIC MMIO
range must be handled. These will be introduced separately later.
Introduce a structure to describe a virtual interrupt controller (vINTC)
and a vintc_ops structure, which provides operations to emulate load and
store accesses to interrupt controller MMIOs and to check whether a given
address falls within the MMIO range of a specific virtual interrupt
controller.
The vAPLIC implementation of these operations will be provided later
once guests can be run and these operations are actually needed.
Introduce these structures here as they are required for the implementation
of domain_vaplic_init() and domain_vaplic_alloc(). Also, introduce
vaplic_init() and init vintc_ops->vcpu_init() with it.
Co-developed-by: Romain Caritey <Romain.Caritey@microchip.com>
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Drop ASSERT() before vintc->ops->vcpu_init() in arch_vcpu_create(); a
NULL deref already produces a sufficient backtrace.
- Parenthesize macro argument in to_vaplic().
- Drop __init from domain_vaplic_init() and domain_vaplic_deinit() since
the caller domain_vintc_init() (follow-up patch) is not __init.
- Remove pointless zero-initializer for rc in vcpu_vaplic_init().
- Fix domain_vaplic_deinit() to null d->arch.vintc before freeing, making
the function idempotent.
- Drop intc_irq_nums(), (*nr_irqs)(void) hook from intc_hw_operations,
aplic_nr_irqs(), and vintc->nr_irqs field entirely.
- Rename vcpu_vaplic_init() to vaplic_init() and drop vgein_assign() and
imsic_set_guest_file_id() calls; those will be introduced/called later,
where for sure we will know on which pCPU vCPU as it is required for
proper h/w IMSIC interrupt file calculation, to have this initialization
in one place.
- Introduce vaplic_deinit().
---
Changes in v2:
- s/vcpu/v for function arguments in struct vintc_ops().
- Update the comment above is_access() and drop const for addr argument.
- Update to_vaplic() to work with 'struct domain *'.
- Drop smsiaddrcfg{h} from vaplic_regs struct as they aren't used for now.
- Drop inclusion of xen/schec.h from intc.c.
- use result of xvzalloc() as initializer in vpalic_alloc().
- Drop goto in domain_vaplic_init().
- s/XVFREE/xvfree.
- s/aplic/vintc.
- Drop __init for vcpu_vaplic_init() as it could be called for secondary CPU bring up.
- Drop vaplic_alloc().
- Drop vintc_ops struct, embed callbacks iniside struct vintc.
- Introduce and init vintc irqs for vAPLIC.
- Introduce intc_irq_nums() to properly initialize number of vAPLIC's irqs.
---
---
xen/arch/riscv/Makefile | 1 +
xen/arch/riscv/domain.c | 11 ++---
xen/arch/riscv/include/asm/aplic.h | 1 +
xen/arch/riscv/include/asm/intc.h | 12 ++++++
xen/arch/riscv/include/asm/vaplic.h | 34 ++++++++++++++++
xen/arch/riscv/vaplic.c | 63 +++++++++++++++++++++++++++++
6 files changed, 114 insertions(+), 8 deletions(-)
create mode 100644 xen/arch/riscv/include/asm/vaplic.h
create mode 100644 xen/arch/riscv/vaplic.c
diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
index 9df8b72b5494..9d8d21b65188 100644
--- a/xen/arch/riscv/Makefile
+++ b/xen/arch/riscv/Makefile
@@ -25,6 +25,7 @@ obj-y += smpboot.o
obj-y += stubs.o
obj-y += time.o
obj-y += traps.o
+obj-y += vaplic.o
obj-y += vmid.o
obj-y += vm_event.o
obj-y += vsbi/
diff --git a/xen/arch/riscv/domain.c b/xen/arch/riscv/domain.c
index e4a8c27ea9cb..129e775c52cb 100644
--- a/xen/arch/riscv/domain.c
+++ b/xen/arch/riscv/domain.c
@@ -11,6 +11,7 @@
#include <asm/bitops.h>
#include <asm/cpufeature.h>
#include <asm/csr.h>
+#include <asm/intc.h>
#include <asm/riscv_encoding.h>
#include <asm/vtimer.h>
@@ -155,14 +156,8 @@ int arch_vcpu_create(struct vcpu *v)
if ( (rc = vcpu_vtimer_init(v)) )
goto fail;
- /*
- * As interrupt controller (IC) is not yet implemented,
- * return an error.
- *
- * TODO: Drop this once IC is implemented.
- */
- rc = -EOPNOTSUPP;
- goto fail;
+ if ( (rc = v->domain->arch.vintc->ops->vcpu_init(v)) )
+ goto fail;
return rc;
diff --git a/xen/arch/riscv/include/asm/aplic.h b/xen/arch/riscv/include/asm/aplic.h
index b0724fe6f360..d443faac57c4 100644
--- a/xen/arch/riscv/include/asm/aplic.h
+++ b/xen/arch/riscv/include/asm/aplic.h
@@ -15,6 +15,7 @@
#include <asm/imsic.h>
+#define APLIC_DOMAINCFG_RO80 (0x80U << 24)
#define APLIC_DOMAINCFG_IE BIT(8, U)
#define APLIC_DOMAINCFG_DM BIT(2, U)
diff --git a/xen/arch/riscv/include/asm/intc.h b/xen/arch/riscv/include/asm/intc.h
index 9b701445179f..d3d456afe5f0 100644
--- a/xen/arch/riscv/include/asm/intc.h
+++ b/xen/arch/riscv/include/asm/intc.h
@@ -15,6 +15,7 @@ enum intc_version {
struct cpu_user_regs;
struct irq_desc;
struct kernel_info;
+struct vcpu;
struct intc_info {
enum intc_version hw_version;
@@ -38,6 +39,7 @@ struct intc_hw_operations {
/* handle external interrupt */
void (*handle_interrupt)(struct cpu_user_regs *regs);
+
};
struct intc_hw_init_ops {
@@ -51,8 +53,17 @@ struct vintc_init_ops {
int (*make_domu_dt_node)(struct kernel_info *kinfo);
};
+struct vintc_ops {
+ /* Initialize some vINTC-related stuff for a vCPU */
+ int (*vcpu_init)(struct vcpu *v);
+
+ /* Deinitialize some vINTC-related stuff for a vCPU */
+ void (*vcpu_deinit)(struct vcpu *v);
+};
+
struct vintc {
const struct vintc_init_ops *init_ops;
+ const struct vintc_ops *ops;
};
void intc_preinit(void);
@@ -65,4 +76,5 @@ void intc_route_irq_to_xen(struct irq_desc *desc, unsigned int priority);
void intc_handle_external_irqs(struct cpu_user_regs *regs);
+
#endif /* ASM__RISCV__INTERRUPT_CONTOLLER_H */
diff --git a/xen/arch/riscv/include/asm/vaplic.h b/xen/arch/riscv/include/asm/vaplic.h
new file mode 100644
index 000000000000..96080bfbc23b
--- /dev/null
+++ b/xen/arch/riscv/include/asm/vaplic.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * xen/arch/riscv/vaplic.c
+ *
+ * Virtual RISC-V Advanced Platform-Level Interrupt Controller support
+ *
+ * Copyright (c) Microchip.
+ */
+
+#ifndef ASM__RISCV__VAPLIC_H
+#define ASM__RISCV__VAPLIC_H
+
+#include <xen/kernel.h>
+#include <xen/types.h>
+
+#include <asm/intc.h>
+
+struct domain;
+
+#define to_vaplic(d) container_of((d)->arch.vintc, struct vaplic, vintc)
+
+struct vaplic_regs {
+ uint32_t domaincfg;
+};
+
+struct vaplic {
+ struct vintc vintc;
+ struct vaplic_regs regs;
+};
+
+int domain_vaplic_init(struct domain *d);
+void domain_vaplic_deinit(struct domain *d);
+
+#endif /* ASM__RISCV__VAPLIC_H */
diff --git a/xen/arch/riscv/vaplic.c b/xen/arch/riscv/vaplic.c
new file mode 100644
index 000000000000..8170e93701ad
--- /dev/null
+++ b/xen/arch/riscv/vaplic.c
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * xen/arch/riscv/vaplic.c
+ *
+ * Virtual RISC-V Advanced Platform-Level Interrupt Controller support
+ *
+ * Copyright (c) Microchip.
+ * Copyright (c) Vates
+ */
+
+#include <xen/errno.h>
+#include <xen/sched.h>
+#include <xen/xvmalloc.h>
+
+#include <asm/aia.h>
+#include <asm/imsic.h>
+#include <asm/intc.h>
+#include <asm/vaplic.h>
+
+#include "aplic-priv.h"
+
+static int cf_check vaplic_init(struct vcpu *v)
+{
+ return vcpu_imsic_init(v);
+}
+
+static void cf_check vaplic_deinit(struct vcpu *v)
+{
+ return vcpu_imsic_deinit(v);
+}
+
+static const struct vintc_ops vintc_ops = {
+ .vcpu_init = vaplic_init,
+ .vcpu_deinit = vaplic_deinit,
+};
+
+int domain_vaplic_init(struct domain *d)
+{
+ struct vaplic *vaplic = xvzalloc(struct vaplic);
+
+ if ( !vaplic )
+ return -ENOMEM;
+
+ d->arch.vintc = &vaplic->vintc;
+ d->arch.vintc->ops = &vintc_ops;
+
+ vaplic->regs.domaincfg = APLIC_DOMAINCFG_IE | APLIC_DOMAINCFG_DM |
+ APLIC_DOMAINCFG_RO80;
+
+ return 0;
+}
+
+void domain_vaplic_deinit(struct domain *d)
+{
+ struct vaplic *vaplic;
+
+ if ( !d->arch.vintc )
+ return;
+
+ vaplic = to_vaplic(d);
+ d->arch.vintc = NULL;
+ xvfree(vaplic);
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 15/23] xen/riscv: introduce (de)initialization helpers for vINTC
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (13 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 14/23] xen/riscv: add very early virtual APLIC (vAPLIC) initialization support Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 16/23] xen/riscv: generate IMSIC DT node for guest domains Oleksii Kurochko
` (7 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Add common helpers domain_vintc_init() and domain_vintc_deinit() to
allocate and deallocate a virtual interrupt controller (vINTC)
structure and initialize basic virtual interrupt controller registers.
domain_vintc_deinit() isn't called at the moment as arch_domain_destroy()
is implemented as stub at the moment.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Drop redundant printk() from domain_vintc_deinit()'s default case to
avoid duplicate messages when init fails.
- Add a comment to domain_vintc_init() clarifying that guests currently
receive a virtual interrupt controller that mirrors the host hardware.
---
Changes in v2:
- Drop __init for domain_vintc_(de)init().
- Update the commit message.
---
---
xen/arch/riscv/domain.c | 3 +++
xen/arch/riscv/include/asm/intc.h | 3 +++
xen/arch/riscv/intc.c | 40 +++++++++++++++++++++++++++++++
3 files changed, 46 insertions(+)
diff --git a/xen/arch/riscv/domain.c b/xen/arch/riscv/domain.c
index 129e775c52cb..3499c25dcfe0 100644
--- a/xen/arch/riscv/domain.c
+++ b/xen/arch/riscv/domain.c
@@ -309,6 +309,9 @@ int arch_domain_create(struct domain *d,
if ( (rc = p2m_init(d, config)) != 0)
goto fail;
+ if ( (rc = domain_vintc_init(d)) )
+ goto fail;
+
return rc;
fail:
diff --git a/xen/arch/riscv/include/asm/intc.h b/xen/arch/riscv/include/asm/intc.h
index d3d456afe5f0..95ca526e1223 100644
--- a/xen/arch/riscv/include/asm/intc.h
+++ b/xen/arch/riscv/include/asm/intc.h
@@ -77,4 +77,7 @@ void intc_route_irq_to_xen(struct irq_desc *desc, unsigned int priority);
void intc_handle_external_irqs(struct cpu_user_regs *regs);
+int domain_vintc_init(struct domain *d);
+void domain_vintc_deinit(struct domain *d);
+
#endif /* ASM__RISCV__INTERRUPT_CONTOLLER_H */
diff --git a/xen/arch/riscv/intc.c b/xen/arch/riscv/intc.c
index f0ce27a96c1d..ec37b359f323 100644
--- a/xen/arch/riscv/intc.c
+++ b/xen/arch/riscv/intc.c
@@ -11,6 +11,7 @@
#include <asm/aia.h>
#include <asm/intc.h>
+#include <asm/vaplic.h>
static const struct intc_hw_operations *__ro_after_init intc_hw_ops;
@@ -83,3 +84,42 @@ int __init make_intc_domU_node(struct kernel_info *kinfo)
return vintc->init_ops->make_domu_dt_node(kinfo);
}
+
+/*
+ * Guests are given a virtual interrupt controller that mirrors the host
+ * hardware: an AIA-capable host yields a virtual AIA for the guest, and
+ * so on for any future controller types.
+ */
+int domain_vintc_init(struct domain *d)
+{
+ int ret = -EOPNOTSUPP;
+ const enum intc_version ver = intc_hw_ops->info->hw_version;
+
+ switch ( ver )
+ {
+ case INTC_APLIC:
+ ret = domain_vaplic_init(d);
+ break;
+
+ default:
+ printk("vintc (ver:%d) isn't implemented\n", ver);
+ break;
+ }
+
+ return ret;
+}
+
+void domain_vintc_deinit(struct domain *d)
+{
+ const enum intc_version ver = intc_hw_ops->info->hw_version;
+
+ switch ( ver )
+ {
+ case INTC_APLIC:
+ domain_vaplic_deinit(d);
+ break;
+
+ default:
+ break;
+ }
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 16/23] xen/riscv: generate IMSIC DT node for guest domains
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (14 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 15/23] xen/riscv: introduce (de)initialization helpers for vINTC Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:24 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 17/23] xen/riscv: create APLIC " Oleksii Kurochko
` (6 subsequent siblings)
22 siblings, 1 reply; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Andrew Cooper, Anthony PERARD,
Michal Orzel, Jan Beulich, Julien Grall, Roger Pau Monné,
Stefano Stabellini, Alistair Francis, Connor Davis
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 <Romain.Caritey@microchip.com>
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
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_ids.
- 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_prop.
- 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.
---
---
...asic-VGEIN-management-for-AIA-guests.patch | 273 ++++++++++++++++++
xen/arch/riscv/imsic.c | 132 +++++++++
xen/arch/riscv/include/asm/guest-layout.h | 2 +
3 files changed, 407 insertions(+)
create mode 100644 0001-xen-riscv-add-basic-VGEIN-management-for-AIA-guests.patch
diff --git a/0001-xen-riscv-add-basic-VGEIN-management-for-AIA-guests.patch b/0001-xen-riscv-add-basic-VGEIN-management-for-AIA-guests.patch
new file mode 100644
index 000000000000..ae8c3425507f
--- /dev/null
+++ b/0001-xen-riscv-add-basic-VGEIN-management-for-AIA-guests.patch
@@ -0,0 +1,273 @@
+From e423a993b2ccb28f59a2d941c503d7bb5b29e683 Mon Sep 17 00:00:00 2001
+From: Oleksii Kurochko <oleksii.kurochko@gmail.com>
+Date: Thu, 1 Jan 2026 12:53:07 +0100
+Subject: [PATCH] xen/riscv: add basic VGEIN management for AIA guests
+
+It was decided to add support for IMSIC from the start instead of having APLIC
+operate in direct delivery mode, as it requires a trap-and-emulation approach,
+which is not optimal from a performance standpoint.
+
+AIA provides a hardware-accelerated mechanism for delivering external
+interrupts to domains via "guest interrupt files" located in IMSIC.
+A single physical hart can implement multiple such files (up to GEILEN),
+allowing several virtual harts to receive interrupts directly from hardware.
+
+Introduce per-CPU tracking of guest interrupt file identifiers (VGEIN)
+for systems implementing AIA specification. Each CPU maintains
+a bitmap describing which guest interrupt files are currently in use.
+
+Add helpers to initialize the bitmap based on the number of available
+guest interrupt files (GEILEN), assign a VGEIN to a vCPU, and release it
+when no longer needed. When assigning a VGEIN, the corresponding value
+is written to the VGEIN field of the guest hstatus register so that
+VS-level external interrupts are delivered from the selected interrupt
+file.
+
+Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
+---
+Changes in v3:
+ - Rephrase per-CPU comment from "Bitmap for each physical cpus..." to
+ "VGEIN control structure for each physical CPU...".
+ - Use %u for cpu in printk("cpu%u.geilen=%u\n").
+ - Fix missing \n in "AIA: failed to init vgein for CPU%u\n".
+ - Shorten dprintk message to "vgein_init() failed: %d\n".
+ - Use %u instead of %d for v->processor in gprintk() calls.
+ - Drop redundant hstatus &= ~HSTATUS_VGEIN in vgein_assign() as
+ hstatus is already cleared before the assignment.
+ - Add check that vgein_id isn't 0 as we don't support s/w interrupt files
+ for the momemnt.
+---
+Changes in v2:
+ - add static for defintion of vgein_bmp;
+ - Drop declarartion of vgein_bmp from aia.h.
+ - Move declaration of 'struct vgein_bmp' from aia.h to aia.c as all the
+ management is inside aia.c.
+ - Instead of decrement of vgein->geilen just update the wait how it is
+ initialized.
+ - Return -EOPNOTSUPP in vgein_init() instead of BUG_ON().
+ - Use %u to print unsigned int.
+ - make bmp field in vgein_bmp not a pointer.
+ - allocate owners dynamically.
+ - Drop unnessary blank lines.
+ - use find_first_zero_bit() instead of bitmap_weight() to find a free slot
+ for vgein number.
+ - Drop the section number for the comment.
+ - Start to search from bitnum 1 for free vgein_id, as bitnum 0 is reserved to
+ tell that no guest extrenal interrupt number is used. Thereby drop vgein_id++
+ at the end of vgein_assign().
+ - s/bitmap_set/__set_bit.
+ - s/bitmap_clear/__clear_bit.
+ - as vgein_init() is needed to be invoked once per CPU being brought up, drop
+ __init for it.
+ - Return vgein_id == 0 if vgein_id is higher then maximun supported by h/w
+ VGEIN.
+ - Add check in vgein_relase() that vgein is 0 and if it is there is nothing
+ is needed to do.
+ - Use gdprintk instead of printk() in vgein_{assign,release}.
+ - Add the claryfing comment above geilen field.
+ - Drop ASSERT in vgein_assign() and return just vgein_id = 0 in the case when
+ there is no aviablable h/w VGEINs.
+ - Make vgein_init() static.
+---
+---
+ xen/arch/riscv/aia.c | 146 +++++++++++++++++++++++++++++++
+ xen/arch/riscv/include/asm/aia.h | 8 ++
+ 2 files changed, 154 insertions(+)
+
+diff --git a/xen/arch/riscv/aia.c b/xen/arch/riscv/aia.c
+index e31c9c2d24b6..5afecde81d3a 100644
+--- a/xen/arch/riscv/aia.c
++++ b/xen/arch/riscv/aia.c
+@@ -1,11 +1,33 @@
+ /* SPDX-License-Identifier: GPL-2.0-only */
+
++#include <xen/bitmap.h>
++#include <xen/cpu.h>
+ #include <xen/errno.h>
+ #include <xen/init.h>
+ #include <xen/sections.h>
++#include <xen/sched.h>
++#include <xen/spinlock.h>
+ #include <xen/types.h>
++#include <xen/xvmalloc.h>
+
++#include <asm/aia.h>
+ #include <asm/cpufeature.h>
++#include <asm/csr.h>
++#include <asm/current.h>
++
++struct vgein_ctrl {
++ unsigned long bmp;
++ spinlock_t lock;
++ struct vcpu **owners;
++ /* The least-significant bits are implemented first, apart from bit 0 */
++ unsigned int geilen;
++};
++
++/*
++ * VGEIN control structure for each physical CPU to track which VS (guest)
++ * interrupt file IDs are in use.
++ */
++static DEFINE_PER_CPU(struct vgein_ctrl, vgein);
+
+ static bool __ro_after_init _aia_usable;
+
+@@ -14,10 +36,134 @@ bool aia_usable(void)
+ return _aia_usable;
+ }
+
++static int vgein_init(unsigned int cpu)
++{
++ struct vgein_ctrl *vgein = &per_cpu(vgein, cpu);
++
++ csr_write(CSR_HGEIE, -1UL);
++ vgein->geilen = flsl(csr_read(CSR_HGEIE) >> 1);
++ csr_write(CSR_HGEIE, 0);
++
++ printk("cpu%u.geilen=%u\n", cpu, vgein->geilen);
++
++ if ( !vgein->geilen )
++ return -EOPNOTSUPP;
++
++ vgein->owners = xvzalloc_array(struct vcpu *, vgein->geilen);
++ if ( !vgein->owners )
++ return -ENOMEM;
++
++ spin_lock_init(&vgein->lock);
++
++ return 0;
++}
++
++static int cf_check cpu_callback(struct notifier_block *nfb, unsigned long action,
++ void *hcpu)
++{
++ unsigned int cpu = (unsigned long)hcpu;
++ int rc = 0;
++
++ switch ( action )
++ {
++ case CPU_STARTING:
++ rc = vgein_init(cpu);
++ if ( rc )
++ printk("AIA: failed to init vgein for CPU%u\n", cpu);
++ break;
++ }
++
++ return notifier_from_errno(rc);
++}
++
++static struct notifier_block cpu_nfb = {
++ .notifier_call = cpu_callback,
++};
++
+ void __init aia_init(void)
+ {
++ int rc;
++
+ if ( !riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ssaia) )
++ {
++ dprintk(XENLOG_WARNING, "SSAIA isn't present in riscv,isa\n");
++ return;
++ }
++
++ if ( (rc = vgein_init(0)) )
++ {
++ dprintk(XENLOG_ERR, "vgein_init() failed: %d\n", rc);
+ return;
++ }
+
+ _aia_usable = true;
++
++ register_cpu_notifier(&cpu_nfb);
++}
++
++unsigned int vgein_assign(struct vcpu *v)
++{
++ unsigned int vgein_id;
++ struct vgein_ctrl *vgein = &per_cpu(vgein, v->processor);
++ unsigned long *bmp = &vgein->bmp;
++ unsigned long flags;
++
++ spin_lock_irqsave(&vgein->lock, flags);
++ /*
++ * The vgein_id shouldn't be zero, as it will indicate that no guest
++ * external interrupt source is selected for VS-level external interrupts
++ * according to RISC-V priviliged spec:
++ * Hypervisor Status Register (hstatus) in RISC-V priviliged spec:
++ *
++ * The VGEIN (Virtual Guest External Interrupt Number) field selects
++ * a guest external interrupt source for VS-level external interrupts.
++ * VGEIN is a WLRL field that must be able to hold values between zero
++ * and the maximum guest external interrupt number (known as GEILEN),
++ * inclusive.
++ * When VGEIN=0, no guest external interrupt source is selected for
++ * VS-level external interrupts.
++ *
++ * So start to search from bit number 1.
++ */
++ vgein_id = find_next_zero_bit(bmp, vgein->geilen + 1, 1);
++
++ if ( vgein_id > vgein->geilen )
++ vgein_id = 0;
++ else
++ __set_bit(vgein_id, bmp);
++
++ spin_unlock_irqrestore(&vgein->lock, flags);
++
++#ifdef VGEIN_DEBUG
++ gprintk(XENLOG_DEBUG, "%s: %pv: vgein_id(%u), xen_cpu%u_bmp=%#lx\n",
++ __func__, v, vgein_id, v->processor, *bmp);
++#endif
++
++ vcpu_guest_cpu_user_regs(v)->hstatus |=
++ MASK_INSR(vgein_id, HSTATUS_VGEIN);
++
++ if ( !vgein_id )
++ domain_crash(v->domain, "s/w interrupt file isn't supported yet\n");
++
++ return vgein_id;
++}
++
++void vgein_release(struct vcpu *v, unsigned int vgen_id)
++{
++ unsigned long flags;
++ struct vgein_ctrl *vgein = &per_cpu(vgein, v->processor);
++
++ if ( !vgen_id )
++ return;
++
++ spin_lock_irqsave(&vgein->lock, flags);
++ __clear_bit(vgen_id, &vgein->bmp);
++ spin_unlock_irqrestore(&vgein->lock, flags);
++
++#ifdef VGEIN_DEBUG
++ gprintk(XENLOG_DEBUG, "%s: vgein_id(%u), xen_cpu%u_bmp=%#lx\n",
++ __func__, vgen_id, v->processor, vgein->bmp);
++#endif
++
++ vcpu_guest_cpu_user_regs(v)->hstatus &= ~HSTATUS_VGEIN;
+ }
+diff --git a/xen/arch/riscv/include/asm/aia.h b/xen/arch/riscv/include/asm/aia.h
+index ca42c3086126..6073c89774bb 100644
+--- a/xen/arch/riscv/include/asm/aia.h
++++ b/xen/arch/riscv/include/asm/aia.h
+@@ -3,8 +3,16 @@
+ #ifndef ASM__RISCV__AIA_H
+ #define ASM__RISCV__AIA_H
+
++#include <xen/percpu.h>
++#include <xen/spinlock.h>
++
++struct vcpu;
++
+ bool aia_usable(void);
+
+ void aia_init(void);
+
++unsigned int vgein_assign(struct vcpu *v);
++void vgein_release(struct vcpu *v, unsigned int vgen_id);
++
+ #endif /* ASM__RISCV__ACPI_H */
+--
+2.54.0
+
diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c
index 59c7556327da..de8c54cb33fd 100644
--- a/xen/arch/riscv/imsic.c
+++ b/xen/arch/riscv/imsic.c
@@ -13,8 +13,12 @@
#include <xen/const.h>
#include <xen/cpumask.h>
#include <xen/device_tree.h>
+#include <xen/domain.h>
#include <xen/errno.h>
+#include <xen/fdt-domain-build.h>
+#include <xen/fdt-kernel.h>
#include <xen/init.h>
+#include <xen/libfdt/libfdt.h>
#include <xen/macros.h>
#include <xen/sched.h>
#include <xen/smp.h>
@@ -36,6 +40,11 @@ static struct imsic_config imsic_cfg = {
.lock = SPIN_LOCK_UNLOCKED,
};
+static unsigned int __read_mostly guest_num_msis;
+
+#define GUEST_IMSIC_COMPATIBLE "riscv,imsics"
+#define GUEST_IMSIC_NUM_MSIS 255
+
#define IMSIC_DISABLE_EIDELIVERY 0
#define IMSIC_ENABLE_EIDELIVERY 1
#define IMSIC_DISABLE_EITHRESHOLD 1
@@ -287,6 +296,11 @@ static int imsic_parse_node(const struct dt_device_node *node,
return -ENOENT;
}
+ if ( dt_property_read_u32(node, "riscv,num-guest-ids", &tmp) )
+ guest_num_msis = tmp;
+ else
+ guest_num_msis = IMSIC_MAX_ID;
+
if ( (imsic_cfg.nr_ids < IMSIC_MIN_ID) ||
(imsic_cfg.nr_ids > IMSIC_MAX_ID) )
{
@@ -521,3 +535,121 @@ int __init imsic_init(const struct dt_device_node *node)
return rc;
}
+
+static int __init guest_imsic_make_reg_property(struct domain *d, void *fdt)
+{
+ paddr_t size = IMSIC_MMIO_PAGE_SZ * d->max_vcpus;
+ __be32 regs[4] = {
+ 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 = 0;
+ __be32 *irq_ext;
+ int res;
+
+ irq_ext = xvzalloc_array(__be32, d->max_vcpus * 2);
+ if ( !irq_ext )
+ return -ENOMEM;
+
+ for ( cpu = 0; cpu < d->max_vcpus; cpu++ )
+ {
+ char buf[64];
+ uint32_t phandle;
+
+ snprintf(buf, sizeof(buf), "/cpus/cpu@%u/interrupt-controller", cpu);
+ phandle = fdt_get_phandle(fdt, fdt_path_offset(fdt, buf));
+
+ if ( !phandle )
+ {
+ res = -ENODEV;
+ goto out;
+ }
+
+ irq_ext[pos++] = cpu_to_be32(phandle);
+ irq_ext[pos++] = cpu_to_be32(IRQ_S_EXT);
+ }
+
+ res = 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 = kinfo->fdt;
+ char vimsic_name[128];
+ unsigned int vimsic_phandle;
+ unsigned int num_msis = min(GUEST_IMSIC_NUM_MSIS + 0U, guest_num_msis);
+
+ res = snprintf(vimsic_name, sizeof(vimsic_name), "/soc/imsic@%lx",
+ GUEST_IMSIC_S_BASE);
+ if ( res >= sizeof(vimsic_name) )
+ {
+ dprintk(XENLOG_DEBUG, "vimsic name is truncated\n");
+ return -ENOBUFS;
+ }
+
+ res = fdt_begin_node(fdt, vimsic_name);
+ if ( res )
+ return res;
+
+ res = fdt_property_string(fdt, "compatible", GUEST_IMSIC_COMPATIBLE);
+ if ( res )
+ return res;
+
+ res = guest_imsic_make_reg_property(kinfo->bd.d, fdt);
+ if ( res )
+ return res;
+
+ res = guest_imsic_set_interrupt_extended_prop(kinfo->bd.d, fdt);
+ if ( res )
+ return res;
+
+ res = fdt_property_u32(fdt, "riscv,num-ids", num_msis);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "msi-controller", NULL, 0);
+ if ( res )
+ return res;
+
+ res = fdt_property_u32(fdt, "#msi-cells", 0);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "interrupt-controller", NULL, 0);
+ if ( res )
+ return res;
+
+ res = fdt_property_u32(fdt, "#interrupt-cells", 0);
+ if ( res )
+ return res;
+
+ vimsic_phandle = alloc_phandle(kinfo);
+ if ( !vimsic_phandle )
+ return -EOVERFLOW;
+
+ res = fdt_property_cell(fdt, "phandle", vimsic_phandle);
+ if ( res )
+ return res;
+
+ if ( phandle )
+ *phandle = vimsic_phandle;
+
+ return fdt_end_node(fdt);
+}
diff --git a/xen/arch/riscv/include/asm/guest-layout.h b/xen/arch/riscv/include/asm/guest-layout.h
index 68d95a09394c..d757bb9219ff 100644
--- a/xen/arch/riscv/include/asm/guest-layout.h
+++ b/xen/arch/riscv/include/asm/guest-layout.h
@@ -3,6 +3,8 @@
#include <public/xen.h>
+#define GUEST_IMSIC_S_BASE __ULL(0x28000000)
+
#define GUEST_RAM_BANKS 2
/*
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 17/23] xen/riscv: create APLIC DT node for guest domains
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (15 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 16/23] xen/riscv: generate IMSIC DT node for guest domains Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:24 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 18/23] xen/riscv: implement IRQ routing for device passthrough Oleksii Kurochko
` (5 subsequent siblings)
22 siblings, 1 reply; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Guests require a Device Tree description of the interrupt controller
topology. Add support for creating an APLIC node when building the
guest DT.
Provide stub for imsic_make_dt_node() it will be introduced properly
in follow-up patch.
The value chosen for GUEST_APLIC_S_BASE is based on QEMU one.
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 <Romain.Caritey@microchip.com>
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Fix rebase conflicts becuase of this patch is reordered after IMSIC DT
node creation is intoduced.
- Update the commit message.
- Move initialization of domaincfg with APLIC_DOMAINCFG_RO80 from this
patch to earlier.
- Change paddr_t aplic_size to unsigned int in vaplic_make_domu_dt_node()
and replace the UB (after it started to be uint) aplic_size >> 32 with
an explicit 0 in the DT reg property.
- Add BUILD_BUG_ON() to be sure that aplic size isn't bigger then
UINT32_MAX.
---
Changes in v2:
- Avoid as max as possible of host properties inheritance. Only number of
APLIC's irqs are checked what leads to an introduction of
get_aplic_irqs_num().
- Move this patch earlier what leads to an introduction of
vimsic_make_domu_dt_node() stub.
- s/vimsic_make_domu_dt_node/imsic_make_domu_dt_node.
- Refactor vimsic_make_domu_dt_node() to avoid re-usage of APLIC host
properties.
- Drop next_phandle as it is now in common code.
- Drop const for kinfo argument of vimsic_make_domu_dt_node() is is
going to be updated inside vimsic_make_domu_dt_node().
- Use introduced before vintc->num_irqs.
---
---
xen/arch/riscv/aplic.c | 2 +
xen/arch/riscv/include/asm/aplic.h | 8 +++
xen/arch/riscv/include/asm/guest-layout.h | 2 +
xen/arch/riscv/include/asm/imsic.h | 3 +
xen/arch/riscv/vaplic.c | 76 +++++++++++++++++++++++
5 files changed, 91 insertions(+)
diff --git a/xen/arch/riscv/aplic.c b/xen/arch/riscv/aplic.c
index 620768fb6164..0abe32c2e446 100644
--- a/xen/arch/riscv/aplic.c
+++ b/xen/arch/riscv/aplic.c
@@ -12,8 +12,10 @@
#include <xen/const.h>
#include <xen/device_tree.h>
#include <xen/errno.h>
+#include <xen/fdt-kernel.h>
#include <xen/init.h>
#include <xen/irq.h>
+#include <xen/libfdt/libfdt.h>
#include <xen/mm.h>
#include <xen/sections.h>
#include <xen/spinlock.h>
diff --git a/xen/arch/riscv/include/asm/aplic.h b/xen/arch/riscv/include/asm/aplic.h
index d443faac57c4..b42b159496b8 100644
--- a/xen/arch/riscv/include/asm/aplic.h
+++ b/xen/arch/riscv/include/asm/aplic.h
@@ -28,6 +28,14 @@
#define APLIC_TARGET_HART_IDX_SHIFT 18
+#define APLIC_IDC_SIZE 32
+
+#define APLIC_MIN_SIZE 0x4000
+#define APLIC_SIZE_ALIGN(x) ROUNDUP(x, APLIC_MIN_SIZE)
+
+#define APLIC_SIZE(nr_cpus) (APLIC_MIN_SIZE + \
+ APLIC_SIZE_ALIGN(APLIC_IDC_SIZE * (nr_cpus)))
+
struct aplic_regs {
uint32_t domaincfg; /* 0x0000 */
uint32_t sourcecfg[1023]; /* 0x0004 */
diff --git a/xen/arch/riscv/include/asm/guest-layout.h b/xen/arch/riscv/include/asm/guest-layout.h
index d757bb9219ff..2e5762af863f 100644
--- a/xen/arch/riscv/include/asm/guest-layout.h
+++ b/xen/arch/riscv/include/asm/guest-layout.h
@@ -3,6 +3,8 @@
#include <public/xen.h>
+#define GUEST_APLIC_S_BASE __ULL(0xd000000)
+
#define GUEST_IMSIC_S_BASE __ULL(0x28000000)
#define GUEST_RAM_BANKS 2
diff --git a/xen/arch/riscv/include/asm/imsic.h b/xen/arch/riscv/include/asm/imsic.h
index 316fe5423c48..9c7fe0d469d1 100644
--- a/xen/arch/riscv/include/asm/imsic.h
+++ b/xen/arch/riscv/include/asm/imsic.h
@@ -78,6 +78,7 @@ struct vimsic_state {
};
struct dt_device_node;
+struct kernel_info;
struct vcpu;
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);
+int vimsic_make_domu_dt_node(struct kernel_info *kinfo, unsigned int *phandle);
+
#endif /* ASM_RISCV_IMSIC_H */
diff --git a/xen/arch/riscv/vaplic.c b/xen/arch/riscv/vaplic.c
index 8170e93701ad..683e8aaec2f3 100644
--- a/xen/arch/riscv/vaplic.c
+++ b/xen/arch/riscv/vaplic.c
@@ -9,6 +9,8 @@
*/
#include <xen/errno.h>
+#include <xen/fdt-kernel.h>
+#include <xen/libfdt/libfdt.h>
#include <xen/sched.h>
#include <xen/xvmalloc.h>
@@ -19,6 +21,11 @@
#include "aplic-priv.h"
+#define VAPLIC_COMPATIBLE "riscv,aplic"
+#define VAPLIC_NUM_SOURCES 96
+
+#define FDT_VAPLIC_INT_CELLS 2
+
static int cf_check vaplic_init(struct vcpu *v)
{
return vcpu_imsic_init(v);
@@ -29,6 +36,74 @@ static void cf_check vaplic_deinit(struct vcpu *v)
return vcpu_imsic_deinit(v);
}
+static int __init cf_check vaplic_make_domu_dt_node(struct kernel_info *kinfo)
+{
+ struct domain *d = kinfo->bd.d;
+ int res = 0;
+ void *fdt = kinfo->fdt;
+ unsigned int msi_parent_phandle;
+ char vaplic_name[128];
+ unsigned int aplic_size = APLIC_SIZE(d->max_vcpus);
+ const __be32 reg[] = {
+ cpu_to_be32(GUEST_APLIC_S_BASE >> 32),
+ cpu_to_be32(GUEST_APLIC_S_BASE),
+ cpu_to_be32(0),
+ cpu_to_be32(aplic_size),
+ };
+
+ BUILD_BUG_ON(APLIC_SIZE(MAX_VIRT_CPUS) > UINT_MAX);
+
+ res = snprintf(vaplic_name, sizeof(vaplic_name), "/soc/aplic@%lx",
+ GUEST_APLIC_S_BASE);
+ if ( res >= sizeof(vaplic_name) )
+ {
+ dprintk(XENLOG_DEBUG, "vaplic name is truncated\n");
+ return -ENOBUFS;
+ }
+
+ res = vimsic_make_domu_dt_node(kinfo, &msi_parent_phandle);
+ if ( res )
+ return res;
+
+ res = fdt_begin_node(fdt, vaplic_name);
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "#interrupt-cells", FDT_VAPLIC_INT_CELLS);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "reg", reg, sizeof(reg));
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "riscv,num-sources", VAPLIC_NUM_SOURCES);
+ if ( res )
+ return res;
+
+ res = fdt_property(fdt, "interrupt-controller", NULL, 0);
+ if ( res )
+ return res;
+
+ res = fdt_property_string(fdt, "compatible", VAPLIC_COMPATIBLE);
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "msi-parent", msi_parent_phandle);
+ if ( res )
+ return res;
+
+ res = fdt_property_cell(fdt, "phandle", kinfo->phandle_intc);
+ if ( res )
+ return res;
+
+ return fdt_end_node(fdt);
+}
+
+static const struct vintc_init_ops __initdata init_ops = {
+ .make_domu_dt_node = vaplic_make_domu_dt_node,
+};
+
static const struct vintc_ops vintc_ops = {
.vcpu_init = vaplic_init,
.vcpu_deinit = vaplic_deinit,
@@ -43,6 +118,7 @@ int domain_vaplic_init(struct domain *d)
d->arch.vintc = &vaplic->vintc;
d->arch.vintc->ops = &vintc_ops;
+ d->arch.vintc->init_ops = &init_ops;
vaplic->regs.domaincfg = APLIC_DOMAINCFG_IE | APLIC_DOMAINCFG_DM |
APLIC_DOMAINCFG_RO80;
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 18/23] xen/riscv: implement IRQ routing for device passthrough
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (16 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 17/23] xen/riscv: create APLIC " Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 19/23] xen/riscv: implement init_intc_phandle() Oleksii Kurochko
` (4 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
dom0less device passthrough requires granting guest domains access to
device interrupts. Introduce map_device_irqs_to_domain() to enumerate
a DT node's interrupt properties, skipping those not owned by
the primary interrupt controller (as at the moment I haven't seen usages
of it), and map_irq_to_domain() to grant domain access and configure
Xen's interrupt descriptor accordingly. Sharing IRQ between domains is
rejected.
route_irq_to_guest() and release_irq() manage irq_desc ownership for
guest-assigned interrupts. Each assignment carries a small irq_guest
structure as irqaction::dev_id, recording the owning domain and virtual
IRQ number which is 1:1 mapped to physical IRQ number. A per-domain
vIRQ allocation bitmap (allocated_irqs in struct vintc), managed by
vintc_reserve_virq(), prevents the same vIRQ being claimed twice.
With APLIC+IMSIC, guest interrupts are delivered directly by hardware
through the IMSIC, bypassing do_IRQ(). The _IRQ_GUEST branch in
do_IRQ() is therefore left as BUG() until a platform without direct
IMSIC delivery is encountered.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Drop extraneous "to" from "Unable to permit to %pd" message.
- Move res/irq/rirq to loop scope; use nirq as declaration initializer.
- Hoist irq_ranges check before the loop (it is loop-invariant).
- Remove spurious forward declarations (struct dt_device_node, struct
rangeset) from intc.h; remove all three from setup.h.
- Use __set_bit() instead of set_bit() in intc_route_irq_to_guest()
since desc->lock is always held on every write path for desc->status.
- Use XVFREE() instead of xvfree() in domain_vintc_deinit().
- Rename allocated_irqs -> used_irqs in struct vintc.
- Fix dangling desc->action in release_irq()'s !IRQ_HAS_MULTIPLE_ACTION
path by nulling *action_ptr after saving the action pointer.
- Use true (not 1) for free_on_release in route_irq_to_guest().
- Use %pd for domain printing in route_irq_to_guest() error paths.
- Introduce release_guest_irq() to pair with route_irq_to_guest() and
plug the irq_guest info leak; call it from domain_vintc_deinit()
for each vIRQ recorded in used_irqs.
---
Changes in v2:
- Rework IRQ mapping in more common (similar approach to Arm).
---
---
xen/arch/riscv/Makefile | 1 +
xen/arch/riscv/aplic.c | 4 +
xen/arch/riscv/device.c | 102 +++++++++++++++
xen/arch/riscv/imsic.c | 5 +-
xen/arch/riscv/include/asm/intc.h | 9 ++
xen/arch/riscv/include/asm/irq.h | 5 +
xen/arch/riscv/intc.c | 41 ++++++
xen/arch/riscv/irq.c | 203 ++++++++++++++++++++++++++++++
xen/arch/riscv/vaplic.c | 2 +
9 files changed, 370 insertions(+), 2 deletions(-)
create mode 100644 xen/arch/riscv/device.c
diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile
index 9d8d21b65188..fc6b34661111 100644
--- a/xen/arch/riscv/Makefile
+++ b/xen/arch/riscv/Makefile
@@ -1,6 +1,7 @@
obj-y += aia.o
obj-y += aplic.o
obj-y += cpufeature.o
+obj-y += device.o
obj-y += domain.o
obj-y += domain-build.init.o
obj-$(CONFIG_DOM0LESS_BOOT) += dom0less-build.init.o
diff --git a/xen/arch/riscv/aplic.c b/xen/arch/riscv/aplic.c
index 0abe32c2e446..a559c81c6d16 100644
--- a/xen/arch/riscv/aplic.c
+++ b/xen/arch/riscv/aplic.c
@@ -306,9 +306,13 @@ static const hw_irq_controller aplic_xen_irq_type = {
.set_affinity = aplic_set_irq_affinity,
};
+/* At the moment there is no difference between guest and Xen ops */
+#define aplic_guest_irq_type aplic_xen_irq_type
+
static const struct intc_hw_operations aplic_ops = {
.info = &aplic_info,
.host_irq_type = &aplic_xen_irq_type,
+ .guest_irq_type = &aplic_guest_irq_type,
.handle_interrupt = aplic_handle_interrupt,
.set_irq_type = aplic_set_irq_type,
};
diff --git a/xen/arch/riscv/device.c b/xen/arch/riscv/device.c
new file mode 100644
index 000000000000..95bd3b46f538
--- /dev/null
+++ b/xen/arch/riscv/device.c
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <xen/device_tree.h>
+#include <xen/errno.h>
+#include <xen/iocap.h>
+#include <xen/rangeset.h>
+#include <xen/sched.h>
+
+#include <asm/intc.h>
+
+int map_irq_to_domain(struct domain *d, unsigned int irq,
+ bool need_mapping, const char *devname)
+{
+ int res;
+
+ res = irq_permit_access(d, irq);
+ if ( res )
+ {
+ printk(XENLOG_ERR "Unable to permit %pd access to IRQ %u\n", d, irq);
+ return res;
+ }
+
+ if ( need_mapping )
+ {
+ /*
+ * Checking the return of vintc_reserve_virq is not
+ * necessary. It should not fail except when we try to map
+ * the IRQ twice. This can legitimately happen if the IRQ is shared.
+ */
+ vintc_reserve_virq(d, irq);
+
+ res = route_irq_to_guest(d, irq, irq, devname);
+ if ( res < 0 )
+ {
+ printk(XENLOG_ERR "Unable to map IRQ%u to %pd\n", irq, d);
+ return res;
+ }
+ }
+
+ dt_dprintk(" - IRQ: %u\n", irq);
+
+ return 0;
+}
+
+/*
+ * map_device_irqs_to_domain retrieves the interrupts configuration from
+ * a device tree node and maps those interrupts to the target domain.
+ *
+ * Returns:
+ * < 0 error
+ * 0 success
+ */
+int map_device_irqs_to_domain(struct domain *d,
+ struct dt_device_node *dev,
+ bool need_mapping,
+ struct rangeset *irq_ranges)
+{
+ unsigned int i, nirq = dt_number_of_irq(dev);
+
+ if ( irq_ranges )
+ return -EOPNOTSUPP;
+
+ /* Give permission and map IRQs */
+ for ( i = 0; i < nirq; i++ )
+ {
+ int res, irq;
+ struct dt_raw_irq rirq;
+
+ res = dt_device_get_raw_irq(dev, i, &rirq);
+ if ( res )
+ {
+ printk(XENLOG_ERR "Unable to retrieve irq %u for %s\n",
+ i, dt_node_full_name(dev));
+ return res;
+ }
+
+ /*
+ * Don't map IRQ that have no physical meaning
+ * ie: IRQ whose controller is not APLIC/IMSIC/PLIC.
+ */
+ if ( rirq.controller != dt_interrupt_controller )
+ {
+ dt_dprintk("irq %u not connected to primary controller."
+ "Connected to %s\n", i,
+ dt_node_full_name(rirq.controller));
+ continue;
+ }
+
+ irq = platform_get_irq(dev, i);
+ if ( irq < 0 )
+ {
+ printk("Unable to get irq %u for %s\n", i, dt_node_full_name(dev));
+ return irq;
+ }
+
+ res = map_irq_to_domain(d, irq, need_mapping, dt_node_name(dev));
+ if ( res )
+ return res;
+ }
+
+ return 0;
+}
diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c
index de8c54cb33fd..bd565aa6af08 100644
--- a/xen/arch/riscv/imsic.c
+++ b/xen/arch/riscv/imsic.c
@@ -538,10 +538,11 @@ int __init imsic_init(const struct dt_device_node *node)
static int __init guest_imsic_make_reg_property(struct domain *d, void *fdt)
{
+ paddr_t base = GUEST_IMSIC_S_BASE;
paddr_t size = IMSIC_MMIO_PAGE_SZ * d->max_vcpus;
__be32 regs[4] = {
- cpu_to_be32(GUEST_IMSIC_S_BASE >> 32),
- cpu_to_be32(GUEST_IMSIC_S_BASE),
+ cpu_to_be32(base >> 32),
+ cpu_to_be32(base),
cpu_to_be32(size >> 32),
cpu_to_be32(size),
};
diff --git a/xen/arch/riscv/include/asm/intc.h b/xen/arch/riscv/include/asm/intc.h
index 95ca526e1223..f257e6a47b2b 100644
--- a/xen/arch/riscv/include/asm/intc.h
+++ b/xen/arch/riscv/include/asm/intc.h
@@ -13,6 +13,7 @@ enum intc_version {
};
struct cpu_user_regs;
+struct domain;
struct irq_desc;
struct kernel_info;
struct vcpu;
@@ -32,6 +33,9 @@ struct intc_hw_operations {
/* hw_irq_controller to enable/disable/eoi host irq */
const struct hw_interrupt_type *host_irq_type;
+ /* hw_irq_controller to enable/disable/eoi guest irq */
+ const struct hw_interrupt_type *guest_irq_type;
+
/* Set IRQ type */
void (*set_irq_type)(struct irq_desc *desc, unsigned int type);
/* Set IRQ priority */
@@ -62,6 +66,8 @@ struct vintc_ops {
};
struct vintc {
+ unsigned int irq_nums;
+ unsigned long *used_irqs;
const struct vintc_init_ops *init_ops;
const struct vintc_ops *ops;
};
@@ -73,6 +79,7 @@ void register_intc_ops(const struct intc_hw_init_ops *init_ops);
void intc_init(void);
void intc_route_irq_to_xen(struct irq_desc *desc, unsigned int priority);
+int intc_route_irq_to_guest(struct irq_desc *desc, unsigned int priority);
void intc_handle_external_irqs(struct cpu_user_regs *regs);
@@ -80,4 +87,6 @@ void intc_handle_external_irqs(struct cpu_user_regs *regs);
int domain_vintc_init(struct domain *d);
void domain_vintc_deinit(struct domain *d);
+bool vintc_reserve_virq(const struct domain *d, unsigned int virq);
+
#endif /* ASM__RISCV__INTERRUPT_CONTOLLER_H */
diff --git a/xen/arch/riscv/include/asm/irq.h b/xen/arch/riscv/include/asm/irq.h
index f633636dc308..2b95f8226be2 100644
--- a/xen/arch/riscv/include/asm/irq.h
+++ b/xen/arch/riscv/include/asm/irq.h
@@ -49,6 +49,11 @@ void init_IRQ(void);
void do_IRQ(struct cpu_user_regs *regs, unsigned int irq);
+int route_irq_to_guest(struct domain *d, unsigned int virq,
+ unsigned int irq, const char *devname);
+
+int release_guest_irq(struct domain *d, unsigned int virq);
+
#endif /* ASM__RISCV__IRQ_H */
/*
diff --git a/xen/arch/riscv/intc.c b/xen/arch/riscv/intc.c
index ec37b359f323..a38740778d23 100644
--- a/xen/arch/riscv/intc.c
+++ b/xen/arch/riscv/intc.c
@@ -7,7 +7,9 @@
#include <xen/init.h>
#include <xen/irq.h>
#include <xen/lib.h>
+#include <xen/sched.h>
#include <xen/spinlock.h>
+#include <xen/xvmalloc.h>
#include <asm/aia.h>
#include <asm/intc.h>
@@ -78,6 +80,22 @@ void intc_route_irq_to_xen(struct irq_desc *desc, unsigned int priority)
intc_set_irq_priority(desc, priority);
}
+int intc_route_irq_to_guest(struct irq_desc *desc,
+ unsigned int priority)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+
+ ASSERT(intc_hw_ops->guest_irq_type);
+
+ desc->handler = intc_hw_ops->guest_irq_type;
+ __set_bit(_IRQ_GUEST, &desc->status);
+
+ intc_set_irq_type(desc, desc->arch.type);
+ intc_set_irq_priority(desc, priority);
+
+ return 0;
+}
+
int __init make_intc_domU_node(struct kernel_info *kinfo)
{
struct vintc *vintc = kinfo->bd.d->arch.vintc;
@@ -106,12 +124,25 @@ int domain_vintc_init(struct domain *d)
break;
}
+ if ( !ret )
+ {
+ d->arch.vintc->used_irqs =
+ xvzalloc_array(unsigned long, BITS_TO_LONGS(d->arch.vintc->irq_nums));
+ if ( !d->arch.vintc->used_irqs )
+ ret = -ENOMEM;
+ }
+
return ret;
}
void domain_vintc_deinit(struct domain *d)
{
const enum intc_version ver = intc_hw_ops->info->hw_version;
+ unsigned int virq;
+
+ for ( virq = 0; virq < d->arch.vintc->irq_nums; virq++ )
+ if ( test_bit(virq, d->arch.vintc->used_irqs) )
+ release_guest_irq(d, virq);
switch ( ver )
{
@@ -122,4 +153,14 @@ void domain_vintc_deinit(struct domain *d)
default:
break;
}
+
+ XVFREE(d->arch.vintc->used_irqs);
+}
+
+bool vintc_reserve_virq(const struct domain *d, unsigned int virq)
+{
+ if ( virq >= d->arch.vintc->irq_nums )
+ return false;
+
+ return !test_and_set_bit(virq, d->arch.vintc->used_irqs);
}
diff --git a/xen/arch/riscv/irq.c b/xen/arch/riscv/irq.c
index 25d329500212..3b90ab013e74 100644
--- a/xen/arch/riscv/irq.c
+++ b/xen/arch/riscv/irq.c
@@ -12,11 +12,20 @@
#include <xen/errno.h>
#include <xen/init.h>
#include <xen/irq.h>
+#include <xen/sched.h>
#include <xen/spinlock.h>
+#include <xen/xvmalloc.h>
#include <asm/hardirq.h>
#include <asm/intc.h>
+/* Describe an IRQ assigned to a guest */
+struct irq_guest
+{
+ struct domain *d;
+ unsigned int virq;
+};
+
static irq_desc_t irq_desc[NR_IRQS];
static bool irq_validate_new_type(unsigned int curr, unsigned int new)
@@ -192,6 +201,15 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq)
if ( desc->handler->ack )
desc->handler->ack(desc);
+ if ( desc->status & IRQ_GUEST )
+ /*
+ * As at the moment APLIC + IMSIC is used for guest interrupts will
+ * be directly passed to guest. But if/when IMSIC won't be available
+ * all interrupts will go through Xenand here an irq injection
+ * will be necessary to do.
+ */
+ panic("unimplemented");
+
if ( desc->status & IRQ_DISABLED )
goto out;
@@ -221,3 +239,188 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq)
spin_unlock(&desc->lock);
irq_exit();
}
+
+static inline struct irq_guest *irq_get_guest_info(struct irq_desc *desc)
+{
+ ASSERT(spin_is_locked(&desc->lock));
+ ASSERT(test_bit(_IRQ_GUEST, &desc->status));
+ ASSERT(desc->action != NULL);
+
+ return desc->action->dev_id;
+}
+
+static inline struct domain *irq_get_domain(struct irq_desc *desc)
+{
+ return irq_get_guest_info(desc)->d;
+}
+
+void release_irq(unsigned int irq, const void *dev_id)
+{
+ struct irq_desc *desc;
+ unsigned long flags;
+ struct irqaction *action, **action_ptr;
+
+ desc = irq_to_desc(irq);
+
+ spin_lock_irqsave(&desc->lock,flags);
+
+ action_ptr = &desc->action;
+#ifdef CONFIG_IRQ_HAS_MULTIPLE_ACTION
+ for ( ;; )
+ {
+ action = *action_ptr;
+ if ( !action )
+ {
+ printk(XENLOG_WARNING "Trying to free already-free IRQ %u\n", irq);
+ spin_unlock_irqrestore(&desc->lock, flags);
+ return;
+ }
+
+ if ( action->dev_id == dev_id )
+ break;
+
+ action_ptr = &action->next;
+ }
+
+ /* Found it - remove it from the action list */
+ *action_ptr = action->next;
+#else
+ action = *action_ptr;
+ *action_ptr = NULL;
+#endif
+
+ /* If this was the last action, shut down the IRQ */
+ if ( !desc->action )
+ {
+ desc->handler->shutdown(desc);
+ __clear_bit(_IRQ_GUEST, &desc->status);
+ }
+
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ /* Wait to make sure it's not being used on another CPU */
+ do { smp_mb(); } while ( test_bit(_IRQ_INPROGRESS, &desc->status) );
+
+ if ( action->free_on_release )
+ xvfree(action);
+}
+
+int release_guest_irq(struct domain *d, unsigned int virq)
+{
+ struct irq_desc *desc = irq_to_desc(virq);
+ struct irq_guest *info;
+ unsigned long flags;
+
+ spin_lock_irqsave(&desc->lock, flags);
+
+ if ( !test_bit(_IRQ_GUEST, &desc->status) )
+ goto unlock_err;
+
+ info = irq_get_guest_info(desc);
+ if ( d != info->d )
+ goto unlock_err;
+
+ spin_unlock_irqrestore(&desc->lock, flags);
+
+ release_irq(desc->irq, info);
+ xvfree(info);
+
+ return 0;
+
+ unlock_err:
+ spin_unlock_irqrestore(&desc->lock, flags);
+ return -EINVAL;
+}
+
+/* Route an IRQ to a specific guest */
+int route_irq_to_guest(struct domain *d, unsigned int virq,
+ unsigned int irq, const char *devname)
+{
+ struct irqaction *action;
+ struct irq_guest *info;
+ struct irq_desc *desc;
+ unsigned long flags;
+ int retval = 0;
+
+ desc = irq_to_desc(irq);
+
+ action = xvmalloc(struct irqaction);
+ if ( !action )
+ return -ENOMEM;
+
+ info = xvmalloc(struct irq_guest);
+ if ( !info )
+ {
+ xvfree(action);
+ return -ENOMEM;
+ }
+
+ info->d = d;
+ info->virq = virq;
+
+ action->dev_id = info;
+ action->name = devname;
+ action->free_on_release = true;
+
+ spin_lock_irqsave(&desc->lock, flags);
+
+ /*
+ * If the IRQ is already used by someone
+ * - If it's the same domain -> Xen doesn't need to update the IRQ desc.
+ * For safety check if we are not trying to assign the IRQ to a
+ * different vIRQ.
+ * - Otherwise -> For now, don't allow the IRQ to be shared between
+ * Xen and domains.
+ */
+ if ( desc->action != NULL )
+ {
+ if ( test_bit(_IRQ_GUEST, &desc->status) )
+ {
+ struct domain *ad = irq_get_domain(desc);
+
+ if ( d != ad )
+ {
+ printk(XENLOG_G_ERR "IRQ %u is already used by %pd\n",
+ irq, ad);
+ retval = -EBUSY;
+ }
+ else if ( irq_get_guest_info(desc)->virq != virq )
+ {
+ printk(XENLOG_G_ERR
+ "%pd: IRQ %u is already assigned to vIRQ %u\n",
+ d, irq, irq_get_guest_info(desc)->virq);
+ retval = -EBUSY;
+ }
+ }
+ else
+ {
+ printk(XENLOG_G_ERR "IRQ %u is already used by Xen\n", irq);
+ retval = -EBUSY;
+ }
+ goto out;
+ }
+
+ retval = _setup_irq(desc, 0, action);
+ if ( retval )
+ goto out;
+
+ retval = intc_route_irq_to_guest(desc, IRQ_NO_PRIORITY);
+
+ spin_unlock_irqrestore(&desc->lock, flags);
+
+ if ( retval )
+ {
+ release_irq(desc->irq, info);
+ goto free_info;
+ }
+
+ return 0;
+
+ out:
+ spin_unlock_irqrestore(&desc->lock, flags);
+ xvfree(action);
+ free_info:
+ xvfree(info);
+
+ return retval;
+}
diff --git a/xen/arch/riscv/vaplic.c b/xen/arch/riscv/vaplic.c
index 683e8aaec2f3..b418cbedd9b3 100644
--- a/xen/arch/riscv/vaplic.c
+++ b/xen/arch/riscv/vaplic.c
@@ -123,6 +123,8 @@ int domain_vaplic_init(struct domain *d)
vaplic->regs.domaincfg = APLIC_DOMAINCFG_IE | APLIC_DOMAINCFG_DM |
APLIC_DOMAINCFG_RO80;
+ d->arch.vintc->irq_nums = VAPLIC_NUM_SOURCES;
+
return 0;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 19/23] xen/riscv: implement init_intc_phandle()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (17 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 18/23] xen/riscv: implement IRQ routing for device passthrough Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 20/23] xen/riscv: initialize RCU, scheduler, and system domains in start_xen() Oleksii Kurochko
` (3 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Implement init_intc_phandle() to read phandle of interrupt controller
node and save it in kernel->phandle_intc for the future usage during
creation of guest interrupt controller node.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
xen/arch/riscv/dom0less-build.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/xen/arch/riscv/dom0less-build.c b/xen/arch/riscv/dom0less-build.c
index 4cc00012aa8d..a1fa51b996a7 100644
--- a/xen/arch/riscv/dom0less-build.c
+++ b/xen/arch/riscv/dom0less-build.c
@@ -4,9 +4,26 @@
#include <xen/device_tree.h>
#include <xen/fdt-kernel.h>
#include <xen/init.h>
+#include <xen/libfdt/libfdt.h>
#include <asm/p2m.h>
+int __init init_intc_phandle(struct kernel_info *kinfo, const char *name,
+ const int node_next, const void *pfdt)
+{
+ if ( dt_node_cmp(name, "intc") == 0 )
+ {
+ uint32_t phandle_intc = fdt_get_phandle(pfdt, node_next);
+
+ if ( phandle_intc != 0 )
+ kinfo->phandle_intc = phandle_intc;
+
+ return 0;
+ }
+
+ return 1;
+}
+
int __init make_arch_nodes(struct kernel_info *kinfo)
{
/* No RISC-V specific nodes need to be made, at the moment. */
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 20/23] xen/riscv: initialize RCU, scheduler, and system domains in start_xen()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (18 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 19/23] xen/riscv: implement init_intc_phandle() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 21/23] xen/riscv: provide init_vuart() Oleksii Kurochko
` (2 subsequent siblings)
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Wire up the missing early-boot initialization steps in start_xen().
The scheduler must be initialized prior to do_initcalls() because
cpupool_create_pool() is called during initcalls; without it,
BUG_ON(IS_ERR(pool)) is triggered inside cpupool_create_pool().
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
Changes in v3:
- Add Acked-by: Jan Beulich <jbeulich@suse.com>.
---
Changes in v2:
- New patch. Several patches were folded into one.
---
---
xen/arch/riscv/setup.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c
index 56a0907a855f..c3e98733ebc3 100644
--- a/xen/arch/riscv/setup.c
+++ b/xen/arch/riscv/setup.c
@@ -6,9 +6,12 @@
#include <xen/compile.h>
#include <xen/console.h>
#include <xen/device_tree.h>
+#include <xen/domain.h>
#include <xen/init.h>
#include <xen/irq.h>
#include <xen/mm.h>
+#include <xen/rcupdate.h>
+#include <xen/sched.h>
#include <xen/serial.h>
#include <xen/shutdown.h>
#include <xen/smp.h>
@@ -156,12 +159,21 @@ void __init noreturn start_xen(unsigned long bootcpu_id,
timer_init();
+ rcu_init();
+
+ setup_system_domains();
+
local_irq_enable();
console_init_postirq();
guest_mm_init();
+ scheduler_init();
+ set_current(idle_vcpu[0]);
+
+ do_initcalls();
+
printk("All set up\n");
machine_halt();
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 21/23] xen/riscv: provide init_vuart()
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (19 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 20/23] xen/riscv: initialize RCU, scheduler, and system domains in start_xen() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 22/23] xen/Kconfig: introduce HAS_STATIC_MEMORY Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 23/23] xen/riscv: add initial dom0less infrastructure support Oleksii Kurochko
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
For debug purpose is enough to have only print messages from guest what is
now implemented in vsbi_legacy_ecall_handler().
For full guesst console support it will better to have something similar to
[1], thereby there is nothing specific should be done, at least, for now
and init_vuart() is provided to make dom0less code buildable.
[1] https://lore.kernel.org/xen-devel/alpine.DEB.2.22.394.2602041533440.3175371@ubuntu-linux-20-04-desktop/
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
Changes in v2:
- Add Acked-by: Jan Beulich <jbeulich@suse.com>.
---
---
xen/arch/riscv/dom0less-build.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/xen/arch/riscv/dom0less-build.c b/xen/arch/riscv/dom0less-build.c
index a1fa51b996a7..d1a51b92936a 100644
--- a/xen/arch/riscv/dom0less-build.c
+++ b/xen/arch/riscv/dom0less-build.c
@@ -8,6 +8,14 @@
#include <asm/p2m.h>
+int __init init_vuart(struct domain *d, struct kernel_info *kinfo,
+ const struct dt_device_node *node)
+{
+ /* Nothing to do at the moment */
+
+ return 0;
+}
+
int __init init_intc_phandle(struct kernel_info *kinfo, const char *name,
const int node_next, const void *pfdt)
{
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 22/23] xen/Kconfig: introduce HAS_STATIC_MEMORY
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (20 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 21/23] xen/riscv: provide init_vuart() Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 23/23] xen/riscv: add initial dom0less infrastructure support Oleksii Kurochko
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Stefano Stabellini,
Julien Grall, Bertrand Marquis, Michal Orzel, Volodymyr Babchuk,
Andrew Cooper, Anthony PERARD, Jan Beulich, Roger Pau Monné
Architectures that implement guest_physmap_add_pages() select
HAS_STATIC_MEMORY; STATIC_MEMORY then depends on it. ARM selects the
new flag; RISC-V does not, so CONFIG_STATIC_MEMORY is unavailable there
and randconfig builds no longer require an explicit STATIC_MEMORY=n
override to avoid a compilation error.
Suggested-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- New patch.
---
---
xen/arch/arm/Kconfig | 1 +
xen/common/Kconfig | 5 ++++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 683ab7d25a1e..d748404e82da 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -22,6 +22,7 @@ config ARM
select HAS_GRANT_CACHE_FLUSH if GRANT_TABLE
select HAS_SHARED_INFO
select HAS_STACK_PROTECTOR
+ select HAS_STATIC_MEMORY
select HAS_UBSAN
config ARCH_DEFCONFIG
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 8b48d84c79e8..6e24f7f4e43b 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -161,6 +161,9 @@ config HAS_SCHED_GRANULARITY
config HAS_SHARED_INFO
bool
+config HAS_STATIC_MEMORY
+ bool
+
config HAS_SOFT_RESET
bool
@@ -196,7 +199,7 @@ config NUMA
config STATIC_MEMORY
bool "Static Allocation Support (UNSUPPORTED)" if UNSUPPORTED
- depends on DOM0LESS_BOOT && HAS_DEVICE_TREE_DISCOVERY
+ depends on HAS_STATIC_MEMORY && DOM0LESS_BOOT && HAS_DEVICE_TREE_DISCOVERY
help
Static Allocation refers to system or sub-system(domains) for
which memory areas are pre-defined by configuration using physical
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 23/23] xen/riscv: add initial dom0less infrastructure support
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
` (21 preceding siblings ...)
2026-06-17 11:17 ` [PATCH v3 22/23] xen/Kconfig: introduce HAS_STATIC_MEMORY Oleksii Kurochko
@ 2026-06-17 11:17 ` Oleksii Kurochko
22 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:17 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Oleksii Kurochko, Alistair Francis, Connor Davis,
Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
Julien Grall, Roger Pau Monné, Stefano Stabellini
Enable dom0less support for RISC-V by selecting HAS_DOM0LESS and
providing the minimal architecture hooks required by the common
dom0less infrastructure.
Add stub implementations for architecture-specific helpers used when
building domains from the device tree. These currently perform no
additional work but allow the generic dom0less code to build and run
on RISC-V.
Introduce max_init_domid as a runtime variable rather than a constant
so that it can be updated during dom0less domain creation.
Provide missing helpers and definitions required by the domain
construction code, including domain bitness helpers and the
p2m_set_allocation() prototype.
Additionally define the guest magic memory region in the public
RISC-V interface. GUEST_MAGIC_BASE is placed at 0x79000000 to avoid
overlapping with the QEMU RISC-V virt machine address space.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
---
Changes in v3:
- Add /* Nothing specific to do for now */ comment to
arch_handle_passthrough_prop().
- Use _ULL() instead of xen_mk_ullong() for GUEST_MAGIC_BASE and
GUEST_MAGIC_SIZE (xen_mk_ullong() is intended for public headers only).
- Fix GUEST_MAGIC_BASE from 0x39000000 to 0x79000000 to avoid the
QEMU RISC-V virt machine PCIE_ECAM range.
- Drop CONFIG_STATIC_MEMORY=n from the CI randconfig; now redundant
since STATIC_MEMORY depends on HAS_STATIC_MEMORY which RISC-V does
not select.
Changes in v2:
- Move declaration of p2m_set_allocation() to p2m-common.h.
- Add __initdata for max_init_domid and drop initalizer for it.
- Add CONFIG_STATIC_MEMORY=n to CI's randconfig to avoid
compilation error because of guest_physmap_add_pages()
isn't provided.
---
xen/arch/riscv/Kconfig | 2 ++
xen/arch/riscv/dom0less-build.c | 7 +++++++
xen/arch/riscv/domain-build.c | 13 +++++++++++++
xen/arch/riscv/include/asm/guest-layout.h | 3 +++
xen/arch/riscv/include/asm/setup.h | 4 +++-
xen/arch/riscv/setup.c | 2 ++
6 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/xen/arch/riscv/Kconfig b/xen/arch/riscv/Kconfig
index 48520588fe40..d8a348c0cf07 100644
--- a/xen/arch/riscv/Kconfig
+++ b/xen/arch/riscv/Kconfig
@@ -6,6 +6,8 @@ config RISCV
select GENERIC_BUG_FRAME
select GENERIC_UART_INIT
select HAS_DEVICE_TREE_DISCOVERY
+ select HAS_DOM0LESS
+ select HAS_DOMAIN_TYPE
select HAS_EX_TABLE
select HAS_PMAP
select HAS_UBSAN
diff --git a/xen/arch/riscv/dom0less-build.c b/xen/arch/riscv/dom0less-build.c
index d1a51b92936a..0801d7e25059 100644
--- a/xen/arch/riscv/dom0less-build.c
+++ b/xen/arch/riscv/dom0less-build.c
@@ -102,3 +102,10 @@ int __init arch_parse_dom0less_node(struct dt_device_node *node,
return 0;
}
+
+int __init arch_handle_passthrough_prop(struct kernel_info *kinfo,
+ struct dt_device_node *node)
+{
+ /* Nothing specific to do for now */
+ return 0;
+}
diff --git a/xen/arch/riscv/domain-build.c b/xen/arch/riscv/domain-build.c
index 4c21ef37a6e1..df4d90e1410a 100644
--- a/xen/arch/riscv/domain-build.c
+++ b/xen/arch/riscv/domain-build.c
@@ -156,9 +156,22 @@ int __init make_cpus_node(const struct domain *d, struct kernel_info *kinfo)
return fdt_end_node(fdt);
}
+int __init construct_hwdom(struct kernel_info *kinfo,
+ const struct dt_device_node *node)
+{
+ return -EOPNOTSUPP;
+}
+
int __init make_timer_node(const struct kernel_info *kinfo)
{
/* There is no need for timer node for RISC-V. */
return 0;
}
+
+int __init make_hypervisor_node(struct domain *d,
+ const struct kernel_info *kinfo,
+ int addrcells, int sizecells)
+{
+ return -EOPNOTSUPP;
+}
diff --git a/xen/arch/riscv/include/asm/guest-layout.h b/xen/arch/riscv/include/asm/guest-layout.h
index 2e5762af863f..757285392d46 100644
--- a/xen/arch/riscv/include/asm/guest-layout.h
+++ b/xen/arch/riscv/include/asm/guest-layout.h
@@ -24,4 +24,7 @@
#define GUEST_RAM_BANK_BASES { GUEST_RAM0_BASE, GUEST_RAM1_BASE }
#define GUEST_RAM_BANK_SIZES { GUEST_RAM0_SIZE, GUEST_RAM1_SIZE }
+#define GUEST_MAGIC_BASE _ULL(0x79000000)
+#define GUEST_MAGIC_SIZE _ULL(0x01000000)
+
#endif /* ASM_RISCV_GUEST_LAYOUT_H */
diff --git a/xen/arch/riscv/include/asm/setup.h b/xen/arch/riscv/include/asm/setup.h
index 2215894cfbb1..678b65ac1e54 100644
--- a/xen/arch/riscv/include/asm/setup.h
+++ b/xen/arch/riscv/include/asm/setup.h
@@ -5,7 +5,9 @@
#include <xen/types.h>
-#define max_init_domid (0)
+#include <public/xen.h>
+
+extern domid_t max_init_domid;
void setup_mm(void);
diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c
index c3e98733ebc3..b8fa004cbf25 100644
--- a/xen/arch/riscv/setup.c
+++ b/xen/arch/riscv/setup.c
@@ -33,6 +33,8 @@
#include <asm/traps.h>
#include <asm/vsbi.h>
+domid_t __initdata max_init_domid;
+
/* Xen stack for bringing up the first CPU. */
unsigned char __initdata cpu0_boot_stack[STACK_SIZE]
__aligned(STACK_SIZE);
--
2.54.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v3 16/23] xen/riscv: generate IMSIC DT node for guest domains
2026-06-17 11:17 ` [PATCH v3 16/23] xen/riscv: generate IMSIC DT node for guest domains Oleksii Kurochko
@ 2026-06-17 11:24 ` Oleksii Kurochko
0 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:24 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Andrew Cooper, Anthony PERARD, Michal Orzel,
Jan Beulich, Julien Grall, Roger Pau Monné,
Stefano Stabellini, Alistair Francis, Connor Davis
On 6/17/26 1:17 PM, Oleksii Kurochko wrote:
> --- a/xen/arch/riscv/include/asm/guest-layout.h
> +++ b/xen/arch/riscv/include/asm/guest-layout.h
> @@ -3,6 +3,8 @@
>
> #include <public/xen.h>
>
> +#define GUEST_IMSIC_S_BASE __ULL(0x28000000)
It should be here _ULL(...) or even _UL().
Sorry for inconvenience.
~ Oleksii
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 17/23] xen/riscv: create APLIC DT node for guest domains
2026-06-17 11:17 ` [PATCH v3 17/23] xen/riscv: create APLIC " Oleksii Kurochko
@ 2026-06-17 11:24 ` Oleksii Kurochko
0 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:24 UTC (permalink / raw)
To: xen-devel
Cc: Romain Caritey, Alistair Francis, Connor Davis, Andrew Cooper,
Anthony PERARD, Michal Orzel, Jan Beulich, Julien Grall,
Roger Pau Monné, Stefano Stabellini
On 6/17/26 1:17 PM, Oleksii Kurochko wrote:
> --- a/xen/arch/riscv/include/asm/guest-layout.h
> +++ b/xen/arch/riscv/include/asm/guest-layout.h
> @@ -3,6 +3,8 @@
>
> #include <public/xen.h>
>
> +#define GUEST_APLIC_S_BASE __ULL(0xd000000)
> +
It should be here _ULL(...) or even _UL().
Sorry for inconvenience.
~ Oleksii
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 04/23] xen/riscv: Implement construct_domain()
2026-06-17 11:17 ` [PATCH v3 04/23] xen/riscv: Implement construct_domain() Oleksii Kurochko
@ 2026-06-17 11:26 ` Jan Beulich
2026-06-17 11:48 ` Oleksii Kurochko
0 siblings, 1 reply; 30+ messages in thread
From: Jan Beulich @ 2026-06-17 11:26 UTC (permalink / raw)
To: Oleksii Kurochko
Cc: Romain Caritey, Alistair Francis, Connor Davis, Andrew Cooper,
Anthony PERARD, Michal Orzel, Julien Grall, Roger Pau Monné,
Stefano Stabellini, xen-devel
On 17.06.2026 13:17, Oleksii Kurochko wrote:
> Implement construct_domain() function for RISC-V, which performs initial setup
> for the domain's first vCPU, loads the kernel, initrd, and device tree,
> and sets up guest CPU registers for boot.
>
> It also creates additional vCPUs up to max_vcpus and assigns the device tree
> address and boot cpuid in registers.
>
> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
> ---
> Changes in v3:
> - s/%d/%u for printing vCPU index in the failure message.
> - Drop dprintk() for successful vCPU creation.
My
Acked-by: Jan Beulich <jbeulich@suse.com>
was lost, however. One more remark:
> --- /dev/null
> +++ b/xen/arch/riscv/domain-build.c
> @@ -0,0 +1,50 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#include <xen/fdt-domain-build.h>
> +#include <xen/fdt-kernel.h>
> +#include <xen/init.h>
> +#include <xen/sched.h>
> +
> +#include <asm/current.h>
> +#include <asm/guest_access.h>
> +
> +int __init construct_domain(struct domain *d, struct kernel_info *kinfo)
> +{
> + struct vcpu *v = d->vcpu[0];
> + struct cpu_user_regs *regs = vcpu_guest_cpu_user_regs(v);
> +
> + BUG_ON(v->is_initialised);
> +
> + /*
> + * At the moment *_load() don't return value and will just panic()
> + * inside.
> + * TODO: it will be good to change that.
> + */
> + kernel_load(kinfo);
> + initrd_load(kinfo, copy_to_guest_phys);
> + dtb_load(kinfo, copy_to_guest_phys);
> +
> + regs->sepc = kinfo->entry;
> +
> + /* Guest boot cpuid = 0 */
> + regs->a0 = 0;
> + regs->a1 = kinfo->dtb_paddr;
> +
> + for ( unsigned int i = 1; i < d->max_vcpus; i++ )
> + {
> + const struct vcpu *tmp_v = vcpu_create(d, i);
> +
> + if ( !tmp_v )
> + {
> + printk("Failed to allocate %pd v%u\n", d, i);
If you dropped the blank before v%u, the output would match that of %pv
(improving the chances of people actually spotting that the exact same
thing is meant). Once again - can do the adjustment while committing,
provided you agree (and provided earlier patches gain the necessary
acks).
Jan
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 09/23] xen/riscv: implement make_arch_nodes()
2026-06-17 11:17 ` [PATCH v3 09/23] xen/riscv: implement make_arch_nodes() Oleksii Kurochko
@ 2026-06-17 11:30 ` Jan Beulich
2026-06-17 11:49 ` Oleksii Kurochko
0 siblings, 1 reply; 30+ messages in thread
From: Jan Beulich @ 2026-06-17 11:30 UTC (permalink / raw)
To: Oleksii Kurochko
Cc: Romain Caritey, Alistair Francis, Connor Davis, Andrew Cooper,
Anthony PERARD, Michal Orzel, Julien Grall, Roger Pau Monné,
Stefano Stabellini, xen-devel
On 17.06.2026 13:17, Oleksii Kurochko wrote:
> No RISC-V-specific nodes need to be created at the moment,
> so make_arch_nodes() is implemented to simply return 0.
>
> It is placed in dom0less-build.c as make_arch_nodes() is
> only used in the dom0less code path. In the future, it will
> be extended to create an emulated UART node.
>
> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
> ---
> Changes in v3:
> - Add Acked-by: Jan Beulich <jbeulich@suse.com>.
???
Jan
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 04/23] xen/riscv: Implement construct_domain()
2026-06-17 11:26 ` Jan Beulich
@ 2026-06-17 11:48 ` Oleksii Kurochko
0 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:48 UTC (permalink / raw)
To: Jan Beulich
Cc: Romain Caritey, Alistair Francis, Connor Davis, Andrew Cooper,
Anthony PERARD, Michal Orzel, Julien Grall, Roger Pau Monné,
Stefano Stabellini, xen-devel
On 6/17/26 1:26 PM, Jan Beulich wrote:
> On 17.06.2026 13:17, Oleksii Kurochko wrote:
>> Implement construct_domain() function for RISC-V, which performs initial setup
>> for the domain's first vCPU, loads the kernel, initrd, and device tree,
>> and sets up guest CPU registers for boot.
>>
>> It also creates additional vCPUs up to max_vcpus and assigns the device tree
>> address and boot cpuid in registers.
>>
>> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
>> ---
>> Changes in v3:
>> - s/%d/%u for printing vCPU index in the failure message.
>> - Drop dprintk() for successful vCPU creation.
>
> My
>
> Acked-by: Jan Beulich <jbeulich@suse.com>
>
> was lost, however. One more remark:
>
>> --- /dev/null
>> +++ b/xen/arch/riscv/domain-build.c
>> @@ -0,0 +1,50 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +
>> +#include <xen/fdt-domain-build.h>
>> +#include <xen/fdt-kernel.h>
>> +#include <xen/init.h>
>> +#include <xen/sched.h>
>> +
>> +#include <asm/current.h>
>> +#include <asm/guest_access.h>
>> +
>> +int __init construct_domain(struct domain *d, struct kernel_info *kinfo)
>> +{
>> + struct vcpu *v = d->vcpu[0];
>> + struct cpu_user_regs *regs = vcpu_guest_cpu_user_regs(v);
>> +
>> + BUG_ON(v->is_initialised);
>> +
>> + /*
>> + * At the moment *_load() don't return value and will just panic()
>> + * inside.
>> + * TODO: it will be good to change that.
>> + */
>> + kernel_load(kinfo);
>> + initrd_load(kinfo, copy_to_guest_phys);
>> + dtb_load(kinfo, copy_to_guest_phys);
>> +
>> + regs->sepc = kinfo->entry;
>> +
>> + /* Guest boot cpuid = 0 */
>> + regs->a0 = 0;
>> + regs->a1 = kinfo->dtb_paddr;
>> +
>> + for ( unsigned int i = 1; i < d->max_vcpus; i++ )
>> + {
>> + const struct vcpu *tmp_v = vcpu_create(d, i);
>> +
>> + if ( !tmp_v )
>> + {
>> + printk("Failed to allocate %pd v%u\n", d, i);
>
> If you dropped the blank before v%u, the output would match that of %pv
> (improving the chances of people actually spotting that the exact same
> thing is meant). Once again - can do the adjustment while committing,
> provided you agree (and provided earlier patches gain the necessary
> acks).
I will be happy with that.
Thanks.
~ Oleksii
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 09/23] xen/riscv: implement make_arch_nodes()
2026-06-17 11:30 ` Jan Beulich
@ 2026-06-17 11:49 ` Oleksii Kurochko
0 siblings, 0 replies; 30+ messages in thread
From: Oleksii Kurochko @ 2026-06-17 11:49 UTC (permalink / raw)
To: Jan Beulich
Cc: Romain Caritey, Alistair Francis, Connor Davis, Andrew Cooper,
Anthony PERARD, Michal Orzel, Julien Grall, Roger Pau Monné,
Stefano Stabellini, xen-devel
On 6/17/26 1:30 PM, Jan Beulich wrote:
> On 17.06.2026 13:17, Oleksii Kurochko wrote:
>> No RISC-V-specific nodes need to be created at the moment,
>> so make_arch_nodes() is implemented to simply return 0.
>>
>> It is placed in dom0less-build.c as make_arch_nodes() is
>> only used in the dom0less code path. In the future, it will
>> be extended to create an emulated UART node.
>>
>> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
>> ---
>> Changes in v3:
>> - Add Acked-by: Jan Beulich <jbeulich@suse.com>.
>
> ???
>
You gave your Acked-by in v2 of this patch but I missed to add it.
I am really sorry.
~ Oleksii
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2026-06-17 11:50 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-17 11:17 [PATCH v3 00/23] Introduce enablemenant of dom0less Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 01/23] xen: arm: move declaration of map_device_irqs_to_domain() to common header Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 02/23] xen: arm: update p2m_set_allocation() prototype Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 03/23] xen/riscv: Implement ARCH_PAGING_MEMPOOL Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 04/23] xen/riscv: Implement construct_domain() Oleksii Kurochko
2026-06-17 11:26 ` Jan Beulich
2026-06-17 11:48 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 05/23] xen/riscv: implement prerequisites for domain_create() Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 06/23] xen/riscv: introduce guest riscv,isa string Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 07/23] xen/riscv: implement make_cpus_node() Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 08/23] xen/riscv: implement make_timer_node() Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 09/23] xen/riscv: implement make_arch_nodes() Oleksii Kurochko
2026-06-17 11:30 ` Jan Beulich
2026-06-17 11:49 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 10/23] xen/riscv: introduce init interrupt controller operations Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 11/23] xen/riscv: implement make_intc_domU_node() Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 12/23] xen/riscv: introduce aia_init() and aia_usable() Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 13/23] xen/riscv: introduce per-vCPU IMSIC state Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 14/23] xen/riscv: add very early virtual APLIC (vAPLIC) initialization support Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 15/23] xen/riscv: introduce (de)initialization helpers for vINTC Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 16/23] xen/riscv: generate IMSIC DT node for guest domains Oleksii Kurochko
2026-06-17 11:24 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 17/23] xen/riscv: create APLIC " Oleksii Kurochko
2026-06-17 11:24 ` Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 18/23] xen/riscv: implement IRQ routing for device passthrough Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 19/23] xen/riscv: implement init_intc_phandle() Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 20/23] xen/riscv: initialize RCU, scheduler, and system domains in start_xen() Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 21/23] xen/riscv: provide init_vuart() Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 22/23] xen/Kconfig: introduce HAS_STATIC_MEMORY Oleksii Kurochko
2026-06-17 11:17 ` [PATCH v3 23/23] xen/riscv: add initial dom0less infrastructure support Oleksii Kurochko
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.