* Re: [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes
[not found] <201701111154365057441@zte.com.cn>
@ 2017-01-11 8:34 ` Ralf Baechle
2017-01-16 16:07 ` James Hogan
1 sibling, 0 replies; 5+ messages in thread
From: Ralf Baechle @ 2017-01-11 8:34 UTC (permalink / raw)
To: jiang.biao2; +Cc: james.hogan, linux-mips, pbonzini, rkrcmar, kvm
On Wed, Jan 11, 2017 at 11:54:36AM +0800, jiang.biao2@zte.com.cn wrote:
> Date: Wed, 11 Jan 2017 11:54:36 +0800 (CST)
> From: jiang.biao2@zte.com.cn
> To: james.hogan@imgtec.com
> Cc: linux-mips@linux-mips.org, james.hogan@imgtec.com, pbonzini@redhat.com,
> rkrcmar@redhat.com, ralf@linux-mips.org, kvm@vger.kernel.org
> Subject: Re: [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes
> Content-Type: multipart/mixed; boundary="=====_001_next====="
>
> Hi,
>
>
> > +void kvm_mips_flush_gva_pt(pgd_t *pgd, enum kvm_mips_flush flags)
>
> > +{
>
> > + if (flags & KMF_GPA) {
>
> > + /* all of guest virtual address space could be affected */
> > + if (flags & KMF_KERN)
> > + /* useg, kseg0, seg2/3 */
> > + kvm_mips_flush_gva_pgd(pgd, 0, 0x7fffffff);
> > + else
> > + /* useg */
> > + kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff);
> > + } else {
> > + /* useg */
> > + kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff);
> > +
> > + /* kseg2/3 */
> > + if (flags & KMF_KERN)
> > + kvm_mips_flush_gva_pgd(pgd, 0x60000000, 0x7fffffff);
> > + }
>
> > +}
>
>
> Is it maybe better to replace the hard code *0x7fffffff*, *0x60000000*,
> *0x3fffffff* with marco?
I think to anybody familiar with the architecture the raw numbers are
easier to understand than weird defines.
Ralf
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes
[not found] <201701111154365057441@zte.com.cn>
2017-01-11 8:34 ` [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes Ralf Baechle
@ 2017-01-16 16:07 ` James Hogan
2017-01-16 16:07 ` James Hogan
1 sibling, 1 reply; 5+ messages in thread
From: James Hogan @ 2017-01-16 16:07 UTC (permalink / raw)
To: jiang.biao2; +Cc: linux-mips, pbonzini, rkrcmar, ralf, kvm
Hi,
On Wed, Jan 11, 2017 at 11:54:36AM +0800, jiang.biao2@zte.com.cn wrote:
> > +void kvm_mips_flush_gva_pt(pgd_t *pgd, enum kvm_mips_flush flags)
> > +{
>
> > + if (flags & KMF_GPA) {
>
> > + /* all of guest virtual address space could be affected */
> > + if (flags & KMF_KERN)
> > + /* useg, kseg0, seg2/3 */
> > + kvm_mips_flush_gva_pgd(pgd, 0, 0x7fffffff)
> > + else
> > + /* useg */
> > + kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff)
> > + } else {
> > + /* useg */
> > + kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff)
> > +
> > + /* kseg2/3 */
> > + if (flags & KMF_KERN)
> > + kvm_mips_flush_gva_pgd(pgd, 0x60000000, 0x7fffffff)
> > + }
> > +}
>
>
>
>
> Is it maybe better to replace the hard code *0x7fffffff*, *0x60000000*, *0x3fffffff* with marco?
I did consider it. E.g. there are definitions in kvm_host.h:
#define KVM_GUEST_KUSEG 0x00000000UL
#define KVM_GUEST_KSEG0 0x40000000UL
#define KVM_GUEST_KSEG1 0x40000000UL
#define KVM_GUEST_KSEG23 0x60000000UL
and conditional definitions in asm/addrspace.h:
64-bit:
#define CKSEG0 _CONST64_(0xffffffff80000000)
#define CKSEG1 _CONST64_(0xffffffffa0000000)
#define CKSSEG _CONST64_(0xffffffffc0000000)
#define CKSEG3 _CONST64_(0xffffffffe0000000)
32-bit:
#define KUSEG 0x00000000
#define KSEG0 0x80000000
#define KSEG1 0xa0000000
#define KSEG2 0xc0000000
#define KSEG3 0xe0000000
#define CKUSEG 0x00000000
#define CKSEG0 0x80000000
#define CKSEG1 0xa0000000
#define CKSEG2 0xc0000000
#define CKSEG3 0xe0000000
So (u32)CKSEG0 - 1, KVM_GUEST_KSEG23, and KVM_GUEST_KSEG0 - 1 would have
worked, but given that the ranges sometimes cover multiple segments it
just seemed more readable to use the hex literals rather than a
sprinkling of opaque definitions from different places.
Thanks for reviewing!
Cheers
James
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes
2017-01-16 16:07 ` James Hogan
@ 2017-01-16 16:07 ` James Hogan
0 siblings, 0 replies; 5+ messages in thread
From: James Hogan @ 2017-01-16 16:07 UTC (permalink / raw)
To: jiang.biao2; +Cc: linux-mips, pbonzini, rkrcmar, ralf, kvm
Hi,
On Wed, Jan 11, 2017 at 11:54:36AM +0800, jiang.biao2@zte.com.cn wrote:
> > +void kvm_mips_flush_gva_pt(pgd_t *pgd, enum kvm_mips_flush flags)
> > +{
>
> > + if (flags & KMF_GPA) {
>
> > + /* all of guest virtual address space could be affected */
> > + if (flags & KMF_KERN)
> > + /* useg, kseg0, seg2/3 */
> > + kvm_mips_flush_gva_pgd(pgd, 0, 0x7fffffff)
> > + else
> > + /* useg */
> > + kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff)
> > + } else {
> > + /* useg */
> > + kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff)
> > +
> > + /* kseg2/3 */
> > + if (flags & KMF_KERN)
> > + kvm_mips_flush_gva_pgd(pgd, 0x60000000, 0x7fffffff)
> > + }
> > +}
>
>
>
>
> Is it maybe better to replace the hard code *0x7fffffff*, *0x60000000*, *0x3fffffff* with marco?
I did consider it. E.g. there are definitions in kvm_host.h:
#define KVM_GUEST_KUSEG 0x00000000UL
#define KVM_GUEST_KSEG0 0x40000000UL
#define KVM_GUEST_KSEG1 0x40000000UL
#define KVM_GUEST_KSEG23 0x60000000UL
and conditional definitions in asm/addrspace.h:
64-bit:
#define CKSEG0 _CONST64_(0xffffffff80000000)
#define CKSEG1 _CONST64_(0xffffffffa0000000)
#define CKSSEG _CONST64_(0xffffffffc0000000)
#define CKSEG3 _CONST64_(0xffffffffe0000000)
32-bit:
#define KUSEG 0x00000000
#define KSEG0 0x80000000
#define KSEG1 0xa0000000
#define KSEG2 0xc0000000
#define KSEG3 0xe0000000
#define CKUSEG 0x00000000
#define CKSEG0 0x80000000
#define CKSEG1 0xa0000000
#define CKSEG2 0xc0000000
#define CKSEG3 0xe0000000
So (u32)CKSEG0 - 1, KVM_GUEST_KSEG23, and KVM_GUEST_KSEG0 - 1 would have
worked, but given that the ranges sometimes cover multiple segments it
just seemed more readable to use the hex literals rather than a
sprinkling of opaque definitions from different places.
Thanks for reviewing!
Cheers
James
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes
2017-01-06 1:32 [PATCH 0/30] KVM: MIPS: Implement GVA page tables James Hogan
@ 2017-01-06 1:32 ` James Hogan
2017-01-06 1:32 ` James Hogan
0 siblings, 1 reply; 5+ messages in thread
From: James Hogan @ 2017-01-06 1:32 UTC (permalink / raw)
To: linux-mips
Cc: James Hogan, Paolo Bonzini, Radim Krčmář,
Ralf Baechle, kvm
Implement invalidation of large ranges of virtual addresses from GVA
page tables in response to a guest ASID change (immediately for guest
kernel page table, lazily for guest user page table).
We iterate through a range of page tables invalidating entries and
freeing fully invalidated tables. To minimise overhead the exact ranges
invalidated depends on the flags argument to kvm_mips_flush_gva_pt(),
which also allows it to be used in future KVM_CAP_SYNC_MMU patches in
response to GPA changes, which unlike guest TLB mapping changes affects
guest KSeg0 mappings.
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
---
arch/mips/include/asm/kvm_host.h | 18 ++++-
arch/mips/kvm/emulate.c | 11 +++-
arch/mips/kvm/mmu.c | 134 ++++++++++++++++++++++++++++++++-
arch/mips/kvm/trap_emul.c | 5 +-
4 files changed, 166 insertions(+), 2 deletions(-)
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index e2bbcfbf2d34..44554241f158 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -610,6 +610,24 @@ extern int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long entryhi,
extern int kvm_mips_guest_tlb_lookup(struct kvm_vcpu *vcpu,
unsigned long entryhi);
extern int kvm_mips_host_tlb_lookup(struct kvm_vcpu *vcpu, unsigned long vaddr);
+
+/* MMU handling */
+
+/**
+ * enum kvm_mips_flush - Types of MMU flushes.
+ * @KMF_USER: Flush guest user virtual memory mappings.
+ * Guest USeg only.
+ * @KMF_KERN: Flush guest kernel virtual memory mappings.
+ * Guest USeg and KSeg2/3.
+ * @KMF_GPA: Flush guest physical memory mappings.
+ * Also includes KSeg0 if KMF_KERN is set.
+ */
+enum kvm_mips_flush {
+ KMF_USER = 0x0,
+ KMF_KERN = 0x1,
+ KMF_GPA = 0x2,
+};
+void kvm_mips_flush_gva_pt(pgd_t *pgd, enum kvm_mips_flush flags);
extern unsigned long kvm_mips_translate_guest_kseg0_to_hpa(struct kvm_vcpu *vcpu,
unsigned long gva);
extern void kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu,
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index 611b8996ca0c..1d399396e486 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -1172,6 +1172,17 @@ enum emulation_result kvm_mips_emulate_CP0(union mips_instruction inst,
nasid);
/*
+ * Flush entries from the GVA page
+ * tables.
+ * Guest user page table will get
+ * flushed lazily on re-entry to guest
+ * user if the guest ASID actually
+ * changes.
+ */
+ kvm_mips_flush_gva_pt(kern_mm->pgd,
+ KMF_KERN);
+
+ /*
* Regenerate/invalidate kernel MMU
* context.
* The user MMU context will be
diff --git a/arch/mips/kvm/mmu.c b/arch/mips/kvm/mmu.c
index 27d6d0dbfeb4..09146b62552f 100644
--- a/arch/mips/kvm/mmu.c
+++ b/arch/mips/kvm/mmu.c
@@ -12,6 +12,7 @@
#include <linux/highmem.h>
#include <linux/kvm_host.h>
#include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
static u32 kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu)
{
@@ -80,6 +81,139 @@ unsigned long kvm_mips_translate_guest_kseg0_to_hpa(struct kvm_vcpu *vcpu,
return (kvm->arch.guest_pmap[gfn] << PAGE_SHIFT) + offset;
}
+/*
+ * kvm_mips_flush_gva_{pte,pmd,pud,pgd,pt}.
+ * Flush a range of guest physical address space from the VM's GPA page tables.
+ */
+
+static bool kvm_mips_flush_gva_pte(pte_t *pte, unsigned long start_gva,
+ unsigned long end_gva)
+{
+ int i_min = __pte_offset(start_gva);
+ int i_max = __pte_offset(end_gva);
+ bool safe_to_remove = (i_min == 0 && i_max == PTRS_PER_PTE - 1);
+ int i;
+
+ /*
+ * There's no freeing to do, so there's no point clearing individual
+ * entries unless only part of the last level page table needs flushing.
+ */
+ if (safe_to_remove)
+ return true;
+
+ for (i = i_min; i <= i_max; ++i) {
+ if (!pte_present(pte[i]))
+ continue;
+
+ set_pte(pte + i, __pte(0));
+ }
+ return false;
+}
+
+static bool kvm_mips_flush_gva_pmd(pmd_t *pmd, unsigned long start_gva,
+ unsigned long end_gva)
+{
+ pte_t *pte;
+ unsigned long end = ~0ul;
+ int i_min = __pmd_offset(start_gva);
+ int i_max = __pmd_offset(end_gva);
+ bool safe_to_remove = (i_min == 0 && i_max == PTRS_PER_PMD - 1);
+ int i;
+
+ for (i = i_min; i <= i_max; ++i, start_gva = 0) {
+ if (!pmd_present(pmd[i]))
+ continue;
+
+ pte = pte_offset(pmd + i, 0);
+ if (i == i_max)
+ end = end_gva;
+
+ if (kvm_mips_flush_gva_pte(pte, start_gva, end)) {
+ pmd_clear(pmd + i);
+ pte_free_kernel(NULL, pte);
+ } else {
+ safe_to_remove = false;
+ }
+ }
+ return safe_to_remove;
+}
+
+static bool kvm_mips_flush_gva_pud(pud_t *pud, unsigned long start_gva,
+ unsigned long end_gva)
+{
+ pmd_t *pmd;
+ unsigned long end = ~0ul;
+ int i_min = __pud_offset(start_gva);
+ int i_max = __pud_offset(end_gva);
+ bool safe_to_remove = (i_min == 0 && i_max == PTRS_PER_PUD - 1);
+ int i;
+
+ for (i = i_min; i <= i_max; ++i, start_gva = 0) {
+ if (!pud_present(pud[i]))
+ continue;
+
+ pmd = pmd_offset(pud + i, 0);
+ if (i == i_max)
+ end = end_gva;
+
+ if (kvm_mips_flush_gva_pmd(pmd, start_gva, end)) {
+ pud_clear(pud + i);
+ pmd_free(NULL, pmd);
+ } else {
+ safe_to_remove = false;
+ }
+ }
+ return safe_to_remove;
+}
+
+static bool kvm_mips_flush_gva_pgd(pgd_t *pgd, unsigned long start_gva,
+ unsigned long end_gva)
+{
+ pud_t *pud;
+ unsigned long end = ~0ul;
+ int i_min = pgd_index(start_gva);
+ int i_max = pgd_index(end_gva);
+ bool safe_to_remove = (i_min == 0 && i_max == PTRS_PER_PGD - 1);
+ int i;
+
+ for (i = i_min; i <= i_max; ++i, start_gva = 0) {
+ if (!pgd_present(pgd[i]))
+ continue;
+
+ pud = pud_offset(pgd + i, 0);
+ if (i == i_max)
+ end = end_gva;
+
+ if (kvm_mips_flush_gva_pud(pud, start_gva, end)) {
+ pgd_clear(pgd + i);
+ pud_free(NULL, pud);
+ } else {
+ safe_to_remove = false;
+ }
+ }
+ return safe_to_remove;
+}
+
+void kvm_mips_flush_gva_pt(pgd_t *pgd, enum kvm_mips_flush flags)
+{
+ if (flags & KMF_GPA) {
+ /* all of guest virtual address space could be affected */
+ if (flags & KMF_KERN)
+ /* useg, kseg0, seg2/3 */
+ kvm_mips_flush_gva_pgd(pgd, 0, 0x7fffffff);
+ else
+ /* useg */
+ kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff);
+ } else {
+ /* useg */
+ kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff);
+
+ /* kseg2/3 */
+ if (flags & KMF_KERN)
+ kvm_mips_flush_gva_pgd(pgd, 0x60000000, 0x7fffffff);
+ }
+}
+
/* XXXKYMA: Must be called with interrupts disabled */
int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
struct kvm_vcpu *vcpu)
diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c
index 2c4b4ccecbcd..7ef7b77834ed 100644
--- a/arch/mips/kvm/trap_emul.c
+++ b/arch/mips/kvm/trap_emul.c
@@ -776,14 +776,15 @@ static void kvm_trap_emul_vcpu_reenter(struct kvm_run *run,
unsigned int gasid;
/*
- * Lazy host ASID regeneration for guest user mode.
+ * Lazy host ASID regeneration / PT flush for guest user mode.
* If the guest ASID has changed since the last guest usermode
* execution, regenerate the host ASID so as to invalidate stale TLB
- * entries.
+ * entries and flush GVA PT entries too.
*/
if (!KVM_GUEST_KERNEL_MODE(vcpu)) {
gasid = kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID;
if (gasid != vcpu->arch.last_user_gasid) {
+ kvm_mips_flush_gva_pt(user_mm->pgd, KMF_USER);
kvm_get_new_mmu_context(user_mm, cpu, vcpu);
for_each_possible_cpu(i)
if (i != cpu)
--
git-series 0.8.10
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes
2017-01-06 1:32 ` [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes James Hogan
@ 2017-01-06 1:32 ` James Hogan
0 siblings, 0 replies; 5+ messages in thread
From: James Hogan @ 2017-01-06 1:32 UTC (permalink / raw)
To: linux-mips
Cc: James Hogan, Paolo Bonzini, Radim Krčmář,
Ralf Baechle, kvm
Implement invalidation of large ranges of virtual addresses from GVA
page tables in response to a guest ASID change (immediately for guest
kernel page table, lazily for guest user page table).
We iterate through a range of page tables invalidating entries and
freeing fully invalidated tables. To minimise overhead the exact ranges
invalidated depends on the flags argument to kvm_mips_flush_gva_pt(),
which also allows it to be used in future KVM_CAP_SYNC_MMU patches in
response to GPA changes, which unlike guest TLB mapping changes affects
guest KSeg0 mappings.
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
---
arch/mips/include/asm/kvm_host.h | 18 ++++-
arch/mips/kvm/emulate.c | 11 +++-
arch/mips/kvm/mmu.c | 134 ++++++++++++++++++++++++++++++++-
arch/mips/kvm/trap_emul.c | 5 +-
4 files changed, 166 insertions(+), 2 deletions(-)
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index e2bbcfbf2d34..44554241f158 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -610,6 +610,24 @@ extern int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long entryhi,
extern int kvm_mips_guest_tlb_lookup(struct kvm_vcpu *vcpu,
unsigned long entryhi);
extern int kvm_mips_host_tlb_lookup(struct kvm_vcpu *vcpu, unsigned long vaddr);
+
+/* MMU handling */
+
+/**
+ * enum kvm_mips_flush - Types of MMU flushes.
+ * @KMF_USER: Flush guest user virtual memory mappings.
+ * Guest USeg only.
+ * @KMF_KERN: Flush guest kernel virtual memory mappings.
+ * Guest USeg and KSeg2/3.
+ * @KMF_GPA: Flush guest physical memory mappings.
+ * Also includes KSeg0 if KMF_KERN is set.
+ */
+enum kvm_mips_flush {
+ KMF_USER = 0x0,
+ KMF_KERN = 0x1,
+ KMF_GPA = 0x2,
+};
+void kvm_mips_flush_gva_pt(pgd_t *pgd, enum kvm_mips_flush flags);
extern unsigned long kvm_mips_translate_guest_kseg0_to_hpa(struct kvm_vcpu *vcpu,
unsigned long gva);
extern void kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu,
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index 611b8996ca0c..1d399396e486 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -1172,6 +1172,17 @@ enum emulation_result kvm_mips_emulate_CP0(union mips_instruction inst,
nasid);
/*
+ * Flush entries from the GVA page
+ * tables.
+ * Guest user page table will get
+ * flushed lazily on re-entry to guest
+ * user if the guest ASID actually
+ * changes.
+ */
+ kvm_mips_flush_gva_pt(kern_mm->pgd,
+ KMF_KERN);
+
+ /*
* Regenerate/invalidate kernel MMU
* context.
* The user MMU context will be
diff --git a/arch/mips/kvm/mmu.c b/arch/mips/kvm/mmu.c
index 27d6d0dbfeb4..09146b62552f 100644
--- a/arch/mips/kvm/mmu.c
+++ b/arch/mips/kvm/mmu.c
@@ -12,6 +12,7 @@
#include <linux/highmem.h>
#include <linux/kvm_host.h>
#include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
static u32 kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu)
{
@@ -80,6 +81,139 @@ unsigned long kvm_mips_translate_guest_kseg0_to_hpa(struct kvm_vcpu *vcpu,
return (kvm->arch.guest_pmap[gfn] << PAGE_SHIFT) + offset;
}
+/*
+ * kvm_mips_flush_gva_{pte,pmd,pud,pgd,pt}.
+ * Flush a range of guest physical address space from the VM's GPA page tables.
+ */
+
+static bool kvm_mips_flush_gva_pte(pte_t *pte, unsigned long start_gva,
+ unsigned long end_gva)
+{
+ int i_min = __pte_offset(start_gva);
+ int i_max = __pte_offset(end_gva);
+ bool safe_to_remove = (i_min == 0 && i_max == PTRS_PER_PTE - 1);
+ int i;
+
+ /*
+ * There's no freeing to do, so there's no point clearing individual
+ * entries unless only part of the last level page table needs flushing.
+ */
+ if (safe_to_remove)
+ return true;
+
+ for (i = i_min; i <= i_max; ++i) {
+ if (!pte_present(pte[i]))
+ continue;
+
+ set_pte(pte + i, __pte(0));
+ }
+ return false;
+}
+
+static bool kvm_mips_flush_gva_pmd(pmd_t *pmd, unsigned long start_gva,
+ unsigned long end_gva)
+{
+ pte_t *pte;
+ unsigned long end = ~0ul;
+ int i_min = __pmd_offset(start_gva);
+ int i_max = __pmd_offset(end_gva);
+ bool safe_to_remove = (i_min == 0 && i_max == PTRS_PER_PMD - 1);
+ int i;
+
+ for (i = i_min; i <= i_max; ++i, start_gva = 0) {
+ if (!pmd_present(pmd[i]))
+ continue;
+
+ pte = pte_offset(pmd + i, 0);
+ if (i == i_max)
+ end = end_gva;
+
+ if (kvm_mips_flush_gva_pte(pte, start_gva, end)) {
+ pmd_clear(pmd + i);
+ pte_free_kernel(NULL, pte);
+ } else {
+ safe_to_remove = false;
+ }
+ }
+ return safe_to_remove;
+}
+
+static bool kvm_mips_flush_gva_pud(pud_t *pud, unsigned long start_gva,
+ unsigned long end_gva)
+{
+ pmd_t *pmd;
+ unsigned long end = ~0ul;
+ int i_min = __pud_offset(start_gva);
+ int i_max = __pud_offset(end_gva);
+ bool safe_to_remove = (i_min == 0 && i_max == PTRS_PER_PUD - 1);
+ int i;
+
+ for (i = i_min; i <= i_max; ++i, start_gva = 0) {
+ if (!pud_present(pud[i]))
+ continue;
+
+ pmd = pmd_offset(pud + i, 0);
+ if (i == i_max)
+ end = end_gva;
+
+ if (kvm_mips_flush_gva_pmd(pmd, start_gva, end)) {
+ pud_clear(pud + i);
+ pmd_free(NULL, pmd);
+ } else {
+ safe_to_remove = false;
+ }
+ }
+ return safe_to_remove;
+}
+
+static bool kvm_mips_flush_gva_pgd(pgd_t *pgd, unsigned long start_gva,
+ unsigned long end_gva)
+{
+ pud_t *pud;
+ unsigned long end = ~0ul;
+ int i_min = pgd_index(start_gva);
+ int i_max = pgd_index(end_gva);
+ bool safe_to_remove = (i_min == 0 && i_max == PTRS_PER_PGD - 1);
+ int i;
+
+ for (i = i_min; i <= i_max; ++i, start_gva = 0) {
+ if (!pgd_present(pgd[i]))
+ continue;
+
+ pud = pud_offset(pgd + i, 0);
+ if (i == i_max)
+ end = end_gva;
+
+ if (kvm_mips_flush_gva_pud(pud, start_gva, end)) {
+ pgd_clear(pgd + i);
+ pud_free(NULL, pud);
+ } else {
+ safe_to_remove = false;
+ }
+ }
+ return safe_to_remove;
+}
+
+void kvm_mips_flush_gva_pt(pgd_t *pgd, enum kvm_mips_flush flags)
+{
+ if (flags & KMF_GPA) {
+ /* all of guest virtual address space could be affected */
+ if (flags & KMF_KERN)
+ /* useg, kseg0, seg2/3 */
+ kvm_mips_flush_gva_pgd(pgd, 0, 0x7fffffff);
+ else
+ /* useg */
+ kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff);
+ } else {
+ /* useg */
+ kvm_mips_flush_gva_pgd(pgd, 0, 0x3fffffff);
+
+ /* kseg2/3 */
+ if (flags & KMF_KERN)
+ kvm_mips_flush_gva_pgd(pgd, 0x60000000, 0x7fffffff);
+ }
+}
+
/* XXXKYMA: Must be called with interrupts disabled */
int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
struct kvm_vcpu *vcpu)
diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c
index 2c4b4ccecbcd..7ef7b77834ed 100644
--- a/arch/mips/kvm/trap_emul.c
+++ b/arch/mips/kvm/trap_emul.c
@@ -776,14 +776,15 @@ static void kvm_trap_emul_vcpu_reenter(struct kvm_run *run,
unsigned int gasid;
/*
- * Lazy host ASID regeneration for guest user mode.
+ * Lazy host ASID regeneration / PT flush for guest user mode.
* If the guest ASID has changed since the last guest usermode
* execution, regenerate the host ASID so as to invalidate stale TLB
- * entries.
+ * entries and flush GVA PT entries too.
*/
if (!KVM_GUEST_KERNEL_MODE(vcpu)) {
gasid = kvm_read_c0_guest_entryhi(cop0) & KVM_ENTRYHI_ASID;
if (gasid != vcpu->arch.last_user_gasid) {
+ kvm_mips_flush_gva_pt(user_mm->pgd, KMF_USER);
kvm_get_new_mmu_context(user_mm, cpu, vcpu);
for_each_possible_cpu(i)
if (i != cpu)
--
git-series 0.8.10
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2017-01-16 16:07 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <201701111154365057441@zte.com.cn>
2017-01-11 8:34 ` [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes Ralf Baechle
2017-01-16 16:07 ` James Hogan
2017-01-16 16:07 ` James Hogan
2017-01-06 1:32 [PATCH 0/30] KVM: MIPS: Implement GVA page tables James Hogan
2017-01-06 1:32 ` [PATCH 20/30] KVM: MIPS/MMU: Invalidate GVA PTs on ASID changes James Hogan
2017-01-06 1:32 ` James Hogan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).