|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |