@@ -91,6 +91,9 @@ struct kvm_arch {
/* G-stage vmid */
struct kvm_vmid vmid;
+ /* Last VCPU that ran on each physical CPU */
+ int __percpu *last_vcpu_ran;
+
/* G-stage page table */
pgd_t *pgd;
phys_addr_t pgd_phys;
@@ -330,7 +333,4 @@ bool kvm_riscv_vcpu_stopped(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu);
-/* Flags representing implementation specific details */
-DECLARE_STATIC_KEY_FALSE(kvm_riscv_vsstage_tlb_no_gpa);
-
#endif /* __RISCV_KVM_HOST_H__ */
@@ -10,23 +10,10 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/kvm_host.h>
-#include <asm/cpufeature.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_nacl.h>
#include <asm/sbi.h>
-DEFINE_STATIC_KEY_FALSE(kvm_riscv_vsstage_tlb_no_gpa);
-
-static void kvm_riscv_setup_vendor_features(void)
-{
- /* Andes AX66: split two-stage TLBs */
- if (riscv_cached_mvendorid(0) == ANDES_VENDOR_ID &&
- (riscv_cached_marchid(0) & 0xFFFF) == 0x8A66) {
- static_branch_enable(&kvm_riscv_vsstage_tlb_no_gpa);
- kvm_info("VS-stage TLB does not cache guest physical address and VMID\n");
- }
-}
-
long kvm_arch_dev_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -172,8 +159,6 @@ static int __init riscv_kvm_init(void)
kvm_info("AIA available with %d guest external interrupts\n",
kvm_riscv_aia_nr_hgei);
- kvm_riscv_setup_vendor_features();
-
kvm_register_perf_callbacks();
rc = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE);
@@ -8,6 +8,7 @@
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/percpu.h>
#include <linux/smp.h>
#include <linux/kvm_host.h>
#include <asm/cacheflush.h>
@@ -160,12 +161,19 @@ void kvm_riscv_local_hfence_vvma_all(unsigned long vmid)
void kvm_riscv_local_tlb_sanitize(struct kvm_vcpu *vcpu)
{
+ bool vcpu_migrated;
+ bool vcpu_switched;
unsigned long vmid;
+ int *last_ran;
- if (!kvm_riscv_gstage_vmid_bits() ||
- vcpu->arch.last_exit_cpu == vcpu->cpu)
+ last_ran = this_cpu_ptr(vcpu->kvm->arch.last_vcpu_ran);
+ vcpu_migrated = (vcpu->arch.last_exit_cpu != vcpu->cpu);
+ vcpu_switched = (*last_ran != vcpu->vcpu_idx);
+ if (!vcpu_migrated && !vcpu_switched)
return;
+ vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid);
+
/*
* On RISC-V platforms with hardware VMID support, we share same
* VMID for all VCPUs of a particular Guest/VM. This means we might
@@ -176,16 +184,23 @@ void kvm_riscv_local_tlb_sanitize(struct kvm_vcpu *vcpu)
* To cleanup stale TLB entries, we simply flush all G-stage TLB
* entries by VMID whenever underlying Host CPU changes for a VCPU.
*/
-
- vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid);
- kvm_riscv_local_hfence_gvma_vmid_all(vmid);
+ if (vcpu_migrated && kvm_riscv_gstage_vmid_bits())
+ kvm_riscv_local_hfence_gvma_vmid_all(vmid);
/*
- * Flush VS-stage TLB entries for implementation where VS-stage
- * TLB does not cahce guest physical address and VMID.
+ * Guest-local sfence.vma only invalidates VS-stage translations on
+ * the Host CPU currently backing the VCPU. If a VCPU migrates, or
+ * if this Host CPU switches between VCPUs of the same VM, stale
+ * VS-stage entries can be left behind on a Host CPU that missed a
+ * guest-local flush. Flush the current CPU's VS-stage context before
+ * entering the guest.
*/
- if (static_branch_unlikely(&kvm_riscv_vsstage_tlb_no_gpa))
+ if (kvm_riscv_nacl_available())
+ nacl_hfence_vvma_all(nacl_shmem(), vmid);
+ else
kvm_riscv_local_hfence_vvma_all(vmid);
+
+ *last_ran = vcpu->vcpu_idx;
}
void kvm_riscv_fence_i_process(struct kvm_vcpu *vcpu)
@@ -9,6 +9,7 @@
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/percpu.h>
#include <linux/uaccess.h>
#include <linux/kvm_host.h>
#include <asm/kvm_mmu.h>
@@ -30,7 +31,9 @@ const struct kvm_stats_header kvm_vm_stats_header = {
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
{
+ int *last_ran;
int r;
+ int cpu;
r = kvm_riscv_mmu_alloc_pgd(kvm);
if (r)
@@ -42,6 +45,17 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
return r;
}
+ kvm->arch.last_vcpu_ran = alloc_percpu(int);
+ if (!kvm->arch.last_vcpu_ran) {
+ kvm_riscv_mmu_free_pgd(kvm);
+ return -ENOMEM;
+ }
+
+ for_each_possible_cpu(cpu) {
+ last_ran = per_cpu_ptr(kvm->arch.last_vcpu_ran, cpu);
+ *last_ran = -1;
+ }
+
kvm_riscv_aia_init_vm(kvm);
kvm_riscv_guest_timer_init(kvm);
@@ -54,6 +68,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvm_destroy_vcpus(kvm);
kvm_riscv_aia_destroy_vm(kvm);
+
+ free_percpu(kvm->arch.last_vcpu_ran);
}
int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irql,