[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 33/39] xen/riscv: restore register state in the new IMSIC VS-file



Complete the migration of a vCPU's guest interrupt file: move the state
saved from the old IMSIC VS-file into the new one and make the vCPU use
the new VS-file.

The interrupt producers have already been retargeted to the new
VS-file, so MSIs may land in it before the saved state is restored.
Hence the saved eip/eie bits are ORed into the new VS-file rather than
written to it, so that such MSIs aren't lost. eithreshold and
eidelivery are restored last: the new VS-file was cleared when it was
acquired, so it doesn't deliver interrupts until its pending and enable
bits are complete.

As with reading the old VS-file, this has to be done on the pCPU owning
the new VS-file, with hstatus.VGEIN temporarily selecting it. That is
v->processor, the pCPU the vCPU is migrating to.

Finally, point hstatus.VGEIN in the vCPU's saved context at the new
VS-file, so that it becomes the source of the vCPU's VS-level external
interrupts and the file the guest accesses through its siselect/sireg.
With that the migration is complete, so drop the BUG_ON("unimplemented")
placeholder from imsic_migrate_vcpu().

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
---
Changes in v3:
 - Reword the commit message: explain why the saved state is ORed into
   the new VS-file and why eithreshold and eidelivery are restored last,
   drop the note about explanatory comments.
 - Leave the trailing semicolon of the switchcase macros to their users.
 - Drop the redundant parentheses around the arguments of
   imsic_vs_csr_set() as they are passed to csr_*() as whole
   expressions.
 - Add missing break after ASSERT_UNREACHABLE() in the default case of
   imsic_eix_set().
 - Restore the state on v->processor and take the id of the new IMSIC
   VS-file from vsfile_data.hgei, as imsic_migrate_vcpu() no longer has
   separate local variables for the new VS-file.
 - Explain why hstatus and vsiselect are saved and restored with a short
   comment in imsic_vsfile_local_update().
 - Introduce imsic_eix_set64() to set bits of a whole 64-bit EIx group,
   which lets the #ifdef CONFIG_RISCV_32 in imsic_vsfile_local_update()
   go.
 - Move the MASK_INSR() conversion and the comment rewording in
   imsic_vsfile_local_read_clear() to the patch introducing that
   function.
---
Changes in v2:
 - New patch.
---
---
 xen/arch/riscv/imsic.c | 80 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 78 insertions(+), 2 deletions(-)

diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c
index 2c4838b6b228..e35688f98bb1 100644
--- a/xen/arch/riscv/imsic.c
+++ b/xen/arch/riscv/imsic.c
@@ -114,6 +114,12 @@ do {                            \
     csr_swap(CSR_VSIREG, v);        \
 })
 
+#define imsic_vs_csr_set(c, v)      \
+do {                                \
+    csr_write(CSR_VSISELECT, c);    \
+    csr_set(CSR_VSIREG, v);         \
+} while (0)
+
 #define imsic_vs_csr_write(c, v)    \
 do {                                \
     csr_write(CSR_VSISELECT, c);    \
@@ -212,6 +218,28 @@ static uint64_t imsic_eix_swap64(unsigned int ireg, 
uint64_t val)
     return old;
 }
 
+static void imsic_eix_set(unsigned int ireg, unsigned long val)
+{
+    switch ( ireg )
+    {
+    imsic_switchcase_64(imsic_switchcase_break, IMSIC_EIP0,
+                        imsic_vs_csr_set, val);
+    imsic_switchcase_64(imsic_switchcase_break, IMSIC_EIE0,
+                        imsic_vs_csr_set, val);
+    default:
+        ASSERT_UNREACHABLE();
+        break;
+    }
+}
+
+/* Set bits of a whole 64-bit EIx group, laid out as described above. */
+static void imsic_eix_set64(unsigned int ireg, uint64_t val)
+{
+    imsic_eix_set(ireg, val);
+    if ( IS_ENABLED(CONFIG_RISCV_32) )
+        imsic_eix_set(ireg + 1, val >> 32);
+}
+
 unsigned int vcpu_guest_file_id(const struct vcpu *v)
 {
     return ACCESS_ONCE(v->arch.vimsic_state->guest_file_id);
@@ -1016,6 +1044,47 @@ int __init vimsic_make_domu_dt_node(struct kernel_info 
*kinfo,
     return fdt_end_node(fdt);
 }
 
+static void cf_check imsic_vsfile_local_update(void *data)
+{
+    unsigned int i;
+    const struct imsic_vsfile_data *idata = data;
+    struct imsic_mrif *mrif = idata->mrif;
+    unsigned long new_hstatus, old_hstatus, old_vsiselect;
+
+    /* We can only update if we have a HW IMSIC context */
+    if ( !idata->hgei )
+        return;
+
+    /*
+     * No atomic accessors are needed to read the values out of the MRIF here,
+     * as this is always called with a pointer to a temporary MRIF on the
+     * stack.
+     */
+
+    /*
+     * The file is reached by retargeting hstatus.VGEIN, and the
+     * imsic_vs_csr_*() accessors alter vsiselect. Both belong to the vCPU
+     * running on this pCPU, so restore them before returning.
+     */
+    old_vsiselect = csr_read(CSR_VSISELECT);
+    old_hstatus = csr_read(CSR_HSTATUS);
+    new_hstatus = old_hstatus & ~HSTATUS_VGEIN;
+    new_hstatus |= MASK_INSR(idata->hgei, HSTATUS_VGEIN);
+    csr_write(CSR_HSTATUS, new_hstatus);
+
+    for ( i = 0; i < idata->nr_eix; i++ )
+    {
+        imsic_eix_set64(IMSIC_EIP0 + i * 2, mrif->eix[i].eip);
+        imsic_eix_set64(IMSIC_EIE0 + i * 2, mrif->eix[i].eie);
+    }
+
+    imsic_vs_csr_write(IMSIC_EITHRESHOLD, mrif->eithreshold);
+    imsic_vs_csr_write(IMSIC_EIDELIVERY, mrif->eidelivery);
+
+    csr_write(CSR_HSTATUS, old_hstatus);
+    csr_write(CSR_VSISELECT, old_vsiselect);
+}
+
 /*
  * Take a h/w guest interrupt file on the pCPU @v runs on and make it the
  * vCPU's one.
@@ -1142,7 +1211,8 @@ void imsic_migrate_vcpu(struct vcpu *v)
 
     /*
      * At this point, all interrupt producers have been moved
-     * to the new IMSIC VS-file.
+     * to the new IMSIC VS-file so we move register state from
+     * the old IMSIC VS/SW-file to the new IMSIC VS-file.
      */
 
     /* Read and clear register state from old IMSIC VS-file */
@@ -1152,5 +1222,11 @@ void imsic_migrate_vcpu(struct vcpu *v)
     /* Free-up old IMSIC VS-file */
     vgein_release(v, old_vsfile_id, old_vsfile_cpu);
 
-    BUG_ON("unimplemented");
+    /* Restore register state in the new IMSIC VS-file */
+    imsic_call_on_cpu(v->processor, imsic_vsfile_local_update, &vsfile_data);
+
+    /* Set VCPU HSTATUS.VGEIN to new IMSIC VS-file */
+    vcpu_guest_cpu_user_regs(v)->hstatus &= ~HSTATUS_VGEIN;
+    vcpu_guest_cpu_user_regs(v)->hstatus |=
+        MASK_INSR(vsfile_data.hgei, HSTATUS_VGEIN);
 }
-- 
2.55.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.