133 lines
4.1 KiB
Diff
133 lines
4.1 KiB
Diff
From d637252f72998261c9d77c0be57317c73ad77f83 Mon Sep 17 00:00:00 2001
|
|
From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
|
|
Date: Tue, 26 Jul 2016 16:38:18 +0300
|
|
Subject: [PATCH] arm/arm64: KVM: drop qman mmio cacheable mapping hack
|
|
|
|
Instead of hardcoding checks for qman cacheable
|
|
mmio region physical addresses extract mapping
|
|
information from the user-space mapping.
|
|
The involves several steps;
|
|
- get access to a pte part of the user-space mapping
|
|
by using get_locked_pte() / pte_unmap_unlock() apis
|
|
- extract memtype (normal / device), shareability from
|
|
the pte
|
|
- convert to S2 translation bits in newly added
|
|
function stage1_to_stage2_pgprot()
|
|
- finish making the s2 translation with the obtained bits
|
|
|
|
Another explored option was using vm_area_struct::vm_page_prot
|
|
which is set in vfio-mc mmap code to the correct page bits.
|
|
However, experiments show that these bits are later altered
|
|
in the generic mmap code (e.g. the shareability bit is always
|
|
set on arm64).
|
|
The only place where the original bits can still be found
|
|
is the user-space mapping, using the method described above.
|
|
|
|
Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
|
|
[Bharat - Fixed mem_type check issue]
|
|
[changed "ifdef ARM64" to CONFIG_ARM64]
|
|
Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com>
|
|
[Ioana - added a sanity check for hugepages]
|
|
Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
|
|
[Fixed format issues]
|
|
Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
|
|
---
|
|
virt/kvm/arm/mmu.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
|
|
1 file changed, 53 insertions(+), 2 deletions(-)
|
|
|
|
--- a/virt/kvm/arm/mmu.c
|
|
+++ b/virt/kvm/arm/mmu.c
|
|
@@ -1381,6 +1381,30 @@ out:
|
|
return ret;
|
|
}
|
|
|
|
+#ifdef CONFIG_ARM64
|
|
+static pgprot_t stage1_to_stage2_pgprot(pgprot_t prot)
|
|
+{
|
|
+ switch (pgprot_val(prot) & PTE_ATTRINDX_MASK) {
|
|
+ case PTE_ATTRINDX(MT_DEVICE_nGnRE):
|
|
+ case PTE_ATTRINDX(MT_DEVICE_nGnRnE):
|
|
+ case PTE_ATTRINDX(MT_DEVICE_GRE):
|
|
+ return PAGE_S2_DEVICE;
|
|
+ case PTE_ATTRINDX(MT_NORMAL_NC):
|
|
+ case PTE_ATTRINDX(MT_NORMAL):
|
|
+ return (pgprot_val(prot) & PTE_SHARED)
|
|
+ ? PAGE_S2
|
|
+ : PAGE_S2_NS;
|
|
+ }
|
|
+
|
|
+ return PAGE_S2_DEVICE;
|
|
+}
|
|
+#else
|
|
+static pgprot_t stage1_to_stage2_pgprot(pgprot_t prot)
|
|
+{
|
|
+ return PAGE_S2_DEVICE;
|
|
+}
|
|
+#endif
|
|
+
|
|
static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap)
|
|
{
|
|
kvm_pfn_t pfn = *pfnp;
|
|
@@ -1725,8 +1749,23 @@ static int user_mem_abort(struct kvm_vcp
|
|
* 3 levels, i.e, PMD is not folded.
|
|
*/
|
|
if (vma_pagesize == PMD_SIZE ||
|
|
- (vma_pagesize == PUD_SIZE && kvm_stage2_has_pmd(kvm)))
|
|
+ (vma_pagesize == PUD_SIZE && kvm_stage2_has_pmd(kvm))) {
|
|
gfn = (fault_ipa & huge_page_mask(hstate_vma(vma))) >> PAGE_SHIFT;
|
|
+ } else {
|
|
+ if (!is_vm_hugetlb_page(vma)) {
|
|
+ pte_t *pte;
|
|
+ spinlock_t *ptl;
|
|
+ pgprot_t prot;
|
|
+
|
|
+ pte = get_locked_pte(current->mm, memslot->userspace_addr, &ptl);
|
|
+ prot = stage1_to_stage2_pgprot(__pgprot(pte_val(*pte)));
|
|
+ pte_unmap_unlock(pte, ptl);
|
|
+#ifdef CONFIG_ARM64
|
|
+ if (pgprot_val(prot) == pgprot_val(PAGE_S2_NS))
|
|
+ mem_type = PAGE_S2_NS;
|
|
+#endif
|
|
+ }
|
|
+ }
|
|
up_read(¤t->mm->mmap_sem);
|
|
|
|
/* We need minimum second+third level pages */
|
|
@@ -1755,6 +1794,11 @@ static int user_mem_abort(struct kvm_vcp
|
|
if (is_error_noslot_pfn(pfn))
|
|
return -EFAULT;
|
|
|
|
+#ifdef CONFIG_ARM64
|
|
+ if (pgprot_val(mem_type) == pgprot_val(PAGE_S2_NS)) {
|
|
+ flags |= KVM_S2PTE_FLAG_IS_IOMAP;
|
|
+ } else
|
|
+#endif
|
|
if (kvm_is_device_pfn(pfn)) {
|
|
mem_type = PAGE_S2_DEVICE;
|
|
flags |= KVM_S2PTE_FLAG_IS_IOMAP;
|
|
@@ -2351,6 +2395,9 @@ int kvm_arch_prepare_memory_region(struc
|
|
gpa_t gpa = mem->guest_phys_addr +
|
|
(vm_start - mem->userspace_addr);
|
|
phys_addr_t pa;
|
|
+ pgprot_t prot;
|
|
+ pte_t *pte;
|
|
+ spinlock_t *ptl;
|
|
|
|
pa = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT;
|
|
pa += vm_start - vma->vm_start;
|
|
@@ -2361,9 +2408,13 @@ int kvm_arch_prepare_memory_region(struc
|
|
goto out;
|
|
}
|
|
|
|
+ pte = get_locked_pte(current->mm, mem->userspace_addr, &ptl);
|
|
+ prot = stage1_to_stage2_pgprot(__pgprot(pte_val(*pte)));
|
|
+ pte_unmap_unlock(pte, ptl);
|
|
+
|
|
ret = kvm_phys_addr_ioremap(kvm, gpa, pa,
|
|
vm_end - vm_start,
|
|
- writable, PAGE_S2_DEVICE);
|
|
+ writable, prot);
|
|
if (ret)
|
|
break;
|
|
}
|