|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 12/39] xen/riscv: implement vCPU context switching
On 9/10/26 3:29 PM, Jan Beulich wrote: On 27.08.2026 17:20, Oleksii Kurochko wrote: x86 does have the equivalent: vmx_do_resume() calls hvm_asid_flush_vcpu() in the active_cpu != smp_processor_id() branch, and svm_do_resume() does the same when launch_core != smp_processor_id() ("Migrating to another ASID domain. Request a new ASID."). The RISC-V VMID allocator follows the x86 ASID scheme: VMIDs are a per-pCPU resource with a per-pCPU generation, so a (generation, vmid) pair obtained on one pCPU means nothing on another. Arm doesn't need this because it allocates a single VMID per domain from a global bitmap. Also, note that I've update a little bit how VMIDs are flushed here [1] but this check still present IIURC.[1] https://lore.kernel.org/xen-devel/cover.1787838835.git.oleksii.kurochko@xxxxxxxxx/T/#m2c06e58c03a09022af112388be3585bf3ae6e4dc + vtimer_ctxt_switch_to(n); + + restore_csr_regs(n); + + p2m_ctxt_switch_to(n); +}In the absenmce of a comment towards the need for this specific order I'd expect these three calls to be ordered the opposite of their counterparts in ctxt_switch_from(). I will put restore_csr_regs(n) (and rename it to csr_regs_ctxt_switch_to(n)) before vtimer_ctxt_switch_to(). There is no any specific requirement to be ordered in the way it is now.
RISC-V will have reset_stack_and_jump() that too but just introduced later and will be used for different use case (in continue_new_vcpu() introduced later in this patch series). But as the Arm RISC-V doesn't use reset_stack_and_jump() in context_switch(). This follows the Arm model: every vCPU has its own Xen stack, and from the incoming vCPU's point of view __context_switch() is ABI-conforming. It restores exactly the sp/ra/s0-s11 that vCPU had when it itself called __context_switch() from context_switch(). So after the return we are in next's own context_switch() frame, and anything the compiler spilled there (ra included) belongs to next. The only exception is a vCPU which has never run: its ra points at continue_new_vcpu() on an empty stack, and that's where reset_stack_and_jump() is needed, as on Arm. I'll make continue_new_vcpu() noreturn accordingly. x86 differs because its stacks are per-pCPU (IIUC), hence its context_switch() can't return.
Here is some diagram for better understanding:
vCPU A (stack A) vCPU B (stack B, switched out earlier)
schedule() schedule()
`- context_switch(A, B) `- context_switch(B, X)
[A's frame: ra, s-regs] [B's frame: ra, s-regs]
`- __context_switch() --------> "returns" here
(save A, load B) schedule_tail(prev = A)
ld ra <- B's frame (B's own ra)
ret -> B's sched_context_switch()
-> ... -> back into B
--- a/xen/arch/riscv/entry.S +++ b/xen/arch/riscv/entry.S @@ -99,3 +99,47 @@ restore_registers:sretEND(handle_trap) + +/* + * struct vcpu *__context_switch(struct vcpu *prev, struct vcpu *next) + * + * This is called on prev's stack, and returns on next's.With ra being switched it may also return to other than the caller. If that's really intended, I think it also needs calling out here. Yes, it's intended. Normally it returns into next's own context_switch() (where next itself last called __context_switch()), and for a vCPU which has never run it returns to continue_new_vcpu(). I'll update the comment to: * This is called on prev's stack, and returns on next's. As ra is * switched too, it doesn't return to its caller: it returns to where * next last called it from, i.e. into next's own context_switch(), or, * for a vCPU which has never run, to continue_new_vcpu() with an empty * stack. + * a0 - prev + * a1 - next + * + * Returns prev in a0 + */ +FUNC(__context_switch) + REG_S s0, VCPU_XEN_SAVED_CONTEXT_S0(a0) + REG_S s1, VCPU_XEN_SAVED_CONTEXT_S1(a0) + REG_S s2, VCPU_XEN_SAVED_CONTEXT_S2(a0) + REG_S s3, VCPU_XEN_SAVED_CONTEXT_S3(a0) + REG_S s4, VCPU_XEN_SAVED_CONTEXT_S4(a0) + REG_S s5, VCPU_XEN_SAVED_CONTEXT_S5(a0) + REG_S s6, VCPU_XEN_SAVED_CONTEXT_S6(a0) + REG_S s7, VCPU_XEN_SAVED_CONTEXT_S7(a0) + REG_S s8, VCPU_XEN_SAVED_CONTEXT_S8(a0) + REG_S s9, VCPU_XEN_SAVED_CONTEXT_S9(a0) + REG_S s10, VCPU_XEN_SAVED_CONTEXT_S10(a0) + REG_S s11, VCPU_XEN_SAVED_CONTEXT_S11(a0) + REG_S sp, VCPU_XEN_SAVED_CONTEXT_SP(a0) + REG_S ra, VCPU_XEN_SAVED_CONTEXT_RA(a0) + + REG_L s0, VCPU_XEN_SAVED_CONTEXT_S0(a1) + REG_L s1, VCPU_XEN_SAVED_CONTEXT_S1(a1) + REG_L s2, VCPU_XEN_SAVED_CONTEXT_S2(a1) + REG_L s3, VCPU_XEN_SAVED_CONTEXT_S3(a1) + REG_L s4, VCPU_XEN_SAVED_CONTEXT_S4(a1) + REG_L s5, VCPU_XEN_SAVED_CONTEXT_S5(a1) + REG_L s6, VCPU_XEN_SAVED_CONTEXT_S6(a1) + REG_L s7, VCPU_XEN_SAVED_CONTEXT_S7(a1) + REG_L s8, VCPU_XEN_SAVED_CONTEXT_S8(a1) + REG_L s9, VCPU_XEN_SAVED_CONTEXT_S9(a1) + REG_L s10, VCPU_XEN_SAVED_CONTEXT_S10(a1) + REG_L s11, VCPU_XEN_SAVED_CONTEXT_S11(a1) + REG_L sp, VCPU_XEN_SAVED_CONTEXT_SP(a1) + REG_L ra, VCPU_XEN_SAVED_CONTEXT_RA(a1) + + ret +END(__context_switch)What about gp and tp? tp points to this hart's pcpu_info (set up once per hart by setup_tp()), i.e. it's per-pCPU rather than per-vCPU state. __context_switch() starts and ends on the same hart, so tp has to be left alone. gp isn't used by Xen at all: there's no __global_pointer$ in the linker script, so no gp-relative relaxation happens, and the compiler never allocates gp. Neither of them is callee-saved per the psABI, so there's nothing to preserve across the call. The guest's gp/tp are part of the guest state and are going to be saved/restored via cpu_user_regs by the trap entry/exit path. --- a/xen/arch/riscv/include/asm/system.h +++ b/xen/arch/riscv/include/asm/system.h @@ -76,6 +76,10 @@ static inline bool local_irq_is_enabled(void)#define arch_fetch_and_add(x, v) __sync_fetch_and_add(x, v) +struct vcpu;I don't think this is needed, as ...+struct vcpu *__context_switch(struct vcpu *prev, struct vcpu *next);... parsing of the return type will make the struct known (before parameters are parsed). Make sense to me. I will drop forward declaration. Also - can't next be pointer-to-const? It could be. I will add const. Thanks! ~ Oleksii
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |