[PATCH v2 34/39] xen/riscv: restore register state in the new IMSIC VS-file
Oleksii Kurochko <[email protected]>
| Newsgroups | gmane.comp.emulators.xen.devel |
|---|---|
| Message-ID | <c7000473af04e618a340270398fb85fffb46ca05.1787838835.git.oleksii.kurochko@gmail.com> |
At this point, all interrupt producers have been moved to the new IMSIC VS-file so we move register state from the old IMSIC VS/SW-file to the new IMSIC VS-file. As new IMSIC VS-file is ready to be used update vCPU's hstatus with new VGEIN. As the whole migration procedure is finished add some extra explanatory comments. Signed-off-by: Oleksii Kurochko <[email protected]> --- Changes in v2: - New patch. --- --- xen/arch/riscv/imsic.c | 82 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c index 3cba58e0c1b3..d7b137a1f559 100644 --- a/xen/arch/riscv/imsic.c +++ b/xen/arch/riscv/imsic.c @@ -112,6 +112,12 @@ do { \ r_; \ }) +#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)); \ @@ -185,6 +191,19 @@ static void imsic_eix_write(unsigned int ireg, unsigned long val) } } +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(); + } +} + unsigned int vcpu_guest_file_id(const struct vcpu *v) { return ACCESS_ONCE(v->arch.vimsic_state->guest_file_id); @@ -630,13 +649,13 @@ static void cf_check imsic_vsfile_local_read_clear(void *data) old_vsiselect = csr_read(CSR_VSISELECT); old_hstatus = csr_read(CSR_HSTATUS); new_hstatus = old_hstatus & ~HSTATUS_VGEIN; - new_hstatus |= ((unsigned long)idata->hgei) << HSTATUS_VGEIN_SHIFT; + new_hstatus |= MASK_INSR(idata->hgei, HSTATUS_VGEIN); csr_write(CSR_HSTATUS, new_hstatus); /* - * There is no need to use atomic functions version to store - * values in MRIF because imsic_vsfile_read_clear() is always called - * with pointer to temporary MRIF on stack. + * No atomic accessors are needed to store the values into the MRIF here, + * as imsic_vsfile_read_clear() is always called with a pointer to a + * temporary MRIF on the stack. */ mrif->eidelivery = imsic_vs_csr_swap(IMSIC_EIDELIVERY, 0); @@ -972,6 +991,49 @@ 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; + struct imsic_mrif_eix *eix; + 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. + */ + + 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++ ) + { + eix = &mrif->eix[i]; + + imsic_eix_set(IMSIC_EIP0 + i * 2, eix->eip[0]); + imsic_eix_set(IMSIC_EIE0 + i * 2, eix->eie[0]); +#ifdef CONFIG_RISCV_32 + imsic_eix_set(IMSIC_EIP0 + i * 2 + 1, eix->eip[1]); + imsic_eix_set(IMSIC_EIE0 + i * 2 + 1, eix->eie[1]); +#endif + } + + 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); +} + void imsic_migrate_vcpu(struct vcpu *v) { unsigned int new_vsfile_hgei; @@ -1068,7 +1130,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 */ @@ -1077,5 +1140,12 @@ 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 */ + vsfile_data.mrif = &tmrif; + imsic_call_on_cpu(new_vsfile_cpu, 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(new_vsfile_hgei, HSTATUS_VGEIN); } -- 2.55.0