xen/riscv: create APLIC DT node for guest domains

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>
Acked-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Oleksii Kurochko authored and Jan Beulich committed 2026-09-21 10:09:06 +02:00
1 parent 3559e12585
commit 3ecc6da8d6
5 files changed
+106

No files matched your search

+13
View File
@@ -34,4 +34,17 @@ struct aplic_priv {
const struct imsic_config *imsic_cfg;
};
/*
* Value is inspired by what QEMU is using for riscv,num-sources property for
* APLIC node.
*/
#define GUEST_APLIC_MAX_SOURCES 96U
/*
* Specifies the number of interrupt sources supported by guest APLIC domain.
* Could be limited by host interrupt controller and is identical for every
* domain for now.
*/
extern unsigned int guest_aplic_num_sources;
#endif /* ASM_RISCV_APLIC_PRIV_H */
+2
View File
@@ -92,6 +92,8 @@ static int __init cf_check aplic_init(void)
panic("%s: failed to get number of interrupt sources\n",
node->full_name);
guest_aplic_num_sources = min(GUEST_APLIC_MAX_SOURCES, aplic_info.num_irqs);
if ( aplic_info.num_irqs > ARRAY_SIZE(aplic.regs->sourcecfg) )
aplic_info.num_irqs = ARRAY_SIZE(aplic.regs->sourcecfg);
+8
View File
@@ -34,6 +34,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 */
@@ -3,6 +3,12 @@
#include <public/xen.h>
/*
* Base address of the guest's supervisor-mode APLIC. The value is the address
* typically used for APLIC by QEMU.
*/
#define GUEST_APLIC_S_BASE _UL(0xd000000)
/*
* Base address of the guest's supervisor-mode IMSIC. The value is the address
* typically used for IMSIC by QEMU.
+77
View File
@@ -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,80 @@
#include "aplic-priv.h"
unsigned int __ro_after_init guest_aplic_num_sources;
#define VAPLIC_COMPATIBLE "riscv,aplic"
#define FDT_VAPLIC_INT_CELLS 2
static int __init cf_check vaplic_make_domu_dt_node(struct kernel_info *kinfo)
{
struct domain *d = kinfo->bd.d;
int res;
void *fdt = kinfo->fdt;
unsigned int msi_parent_phandle;
char vaplic_name[32];
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, ARRAY_SIZE(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", guest_aplic_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 __initconstrel init_ops = {
.make_domu_dt_node = vaplic_make_domu_dt_node,
};
static const struct vintc_ops vintc_ops = {
.vcpu_init = vcpu_imsic_init,
.vcpu_deinit = vcpu_imsic_deinit,
@@ -33,6 +109,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_RO;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.