From: Oleksii Kurochko <oleksii.kurochko@gmail.com>
To: xen-devel@lists.xenproject.org
Cc: "Romain Caritey" <Romain.Caritey@microchip.com>,
"Baptiste Le Duc" <baptiste.le-duc@vates.tech>,
"Zheng Zhang" <zhangzheng@iscas.ac.cn>,
"Alistair Francis" <alistair.francis@wdc.com>,
"Connor Davis" <connojdavis@gmail.com>,
"Andrew Cooper" <andrew.cooper3@citrix.com>,
"Anthony PERARD" <anthony.perard@vates.tech>,
"Michal Orzel" <michal.orzel@amd.com>,
"Jan Beulich" <jbeulich@suse.com>,
"Julien Grall" <julien@xen.org>,
"Roger Pau Monné" <roger@xenproject.org>,
"Stefano Stabellini" <sstabellini@kernel.org>
Subject: Re: [PATCH v2 12/39] xen/riscv: implement vCPU context switching
Date: Sat, 5 Sep 2026 09:25:13 +0200 [thread overview]
Message-ID: <9267476f-c6a0-4cfb-b128-10c475d2d5a6@gmail.com> (raw)
In-Reply-To: <8848874c69f00fbfcf6ad75a39e28479a4cdd08b.1787838835.git.oleksii.kurochko@gmail.com>
I've updated the part of handling of VMID for p2m during context switch
as some things were still missed. This one implementation looks more
correct to me.
diff --git a/xen/arch/riscv/domain.c b/xen/arch/riscv/domain.c
index 0ad851ee0f5f..c05d6f8abaaa 100644
--- a/xen/arch/riscv/domain.c
+++ b/xen/arch/riscv/domain.c
@@ -404,16 +404,6 @@ static void ctxt_switch_to(struct vcpu *n)
if ( is_idle_vcpu(n) )
return;
- /*
- * If this vCPU last ran on a different pCPU, invalidate its VMID so
- * vmid_handle_vmenter() assigns a fresh one from the current
pCPU's pool.
- * Without this, two pCPUs could independently assign the same
- * (generation, vmid) pair, generation counters start at the same value
- * on all pCPUs and increment independently, causing TLB contamination.
- */
- if ( n->arch.last_cpu != smp_processor_id() )
- vmid_flush_vcpu(n);
-
vtimer_ctxt_switch_to(n);
restore_csr_regs(n);
@@ -421,6 +411,15 @@ static void ctxt_switch_to(struct vcpu *n)
p2m_ctxt_switch_to(n);
}
+/*
+ * Domain whose p2m this hart's HGATP points at. ctxt_switch_to() bails out
+ * early for the idle vCPU, so HGATP survives a pass through idle and keeps
+ * pointing at the domain which ran here last. That domain, rather than the
+ * one the scheduler switched away from, is what owns this hart's G-stage
+ * translations.
+ */
+static DEFINE_PER_CPU(struct domain *, hgatp_owner);
+
static void schedule_tail(struct vcpu *prev)
{
unsigned int cpu = smp_processor_id();
@@ -429,40 +428,88 @@ static void schedule_tail(struct vcpu *prev)
ctxt_switch_from(prev);
+ write_atomic(&prev->dirty_cpu, VCPU_CPU_CLEAN);
+
/*
- * Mark this CPU in next domain's dirty cpumasks before calling
- * ctxt_switch_to(). This avoids a race on things like p2m flushing,
- * which is synchronised on that function.
+ * Switching to the idle vCPU leaves HGATP alone, so this hart
keeps both
+ * the G-stage translations of its owner and its place in that domain's
+ * dirty_cpumask: p2m_tlb_flush() goes on reaching it, and a domain
which
+ * idles between two runs on the same hart keeps its VMIDs.
*/
- if ( prev->domain != current->domain )
+ if ( !is_idle_vcpu(current) )
+ {
+ struct domain *owner = this_cpu(hgatp_owner);
+
+ if ( owner != current->domain )
+ {
+ /*
+ * Once this hart drops out of the owner's dirty_cpumask it
stops
+ * being a target of p2m_tlb_flush(), while its TLB may
still hold
+ * G-stage translations of that domain: none of the vCPUs
of that
+ * domain which ran here has had its VMID invalidated. Move the
+ * hart to a new VMID generation so that none of them can be
+ * reached again.
+ */
+ if ( owner )
+ {
+ vmid_flush_hart();
+
+ cpumask_clear_cpu(cpu, owner->dirty_cpumask);
+ }
+
+ /*
+ * Mark this hart in the incoming domain's dirty_cpumask before
+ * ctxt_switch_to() points HGATP at its p2m. This avoids a
race on
+ * things like p2m flushing, which is synchronised on that
+ * function.
+ */
+ cpumask_set_cpu(cpu, current->domain->dirty_cpumask);
+
+ /*
+ * Pairs with the barrier in p2m_tlb_flush().
cpumask_set_cpu() is
+ * an unordered AMO on RISC-V, so without this a concurrent
flusher
+ * could read the mask without this hart in it while this
hart is
+ * already walking the p2m it is about to be pointed at.
+ */
+ smp_mb();
+
+ this_cpu(hgatp_owner) = current->domain;
+ }
+ }
+
+ if ( !is_idle_vcpu(current) )
{
- cpumask_set_cpu(cpu, current->domain->dirty_cpumask);
+ bool need_flush;
+
+ /*
+ * A VMID is meaningful only on the hart whose pool issued it:
+ * generations are per-hart counters which all start at 1 and
advance
+ * independently, so the pair a vCPU brings from another hart
may match
+ * this hart's generation by coincidence, leaving the vCPU
under a VMID
+ * which is live here for someone else.
+ */
+ if ( current->arch.last_cpu != cpu )
+ vmid_flush_vcpu(current);
/*
- * Once this hart drops out of prev's dirty_cpumask it stops
being a
- * target of p2m_tlb_flush(), while its TLB may still hold G-stage
- * translations of prev's domain: neither the vCPU which just
ran nor
- * any other vCPU of that domain which ran here earlier has had its
- * VMID invalidated. Move the hart to a new VMID generation so that
- * none of them can be reached again.
- *
- * Switching away from the idle vCPU needs no bump: the idle domain
- * has no p2m of its own, and whatever G-stage entries this
hart may
- * still hold (or speculatively create while HGATP keeps
pointing at
- * the last guest's p2m) are tagged with a VMID which was
already made
- * stale when that guest was switched out. Skipping the bump
here also
- * avoids burning a generation on every pass through idle.
+ * Claim the VMID here rather than leaving it to the next guest
entry:
+ * ctxt_switch_to() makes HGATP live below, and a stale VMID there
+ * pairs this domain's G-stage root with a tag which may
already have
+ * been re-issued to a vCPU of another domain.
*/
- if ( !is_idle_vcpu(prev) )
- vmid_flush_hart();
+ need_flush = vmid_handle_vmenter(¤t->arch.vmid);
- cpumask_clear_cpu(cpu, prev->domain->dirty_cpumask);
+ /*
+ * A VMID isn't re-used until the generation it was issued in
wraps, so
+ * a G-stage flush is needed only when vmid_handle_vmenter()
says so.
+ */
+ if ( unlikely(need_flush) )
+ local_hfence_gvma_all();
}
- write_atomic(¤t->dirty_cpu, cpu);
ctxt_switch_to(current);
- write_atomic(&prev->dirty_cpu, VCPU_CPU_CLEAN);
+ write_atomic(¤t->dirty_cpu, cpu);
current->arch.last_cpu = cpu;
diff --git a/xen/arch/riscv/p2m.c b/xen/arch/riscv/p2m.c
index 1f7a6907525d..98c2d6de6933 100644
--- a/xen/arch/riscv/p2m.c
+++ b/xen/arch/riscv/p2m.c
@@ -243,6 +243,15 @@ static void p2m_tlb_flush(struct p2m_domain *p2m)
p2m->need_flush = false;
+ /*
+ * Order the p2m updates above against the read of dirty_cpumask below,
+ * pairing with the barrier in schedule_tail(). Either that hart is
seen
+ * here and gets an HFENCE.GVMA, or it adds itself to the mask
afterwards,
+ * in which case it starts walking this p2m only once the updates are
+ * visible to it.
+ */
+ smp_mb();
+
sbi_remote_hfence_gvma(d->dirty_cpumask, 0, 0);
}
@@ -1523,22 +1532,12 @@ void p2m_ctxt_switch_from(struct vcpu *p)
void p2m_ctxt_switch_to(struct vcpu *n)
{
struct p2m_domain *p2m = p2m_get_hostp2m(n->domain);
- bool need_flush;
if ( is_idle_vcpu(n) )
return;
- need_flush = vmid_handle_vmenter(&n->arch.vmid);
-
csr_write(CSR_HGATP, construct_hgatp(p2m, n->arch.vmid.vmid));
- /*
- * A VMID isn't re-used until the generation it was issued in wraps, so
- * a G-stage flush is needed only when vmid_handle_vmenter() says so.
- */
- if ( unlikely(need_flush) )
- local_hfence_gvma_all();
-
csr_write(CSR_VSATP, n->arch.vsatp);
/*
Any concerns about this implementation?
Thanks in advance.
~ Oleksii
next prev parent reply other threads:[~2026-09-05 7:25 UTC|newest]
Thread overview: 163+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 15:20 [PATCH v2 00/39] [RISC-V] virtual interrupt controller (vAPLIC/vIMSIC) support Oleksii Kurochko
2026-08-27 15:20 ` [PATCH v2 01/39] xen/riscv: drop pregs from struct cpu_user_regs Oleksii Kurochko
2026-08-31 12:48 ` Baptiste Le Duc
2026-09-01 6:58 ` Jan Beulich
2026-08-27 15:20 ` [PATCH v2 02/39] xen/riscv: drop bug.h's duplicate instruction length helpers Oleksii Kurochko
2026-08-31 12:48 ` Baptiste Le Duc
2026-09-01 7:01 ` Jan Beulich
2026-09-02 10:48 ` Oleksii Kurochko
2026-09-02 13:02 ` Jan Beulich
2026-09-02 13:45 ` Oleksii Kurochko
2026-09-02 14:27 ` Jan Beulich
2026-08-27 15:20 ` [PATCH v2 03/39] xen/riscv: set the guest's XLEN explicitly in hstatus.VSXL Oleksii Kurochko
2026-08-31 12:48 ` Baptiste Le Duc
2026-09-01 7:03 ` Jan Beulich
2026-09-01 8:40 ` Oleksii Kurochko
2026-09-01 15:16 ` Jan Beulich
2026-09-01 15:20 ` Jan Beulich
2026-09-02 11:42 ` Oleksii Kurochko
2026-09-02 13:07 ` Jan Beulich
2026-09-02 13:29 ` Oleksii Kurochko
2026-09-02 14:31 ` Jan Beulich
2026-09-02 15:17 ` Oleksii Kurochko
2026-09-02 15:56 ` Oleksii Kurochko
2026-09-02 17:45 ` Oleksii Kurochko
2026-08-27 15:20 ` [PATCH v2 04/39] xen/riscv: introduce csr_read64() Oleksii Kurochko
2026-08-27 15:36 ` Andrew Cooper
2026-08-31 12:42 ` Oleksii Kurochko
2026-09-01 7:07 ` Jan Beulich
2026-08-27 15:20 ` [PATCH v2 05/39] xen/riscv: request a G-stage flush on vmenter when VMIDs are disabled Oleksii Kurochko
2026-08-31 12:48 ` Baptiste Le Duc
2026-09-01 8:43 ` Oleksii Kurochko
2026-08-27 15:20 ` [PATCH v2 06/39] xen/riscv: use UINT64_MAX to disable the VS-timer Oleksii Kurochko
2026-08-31 12:48 ` Baptiste Le Duc
2026-09-01 7:12 ` Jan Beulich
2026-09-01 8:47 ` Oleksii Kurochko
2026-08-27 15:20 ` [PATCH v2 07/39] xen/riscv: add missing APLIC register offsets, masks to asm/aplic.h Oleksii Kurochko
2026-09-01 15:36 ` Baptiste Le Duc
2026-09-01 15:53 ` Jan Beulich
2026-09-02 13:22 ` Jan Beulich
2026-09-02 13:52 ` Oleksii Kurochko
2026-08-27 15:20 ` [PATCH v2 08/39] xen/riscv: introduce device-agnostic MMIO emulation dispatch Oleksii Kurochko
2026-09-01 15:36 ` Baptiste Le Duc
2026-09-03 10:28 ` Oleksii Kurochko
2026-09-09 13:24 ` Jan Beulich
2026-09-09 14:04 ` Oleksii Kurochko
2026-09-09 14:32 ` Jan Beulich
2026-08-27 15:20 ` [PATCH v2 09/39] xen/riscv: implement virtual APLIC MMIO emulation Oleksii Kurochko
2026-09-02 11:51 ` Baptiste Le Duc
2026-09-04 11:58 ` Oleksii Kurochko
2026-09-04 12:03 ` Jan Beulich
2026-09-02 12:31 ` Baptiste Le Duc
2026-09-04 14:02 ` Oleksii Kurochko
2026-09-09 14:26 ` Jan Beulich
2026-09-10 10:37 ` Oleksii Kurochko
2026-09-10 11:14 ` Jan Beulich
2026-09-10 14:24 ` Oleksii Kurochko
2026-09-12 8:50 ` SeungJu Cheon
2026-08-27 15:20 ` [PATCH v2 10/39] xen/riscv: build the target hart index via aplic_hart_field() Oleksii Kurochko
2026-09-04 8:26 ` Baptiste Le Duc
2026-09-04 14:28 ` Oleksii Kurochko
2026-09-09 14:51 ` Jan Beulich
2026-09-09 14:52 ` Jan Beulich
2026-09-10 10:59 ` Oleksii Kurochko
2026-09-10 11:23 ` Jan Beulich
2026-09-10 11:23 ` Jan Beulich
2026-09-10 12:44 ` Oleksii Kurochko
2026-09-10 12:57 ` Jan Beulich
2026-09-11 9:47 ` Oleksii Kurochko
2026-08-27 15:20 ` [PATCH v2 11/39] xen/riscv: add helper to check APLIC MSI mode Oleksii Kurochko
2026-09-04 8:26 ` Baptiste Le Duc
2026-09-09 14:53 ` Jan Beulich
2026-08-27 15:20 ` [PATCH v2 12/39] xen/riscv: implement vCPU context switching Oleksii Kurochko
2026-09-02 14:42 ` Oleksii Kurochko
2026-09-04 8:26 ` Baptiste Le Duc
2026-09-04 8:33 ` Jan Beulich
2026-09-04 9:54 ` Baptiste Le Duc
2026-09-04 14:55 ` Oleksii Kurochko
2026-09-07 8:17 ` Jan Beulich
2026-09-08 9:06 ` Oleksii Kurochko
2026-09-05 7:25 ` Oleksii Kurochko [this message]
2026-09-10 13:29 ` Jan Beulich
2026-09-11 10:43 ` Oleksii Kurochko
2026-08-27 15:20 ` [PATCH v2 13/39] xen/riscv: save and restore AIA state on vCPU context switch Oleksii Kurochko
2026-09-04 9:52 ` Baptiste Le Duc
2026-09-04 16:40 ` Oleksii Kurochko
2026-08-27 15:20 ` [PATCH v2 14/39] xen/riscv: introduce vintc_ctxt_switch_{from,to}() Oleksii Kurochko
2026-09-04 11:25 ` Baptiste Le Duc
2026-09-04 16:54 ` Oleksii Kurochko
2026-09-10 14:54 ` Jan Beulich
2026-08-27 15:20 ` [PATCH v2 15/39] xen/riscv: add IMSIC vCPU context switch handlers Oleksii Kurochko
2026-09-04 11:33 ` Baptiste Le Duc
2026-09-04 16:56 ` Oleksii Kurochko
2026-09-10 14:57 ` Jan Beulich
2026-09-11 11:19 ` Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 16/39] xen/riscv: extend exception tables with type and data fields Oleksii Kurochko
2026-09-07 15:57 ` Baptiste Le Duc
2026-09-08 6:06 ` Jan Beulich
2026-09-08 8:18 ` Baptiste Le Duc
2026-09-08 9:19 ` Oleksii Kurochko
2026-09-08 16:26 ` Baptiste Le Duc
2026-09-08 13:44 ` Jan Beulich
2026-09-09 11:20 ` Oleksii Kurochko
2026-09-09 12:22 ` Jan Beulich
2026-09-09 12:42 ` Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 17/39] xen/riscv: decouple INSN_PSEUDO_VS_* from the hypervisor's XLEN Oleksii Kurochko
2026-09-07 15:57 ` Baptiste Le Duc
2026-09-08 9:34 ` Oleksii Kurochko
2026-09-08 16:04 ` Baptiste Le Duc
2026-09-09 12:57 ` Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 18/39] xen/riscv: add guest page fault handling stub Oleksii Kurochko
2026-09-07 15:57 ` Baptiste Le Duc
2026-09-08 9:49 ` Oleksii Kurochko
2026-09-08 14:10 ` Jan Beulich
2026-09-09 15:09 ` Oleksii Kurochko
2026-09-10 6:38 ` Jan Beulich
2026-09-11 11:47 ` Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 19/39] xen/riscv: implement trap redirection to a guest Oleksii Kurochko
2026-09-07 15:57 ` Baptiste Le Duc
2026-09-08 10:01 ` Oleksii Kurochko
2026-09-08 14:58 ` Oleksii Kurochko
2026-09-08 15:05 ` Jan Beulich
2026-09-08 15:47 ` Baptiste Le Duc
2026-09-08 15:58 ` Jan Beulich
2026-09-08 14:16 ` Jan Beulich
2026-09-08 15:25 ` Oleksii Kurochko
2026-09-08 14:16 ` Jan Beulich
2026-08-27 15:21 ` [PATCH v2 20/39] xen/riscv: detect Shtvala Oleksii Kurochko
2026-09-07 15:57 ` Baptiste Le Duc
2026-09-08 10:15 ` Oleksii Kurochko
2026-09-08 15:49 ` Baptiste Le Duc
2026-08-27 15:21 ` [PATCH v2 21/39] xen/riscv: resolve the faulting guest physical address Oleksii Kurochko
2026-09-09 12:04 ` Baptiste Le Duc
2026-09-11 12:56 ` Oleksii Kurochko
2026-09-10 15:06 ` Jan Beulich
2026-08-27 15:21 ` [PATCH v2 22/39] xen/riscv: add guest memory read helper Oleksii Kurochko
2026-09-09 12:04 ` Baptiste Le Duc
2026-09-10 15:19 ` Jan Beulich
2026-09-11 13:06 ` Oleksii Kurochko
2026-09-11 13:41 ` Oleksii Kurochko
2026-09-11 13:47 ` Jan Beulich
2026-09-11 13:50 ` Oleksii Kurochko
2026-09-10 15:28 ` Jan Beulich
2026-09-11 13:57 ` Oleksii Kurochko
2026-09-11 14:00 ` Jan Beulich
2026-09-11 14:29 ` Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 23/39] xen/riscv: look up the exception table for any trap taken in Xen context Oleksii Kurochko
2026-09-10 15:31 ` Jan Beulich
2026-08-27 15:21 ` [PATCH v2 24/39] xen/riscv: add helpers for decoding a trapped load or store Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 25/39] xen/riscv: add guest load emulation for trapped MMIO accesses Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 26/39] xen/riscv: add guest store " Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 27/39] xen/riscv: introduce arch_move_irqs() Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 28/39] xen/riscv: handle the case when no vCPU migration is needed Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 29/39] xen/riscv: introduce aplic_reconfigure_target() Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 30/39] xen/riscv: prepare new IMSIC VS-file Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 31/39] xen/riscv: implement APLIC-hart sync barrier for vCPU migration Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 32/39] xen/riscv: remap interrupts to new IMSIC VS-file Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 33/39] xen/riscv: dump old interrupt file to memory Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 34/39] xen/riscv: restore register state in the new IMSIC VS-file Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 35/39] xen/riscv: add basic VGEIN management for AIA guests Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 36/39] xen/riscv: wake up a descheduled vCPU on a guest external interrupt Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 37/39] xen/riscv: map IMSIC interrupt file for vCPUs Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 38/39] xen/riscv: implement continue_new_vcpu() Oleksii Kurochko
2026-08-27 15:21 ` [PATCH v2 39/39] xen/riscv: introduce IMSIC h/w interrupt file attaching to vcpu Oleksii Kurochko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9267476f-c6a0-4cfb-b128-10c475d2d5a6@gmail.com \
--to=oleksii.kurochko@gmail.com \
--cc=Romain.Caritey@microchip.com \
--cc=alistair.francis@wdc.com \
--cc=andrew.cooper3@citrix.com \
--cc=anthony.perard@vates.tech \
--cc=baptiste.le-duc@vates.tech \
--cc=connojdavis@gmail.com \
--cc=jbeulich@suse.com \
--cc=julien@xen.org \
--cc=michal.orzel@amd.com \
--cc=roger@xenproject.org \
--cc=sstabellini@kernel.org \
--cc=xen-devel@lists.xenproject.org \
--cc=zhangzheng@iscas.ac.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.