|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v3 39/39] xen/riscv: introduce IMSIC h/w interrupt file attaching to vcpu
Introduce imsic_vsfile_attach() to give a vCPU a working guest
interrupt file.
A guest (VS) interrupt file has to be backed by one of the hardware
guest interrupt files of the pCPU the vCPU runs on, so that pCPU has to
be known first. arch_vcpu_create() is therefore not a suitable place:
the pCPU assigned to a vCPU can still change before the vCPU is first
scheduled, which would mean taking another file and remapping the
guest's IMSIC page to it. Call imsic_vsfile_attach() from
continue_new_vcpu() instead, i.e. when the vCPU is scheduled for the
first time; as that isn't an __init context, neither is
imsic_vsfile_attach().
Giving a vCPU its first file shares most of the steps with moving it to
a new one on migration, so move the body of imsic_migrate_vcpu() to
imsic_vsfile_move() and use it for both. Its first_attach argument skips
the part which moves the interrupt state out of the old file: the vCPU
has never run at that point, so the freshly acquired and zeroed file is
all the interrupt state it has, and hstatus.VGEIN can be pointed at it
right away.
vAPLIC target registers are reconfigured on the first attach as well: a
target the guest writes for a vCPU which has no h/w guest interrupt file
yet only updates the stored copy, which reaches the h/w at this point.
A vCPU which has already run is left without a h/w file only when its
first attach failed, which crashed its domain. Such a vCPU can still be
migrated, e.g. by an affinity change or a pCPU going offline, until the
domain is destroyed, so don't panic() for it, which would take the whole
host down: return early. Should a vCPU of a domain which isn't shutting
down ever get there, crash that domain rather than the host.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
---
imsic_vsfile_move() isn't split out of imsic_migrate_vcpu() earlier in the
series: until this patch imsic_migrate_vcpu() would be its only user, so the
first_attach path would have no caller. The first attach itself can't come
earlier either, as it is done from continue_new_vcpu(), introduced by
"xen/riscv: implement continue_new_vcpu()".
---
Changes in v3:
- imsic_update_state() is now implemented by "xen/riscv: remap
interrupts to new IMSIC VS-file".
- Share the code of imsic_vsfile_attach() and imsic_migrate_vcpu() in
imsic_vsfile_move(), whose first_attach argument skips the part moving
state out of the old file.
- Call vaplic_reconfigure_target() on the first attach as well, so that
vAPLIC targets the guest wrote for the vCPU before it got its file reach
the h/w.
- Replace panic() for a vCPU left without a h/w file by domain_crash():
it can only happen to a vCPU whose first imsic_vsfile_acquire() failed
and crashed its domain, and such a vCPU can still be migrated.
- imsic_vsfile_acquire(), together with the vgein_release() on a
mapping failure, is now introduced by "xen/riscv: remap interrupts to
new IMSIC VS-file", without the cpu argument (the file is always
taken on v->processor).
- Include asm/imsic.h for imsic_vsfile_attach().
- Drop imsic_nr_eix() in favour of imsic_cfg.nr_eix.
- Drop vcpu_set_vgein(): with the code shared in imsic_vsfile_move(),
hstatus.VGEIN is updated in one place only.
- Rework the commit message: drop the stale vcpu_aia_init() name and
the claim that the IMSIC state has no concurrent readers yet.
---
Changes in v2:
- Update vcpu_aia_init() to catch sw interrupt file and update some
debug messages in it.
- Add vgein_release() if IMSIC h/w mapping failed.
- imsic_update_state(): store v->processor rather than
cpuid_to_hartid(), as ->vsfile_cpu is consumed as a Xen CPU id
(aplic_hart_field(), cpumask_of()) and its NR_CPUS sentinel lives in
that numbering space.
- Drop parentheses around guest_file_id ? ... in imsic_update_state().
- Rename vcpu_aia_init to imsic_vsfile_attach() and move the code to
imsic.c.
---
---
xen/arch/riscv/domain.c | 3 ++
xen/arch/riscv/imsic.c | 79 +++++++++++++++++++++++-------
xen/arch/riscv/include/asm/imsic.h | 2 +
3 files changed, 66 insertions(+), 18 deletions(-)
diff --git a/xen/arch/riscv/domain.c b/xen/arch/riscv/domain.c
index 9155ff4234e8..e8ae62626b76 100644
--- a/xen/arch/riscv/domain.c
+++ b/xen/arch/riscv/domain.c
@@ -13,6 +13,7 @@
#include <asm/csr.h>
#include <asm/current.h>
#include <asm/gpr-num.h>
+#include <asm/imsic.h>
#include <asm/intc.h>
#include <asm/mmio.h>
#include <asm/riscv_encoding.h>
@@ -268,6 +269,8 @@ static void continue_new_vcpu(struct vcpu *prev)
vcpu_set_vsxl(current);
+ imsic_vsfile_attach(current);
+
/*
* return_to_new_vcpu() sets up hstatus.SPV, sstatus.SPP and sepc so
* that sret enters the guest in VS-mode. A trap taken in HS-mode
diff --git a/xen/arch/riscv/imsic.c b/xen/arch/riscv/imsic.c
index a8e99997c087..bb8cdf437a6a 100644
--- a/xen/arch/riscv/imsic.c
+++ b/xen/arch/riscv/imsic.c
@@ -1251,7 +1251,14 @@ static unsigned int imsic_vsfile_acquire(struct vcpu *v)
return vsfile_id;
}
-void imsic_migrate_vcpu(struct vcpu *v)
+/*
+ * Give the vCPU a h/w guest interrupt file on the pCPU it runs on and move
+ * all its interrupt producers and state there.
+ *
+ * @first_attach tells that the vCPU is only now given its very first file,
+ * so there is no old file to move anything out of.
+ */
+static void imsic_vsfile_move(struct vcpu *v, bool first_attach)
{
struct imsic_vsfile_data vsfile_data = {
.nr_eix = imsic_cfg.nr_eix,
@@ -1262,33 +1269,38 @@ void imsic_migrate_vcpu(struct vcpu *v)
unsigned int old_vsfile_id;
unsigned int old_vsfile_cpu;
- /*
- * The scheduler can mark a freshly created vCPU's unit as migrated and
- * invoke this before the vCPU has ever run (see the migrated branch in
- * schedule()). No need to do migration for such vCPUs as they aren't fully
- * initialized (for example, context_switch() will be called after
- * imsic_migrate_vcpu()).
- */
- if ( v->arch.last_cpu == CPU_NONE )
- return;
-
read_lock_irqsave(&imsic_state->vsfile_lock, flags);
old_vsfile_id = imsic_state->guest_file_id;
old_vsfile_cpu = imsic_state->vsfile_cpu;
read_unlock_irqrestore(&imsic_state->vsfile_lock, flags);
+ ASSERT(!first_attach || old_vsfile_cpu == CPU_NONE);
+
/*
- * We don't support SW interrupt files at the moment. Bail out before
- * anything is touched, as the old file has no owning pCPU in that case
- * and there is nothing to retarget the producers away from.
+ * With no h/w file owned, the vCPU is either given its first file or
+ * uses a s/w file, and s/w files aren't supported at the moment.
+ *
+ * A vCPU which has already run has no h/w file only if its first
+ * imsic_vsfile_acquire() failed and crashed its domain. The vCPU can
+ * still be migrated until the domain is destroyed, so return early, as
+ * there is no old file to move anything out of. Should that ever happen
+ * for a domain which isn't shutting down, crash it rather than the host;
+ * for one which already is, domain_crash() does nothing but log.
+ *
+ * TODO: once s/w files are supported, move the state out of the s/w file
+ * here instead.
*/
- if ( old_vsfile_cpu == CPU_NONE )
- panic("IMSIC SW-file isn't supported\n");
+ if ( old_vsfile_cpu == CPU_NONE && !first_attach )
+ {
+ ASSERT(domain_shutting_down(v->domain));
+ domain_crash(v->domain, "%pv: IMSIC s/w VS-file isn't supported\n", v);
+ return;
+ }
/*
* At this point, all interrupt producers are still using the old IMSIC
- * VS-file. Allocate and clear the new one before redirecting anything
- * to it.
+ * VS-file, if any. Allocate and clear the new one before redirecting
+ * anything to it.
*/
/* Zero-out, map and start to use the new IMSIC VS-file */
@@ -1310,6 +1322,13 @@ void imsic_migrate_vcpu(struct vcpu *v)
*/
vaplic_reconfigure_target(v);
+ /*
+ * The vCPU has never run yet, so the just zeroed out file is all the
+ * interrupt state it has and HSTATUS.VGEIN can be pointed at it at once.
+ */
+ if ( first_attach )
+ goto set_vgein;
+
/*
* Synchronizing interactions between a hart and the APLIC.
*
@@ -1349,8 +1368,32 @@ void imsic_migrate_vcpu(struct vcpu *v)
if ( !v->is_running )
imsic_call_on_cpu(v->processor, imsic_local_hgeie_set, &vsfile_data);
+ set_vgein:
/* 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);
}
+
+void imsic_migrate_vcpu(struct vcpu *v)
+{
+ /*
+ * The scheduler can mark a freshly created vCPU's unit as migrated and
+ * invoke this before the vCPU has ever run (see the migrated branch in
+ * schedule()). No need to do migration for such vCPUs as they aren't fully
+ * initialized (for example, context_switch() will be called after
+ * imsic_migrate_vcpu()).
+ */
+ if ( v->arch.last_cpu == CPU_NONE )
+ return;
+
+ imsic_vsfile_move(v, false);
+}
+
+void imsic_vsfile_attach(struct vcpu *v)
+{
+ if ( !aia_usable() )
+ return;
+
+ imsic_vsfile_move(v, true);
+}
diff --git a/xen/arch/riscv/include/asm/imsic.h
b/xen/arch/riscv/include/asm/imsic.h
index e08b041eebbd..118c3dc94a17 100644
--- a/xen/arch/riscv/include/asm/imsic.h
+++ b/xen/arch/riscv/include/asm/imsic.h
@@ -118,4 +118,6 @@ int imsic_map_guest_file(struct vcpu *v, unsigned int
vsfile_id);
void imsic_migrate_vcpu(struct vcpu *v);
+void imsic_vsfile_attach(struct vcpu *v);
+
#endif /* ASM_RISCV_IMSIC_H */
--
2.55.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |