Similar to ARM systems.

Idea is as follows: If the MSI(-X) is masked, then allow any write to
the underlying register. If a MSI(-X) is unmasked, then check its target
address and add the offset of the vs-file.

The original value is stored in the shadow register, and will be
restored when jailhouse is disabled.

Signed-off-by: Ralf Ramsauer <ralf.ramsa...@oth-regensburg.de>
---
 hypervisor/arch/riscv/pci.c | 86 ++++++++++++++++++++++++++++++++++---
 1 file changed, 80 insertions(+), 6 deletions(-)

diff --git a/hypervisor/arch/riscv/pci.c b/hypervisor/arch/riscv/pci.c
index 067a7651..39e1e4cb 100644
--- a/hypervisor/arch/riscv/pci.c
+++ b/hypervisor/arch/riscv/pci.c
@@ -1,16 +1,20 @@
 /*
  * Jailhouse, a Linux-based partitioning hypervisor
  *
- * Copyright (c) Siemens AG, 2020
+ * Copyright (c) OTH Regensburg, 2023
  *
  * Authors:
- *  Jan Kiszka <jan.kis...@siemens.com>
+ *  Ralf Ramsauer <ralf.ramsa...@oth-regensburg.de>
+ *  Stefan Huber <stefan.hu...@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/entry.h>
+#include <jailhouse/cell.h>
+#include <jailhouse/percpu.h>
+#include <jailhouse/control.h>
+#include <jailhouse/mmio.h>
 #include <jailhouse/pci.h>
 
 u32 arch_pci_read_config(u16 bdf, u16 address, unsigned int size)
@@ -24,7 +28,7 @@ void arch_pci_write_config(u16 bdf, u16 address, u32 value, 
unsigned int size)
 
 int arch_pci_add_physical_device(struct cell *cell, struct pci_device *device)
 {
-       return -ENOSYS;
+       return 0;
 }
 
 void arch_pci_remove_physical_device(struct pci_device *device)
@@ -40,10 +44,80 @@ void arch_pci_set_suppress_msi(struct pci_device *device,
 int arch_pci_update_msi(struct pci_device *device,
                        const struct jailhouse_pci_capability *cap)
 {
-       return -ENOSYS;
+       const struct jailhouse_pci_device *info = device->info;
+       union pci_msi_registers target;
+       struct public_per_cpu *ppc;
+       unsigned short vs_file;
+       unsigned int cpu;
+       unsigned int n;
+
+       /* If the MSI is masked, allow to write any address */
+       target = device->msi_registers;
+       if (!device->msi_registers.msg32.enable)
+               goto passthru;
+
+       /* Only allow non-masked access, if vs-file is set */
+       vs_file = this_cell()->arch.vs_file;
+       if (!vs_file)
+               return -EINVAL;
+
+       for_each_cpu(cpu, &this_cell()->cpu_set) {
+               ppc = public_per_cpu(cpu);
+               /*
+                * If the MSI is unmasked, only allow if the address is
+                * on the S-Mode file and calculate the VS-mode offset.
+                */
+               if (ppc->imsic_base == device->msi_registers.msg64.address) {
+                       target.msg64.address += vs_file * 0x1000;
+                       goto passthru;
+               }
+       }
+
+       return -EINVAL;
+
+passthru:
+       for (n = 1; n < (info->msi_64bits ? 4 : 3); n++)
+               pci_write_config(info->bdf, cap->start + n * 4,
+                                target.raw[n], 4);
+
+       return 0;
 }
 
 int arch_pci_update_msix_vector(struct pci_device *device, unsigned int index)
 {
-       return -ENOSYS;
+       struct public_per_cpu *ppc;
+       unsigned short vs_file;
+       unsigned int cpu;
+       u64 vs_offset = 0;
+
+       vs_file = this_cell()->arch.vs_file;
+
+       /* If the MSI is masked, allow to write any address */
+       if (device->msix_vectors[index].masked)
+               goto passthru;
+
+       /* Only allow non-masked access, if vs-file is set */
+       if (!vs_file)
+               return -EINVAL;
+
+       /*
+        * If the MSI is unmasked, only allow if the address is on the S-Mode
+        * file and calculate the VS-mode offset.
+        */
+       for_each_cpu(cpu, &this_cell()->cpu_set) {
+               ppc = public_per_cpu(cpu);
+               if (ppc->imsic_base == device->msix_vectors[index].address) {
+                       vs_offset = vs_file * 0x1000;
+                       goto passthru;
+               }
+       }
+
+       return -EINVAL;
+
+passthru:
+       mmio_write64_split(&device->msix_table[index].address,
+                          device->msix_vectors[index].address + vs_offset);
+       mmio_write32(&device->msix_table[index].data,
+                    device->msix_vectors[index].data);
+       return 0;
 }
-- 
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-71-ralf.ramsauer%40oth-regensburg.de.

Reply via email to