Later, we will add support for PLIC and APLIC. This irqchip layer adds a
level of abstraction for both irqchips, and will hold code that is
shared between both.

With this commit, fill irqchip.c with life, and and the common code for
both.

Signed-off-by: Ralf Ramsauer <ralf.ramsa...@oth-regensburg.de>
---
 hypervisor/arch/riscv/Kbuild    |   4 +-
 hypervisor/arch/riscv/irqchip.c | 182 ++++++++++++++++++++++++++++++++
 2 files changed, 184 insertions(+), 2 deletions(-)
 create mode 100644 hypervisor/arch/riscv/irqchip.c

diff --git a/hypervisor/arch/riscv/Kbuild b/hypervisor/arch/riscv/Kbuild
index 7809007c..57c52854 100644
--- a/hypervisor/arch/riscv/Kbuild
+++ b/hypervisor/arch/riscv/Kbuild
@@ -14,5 +14,5 @@
 
 always-y := lib.a
 
-lib-y := entry.o exception.o setup.o dbg-write.o control.o ivshmem.o paging.o
-lib-y += pci.o traps.o lib.o
+lib-y := entry.o exception.o setup.o dbg-write.o control.o ivshmem.o irqchip.o
+lib-y += paging.o pci.o traps.o lib.o
diff --git a/hypervisor/arch/riscv/irqchip.c b/hypervisor/arch/riscv/irqchip.c
new file mode 100644
index 00000000..880f1fab
--- /dev/null
+++ b/hypervisor/arch/riscv/irqchip.c
@@ -0,0 +1,182 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) OTH Regensburg, 2023
+ *
+ * Authors:
+ *  Ralf Ramsauer <ralf.ramsa...@oth-regensburg.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <jailhouse/control.h>
+#include <jailhouse/unit.h>
+#include <jailhouse/printk.h>
+#include <jailhouse/processor.h>
+#include <asm/irqchip.h>
+
+/* Could also be used for arm-common/irqchip.c */
+#define IRQCHIP_PINS \
+       (sizeof(((struct jailhouse_irqchip *)0)->pin_bitmap) * 8)
+
+#define IRQ_BITMAP_PINS \
+       (sizeof(((struct cell *)0)->arch.irq_bitmap) * 8)
+
+struct irqchip irqchip;
+
+static unsigned int irqchip_mmio_count_regions(struct cell *cell)
+{
+       return 1;
+}
+
+/* Borrowed from ARM */
+static void irqchip_config_commit(struct cell *cell)
+{
+       unsigned int n;
+
+       if (!cell)
+               return;
+
+       for (n = 1; n < MAX_IRQS; n++) {
+               if (irqchip_irq_in_cell(cell, n) && cell != &root_cell)
+                       irqchip.adjust_irq_target(cell, n);
+
+               if (irqchip_irq_in_cell(&root_cell, n))
+                       irqchip.adjust_irq_target(&root_cell, n);
+       }
+}
+
+static enum mmio_result irqchip_mmio(void *arg, struct mmio_access *access)
+{
+       /* only allow 32bit access */
+       if (access->size != IRQCHIP_REG_SZ)
+               return MMIO_ERROR;
+
+       return irqchip.mmio_handler(arg, access);
+}
+
+static int irqchip_cell_init(struct cell *cell)
+{
+       const struct jailhouse_irqchip *chip;
+       unsigned int n, pos;
+
+       mmio_region_register(cell, irqchip_phys(), irqchip_size(),
+                            irqchip_mmio, cell);
+
+       memset(cell->arch.irq_bitmap, 0, sizeof(cell->arch.irq_bitmap));
+
+       for_each_irqchip(chip, cell->config, n) {
+               /* Only support one single PLIC at the moment */
+               if (chip->address !=
+                   system_config->platform_info.riscv.irqchip.base_address)
+                       return trace_error(-EINVAL);
+
+               if (chip->pin_base % 32 != 0 ||
+                   chip->pin_base + IRQCHIP_PINS > IRQ_BITMAP_PINS)
+                       return trace_error(-EINVAL);
+
+               for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++)
+                       cell->arch.irq_bitmap[chip->pin_base / 32 + pos] |=
+                               chip->pin_bitmap[pos];
+       }
+
+       /* This logic is shared with arm-common */
+       if (cell == &root_cell)
+               return 0;
+
+       for_each_irqchip(chip, cell->config, n)
+               for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++)
+                       root_cell.arch.irq_bitmap[chip->pin_base / 32 + pos] &=
+                               ~chip->pin_bitmap[pos];
+
+       return 0;
+}
+
+static inline bool guest_ext_pending(void)
+{
+       return !!(csr_read(CSR_HVIP) &
+                       ((1 << IRQ_S_EXT) << VSIP_TO_HVIP_SHIFT));
+}
+
+int irqchip_set_pending(void)
+{
+       int err;
+
+       this_cpu_public()->stats[JAILHOUSE_CPU_STAT_VMEXITS_VIRQ]++;
+
+       err = irqchip.claim_irq();
+       if (err)
+               return err;
+
+       /*
+        * We can directly inject the IRQ into the guest if the IRQ is not
+        * pending, because we know that the IRQ is enabled, otherwise we
+        * wouldn't have received it
+        */
+       guest_inject_ext();
+
+       /*
+        * Don't claim complete! This must be done by the guest. We will handle
+        * that in plic_handler(). In the meanwhile we simply deactivate S-Mode
+        * External IRQs, and reenable them when the guest claims it. In this
+        * way, we only need to store one pending IRQ per hart.
+        */
+       ext_disable();
+
+       return 0;
+}
+
+static int irqchip_init(void)
+{
+       int err;
+
+       /* We don't have a working irqchip yet */
+       switch (irqchip_type()) {
+               default:
+                       return trace_error(-ENOSYS);
+       }
+
+       irqchip.base = paging_map_device(irqchip_phys(), irqchip_size());
+       if (!irqchip.base)
+               return -ENOMEM;
+
+
+       err = irqchip_cell_init(&root_cell);
+       if (err)
+               return err;
+
+       err = irqchip.init();
+
+       return err;
+}
+
+static void irqchip_shutdown(void)
+{
+       if (!irqchip.base)
+               return;
+
+       paging_unmap_device(irqchip_phys(), irqchip.base, irqchip_size());
+}
+
+static void irqchip_cell_exit(struct cell *cell)
+{
+       const struct jailhouse_irqchip *chip;
+       unsigned int n, pos;
+
+       mmio_region_unregister(cell, irqchip_phys());
+
+       /* set all pins of the old cell in the root cell */
+       for_each_irqchip(chip, cell->config, n)
+               for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++)
+                       root_cell.arch.irq_bitmap[chip->pin_base / 32 + pos] |=
+                               chip->pin_bitmap[pos];
+
+       /* mask out pins again that actually didn't belong to the root cell */
+       for_each_irqchip(chip, root_cell.config, n)
+               for (pos = 0; pos < ARRAY_SIZE(chip->pin_bitmap); pos++)
+                       root_cell.arch.irq_bitmap[chip->pin_base / 32 + pos] &=
+                               chip->pin_bitmap[pos];
+}
+
+DEFINE_UNIT(irqchip, "RISC-V irqchip");
-- 
2.40.1

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to jailhouse-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/20230519204033.643200-50-ralf.ramsauer%40oth-regensburg.de.

Reply via email to