From 45581e9c2ae8a276719969841a1d48c07627c4ae Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Mon, 13 Jan 2025 21:37:17 +0800 Subject: [PATCH 1/2] LoongArch: KVM: Clear LLBCTL if secondary mmu mapping is changed commit 4d38d0416ece7bab532e89a49f988a9954f12ee9 upstream LLBCTL is a separated guest CSR register from host, host exception ERET instruction will clear the host LLBCTL CSR register, and guest exception will clear the guest LLBCTL CSR register. VCPU0 atomic64_fetch_add_unless VCPU1 atomic64_fetch_add_unless ll.d %[p], %[c] beq %[p], %[u], 1f Here secondary mmu mapping is changed, host hpa page is replaced with a new page. And VCPU1 will execute atomic instruction on the new page. ll.d %[p], %[c] beq %[p], %[u], 1f add.d %[rc], %[p], %[a] sc.d %[rc], %[c] add.d %[rc], %[p], %[a] sc.d %[rc], %[c] LLBCTL is set on VCPU0 and it represents the memory is not modified by other VCPUs, sc.d will modify the memory directly. So clear WCLLB of the guest LLBCTL register when mapping is the changed. Fixes: ("LoongArch:LSVZ: Clear LLBCTL if secondary mmu mapping is changed") Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen Signed-off-by: Xianglai Li Change-Id: I6db0b913a2a56021153078b896396b825e544545 Signed-off-by: Ming Wang --- arch/loongarch/kvm/main.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c index ef2bad612c00..3dddf3c8f222 100644 --- a/arch/loongarch/kvm/main.c +++ b/arch/loongarch/kvm/main.c @@ -246,20 +246,22 @@ void kvm_check_vpid(struct kvm_vcpu *vcpu) vcpu->cpu = cpu; kvm_clear_request(KVM_REQ_TLB_FLUSH_GPA, vcpu); /* - * LLBCTL_WCLLB is separated CSR register from host - * eret instruction in host mode clears host LLBCTL_WCLLB - * register, and clears guest register in guest mode + * LLBCTL is a separated guest CSR register from host, a general + * exception ERET instruction clears the host LLBCTL register in + * host mode, and clears the guest LLBCTL register in guest mode. + * ERET in tlb refill exception does not clear LLBCTL register. * - * When gpa --> hpa mapping is changed, guest does not know - * even if the content is changed with new address + * When secondary mmu mapping is changed, guest OS does not know + * even if the content is changed after mapping is changed. * - * Here clear guest LLBCTL_WCLLB register when mapping is - * changed, else if mapping is changed when guest is executing - * LL/SC pair, LL loads old address, SC store new address - * successfully since LLBCTL_WCLLB is on, even if memory - * with new address is changed with other VCPUs. + * Here clear WCLLB of the guest LLBCTL register when mapping is + * changed. Otherwise, if mmu mapping is changed while guest is + * executing LL/SC pair, LL loads with the old address and set + * the LLBCTL flag, SC checks the LLBCTL flag and will store the + * new address successfully since LLBCTL_WCLLB is on, even if + * memory with new address is changed on other VCPUs. */ - set_gcsr_llbctl(LOONGARCH_CSR_LLBCTL); + set_gcsr_llbctl(CSR_LLBCTL_WCLLB); } /* Restore GSTAT(0x50).vpid */ -- Gitee From 075d7348c3d26c94370cc4dff1fd5c8acfc75133 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 26 Dec 2025 18:35:40 +0800 Subject: [PATCH 2/2] LoongArch: Fix AP booting issue in VM mode commit 6ce031e5d6f475d476bab55ab7d8ea168fedc4c1 upstream Native IPI is used for AP booting, because it is the booting interface between OS and BIOS firmware. The paravirt IPI is only used inside OS, and native IPI is necessary to boot AP. When booting AP, we write the kernel entry address in the HW mailbox of AP and send IPI interrupt to it. AP executes idle instruction and waits for interrupts or SW events, then clears IPI interrupt and jumps to the kernel entry from HW mailbox. Between writing HW mailbox and sending IPI, AP can be woken up by SW events and jumps to the kernel entry, so ACTION_BOOT_CPU IPI interrupt will keep pending during AP booting. And native IPI interrupt handler needs be registered so that it can clear pending native IPI, else there will be endless interrupts during AP booting stage. Here native IPI interrupt is initialized even if paravirt IPI is used. Cc: stable@vger.kernel.org Fixes: ("LoongArch: KVM: Add PV IPI support on guest side") Signed-off-by: Bibo Mao Signed-off-by: Huacai Chen Signed-off-by: Xianglai Li --- arch/loongarch/kernel/paravirt.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c index 9cc27c3feb69..56690e025258 100644 --- a/arch/loongarch/kernel/paravirt.c +++ b/arch/loongarch/kernel/paravirt.c @@ -50,11 +50,18 @@ static u64 paravt_steal_clock(int cpu) } #ifdef CONFIG_SMP +static struct smp_ops native_ops; + static void pv_send_ipi_single(int cpu, unsigned int action) { int min, old; irq_cpustat_t *info = &per_cpu(irq_stat, cpu); + if (unlikely(action == ACTION_BOOT_CPU)) { + native_ops.send_ipi_single(cpu, action); + return; + } + old = atomic_fetch_or(BIT(action), &info->message); if (old) return; @@ -74,6 +81,11 @@ static void pv_send_ipi_mask(const struct cpumask *mask, unsigned int action) if (cpumask_empty(mask)) return; + if (unlikely(action == ACTION_BOOT_CPU)) { + native_ops.send_ipi_mask(mask, action); + return; + } + action = BIT(action); for_each_cpu(i, mask) { info = &per_cpu(irq_stat, i); @@ -106,7 +118,7 @@ static void pv_send_ipi_mask(const struct cpumask *mask, unsigned int action) if (bitmap) kvm_hypercall3(KVM_HCALL_FUNC_IPI, (unsigned long)bitmap, - (unsigned long)(bitmap >> BITS_PER_LONG), min); + (unsigned long)(bitmap >> BITS_PER_LONG), min); } static irqreturn_t pv_ipi_interrupt(int irq, void *dev) @@ -129,6 +141,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev) info->ipi_irqs[IPI_CALL_FUNCTION]++; } + if (action & SMP_CLEAR_VECTOR) { + complete_irq_moving(); + info->ipi_irqs[IPI_CLEAR_VECTOR]++; + } + return IRQ_HANDLED; } @@ -136,6 +153,8 @@ static void pv_init_ipi(void) { int r, swi; + /* Init native ipi irq for ACTION_BOOT_CPU */ + native_ops.init_ipi(); swi = get_percpu_irq(INT_SWI0); if (swi < 0) panic("SWI0 IRQ mapping failed\n"); @@ -182,6 +201,7 @@ int __init pv_ipi_init(void) return 0; #ifdef CONFIG_SMP + native_ops = smp_ops; smp_ops.init_ipi = pv_init_ipi; smp_ops.send_ipi_single = pv_send_ipi_single; smp_ops.send_ipi_mask = pv_send_ipi_mask; -- Gitee