lkml.org 
[lkml]   [2018]   [Jul]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v5 1/7] KVM: arm/arm64: Share common code in user_mem_abort()
    Date
    The code for operations such as marking the pfn as dirty, and
    dcache/icache maintenance during stage 2 fault handling is duplicated
    between normal pages and PMD hugepages.

    Instead of creating another copy of the operations when we introduce
    PUD hugepages, let's share them across the different pagesizes.

    Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
    Cc: Christoffer Dall <christoffer.dall@arm.com>
    Cc: Marc Zyngier <marc.zyngier@arm.com>
    ---
    virt/kvm/arm/mmu.c | 67 ++++++++++++++++++++++++++--------------------
    1 file changed, 38 insertions(+), 29 deletions(-)

    diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
    index 1d90d79706bd..ea3d992e4fb7 100644
    --- a/virt/kvm/arm/mmu.c
    +++ b/virt/kvm/arm/mmu.c
    @@ -1422,7 +1422,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
    unsigned long fault_status)
    {
    int ret;
    - bool write_fault, exec_fault, writable, hugetlb = false, force_pte = false;
    + bool write_fault, writable, hugetlb = false, force_pte = false;
    + bool exec_fault, needs_exec;
    unsigned long mmu_seq;
    gfn_t gfn = fault_ipa >> PAGE_SHIFT;
    struct kvm *kvm = vcpu->kvm;
    @@ -1431,7 +1432,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
    kvm_pfn_t pfn;
    pgprot_t mem_type = PAGE_S2;
    bool logging_active = memslot_is_logging(memslot);
    - unsigned long flags = 0;
    + unsigned long vma_pagesize, flags = 0;

    write_fault = kvm_is_write_fault(vcpu);
    exec_fault = kvm_vcpu_trap_is_iabt(vcpu);
    @@ -1451,7 +1452,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
    return -EFAULT;
    }

    - if (vma_kernel_pagesize(vma) == PMD_SIZE && !logging_active) {
    + vma_pagesize = vma_kernel_pagesize(vma);
    + if (vma_pagesize == PMD_SIZE && !logging_active) {
    hugetlb = true;
    gfn = (fault_ipa & PMD_MASK) >> PAGE_SHIFT;
    } else {
    @@ -1520,28 +1522,45 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
    if (mmu_notifier_retry(kvm, mmu_seq))
    goto out_unlock;

    - if (!hugetlb && !force_pte)
    + if (!hugetlb && !force_pte) {
    + /*
    + * Only PMD_SIZE transparent hugepages(THP) are
    + * currently supported. This code will need to be
    + * updated to support other THP sizes.
    + */
    hugetlb = transparent_hugepage_adjust(&pfn, &fault_ipa);
    + if (hugetlb)
    + vma_pagesize = PMD_SIZE;
    + }
    +
    + if (writable)
    + kvm_set_pfn_dirty(pfn);
    +
    + if (fault_status != FSC_PERM)
    + clean_dcache_guest_page(pfn, vma_pagesize);

    - if (hugetlb) {
    + if (exec_fault)
    + invalidate_icache_guest_page(pfn, vma_pagesize);
    +
    + /*
    + * If we took an execution fault we have made the
    + * icache/dcache coherent above and should now let the s2
    + * mapping be executable.
    + *
    + * Write faults (!exec_fault && FSC_PERM) are orthogonal to
    + * execute permissions, and we preserve whatever we have.
    + */
    + needs_exec = exec_fault ||
    + (fault_status == FSC_PERM && stage2_is_exec(kvm, fault_ipa));
    +
    + if (hugetlb && vma_pagesize == PMD_SIZE) {
    pmd_t new_pmd = pfn_pmd(pfn, mem_type);
    new_pmd = pmd_mkhuge(new_pmd);
    - if (writable) {
    + if (writable)
    new_pmd = kvm_s2pmd_mkwrite(new_pmd);
    - kvm_set_pfn_dirty(pfn);
    - }

    - if (fault_status != FSC_PERM)
    - clean_dcache_guest_page(pfn, PMD_SIZE);
    -
    - if (exec_fault) {
    + if (needs_exec)
    new_pmd = kvm_s2pmd_mkexec(new_pmd);
    - invalidate_icache_guest_page(pfn, PMD_SIZE);
    - } else if (fault_status == FSC_PERM) {
    - /* Preserve execute if XN was already cleared */
    - if (stage2_is_exec(kvm, fault_ipa))
    - new_pmd = kvm_s2pmd_mkexec(new_pmd);
    - }

    ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
    } else {
    @@ -1549,21 +1568,11 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,

    if (writable) {
    new_pte = kvm_s2pte_mkwrite(new_pte);
    - kvm_set_pfn_dirty(pfn);
    mark_page_dirty(kvm, gfn);
    }

    - if (fault_status != FSC_PERM)
    - clean_dcache_guest_page(pfn, PAGE_SIZE);
    -
    - if (exec_fault) {
    + if (needs_exec)
    new_pte = kvm_s2pte_mkexec(new_pte);
    - invalidate_icache_guest_page(pfn, PAGE_SIZE);
    - } else if (fault_status == FSC_PERM) {
    - /* Preserve execute if XN was already cleared */
    - if (stage2_is_exec(kvm, fault_ipa))
    - new_pte = kvm_s2pte_mkexec(new_pte);
    - }

    ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, flags);
    }
    --
    2.17.1
    \
     
     \ /
      Last update: 2018-07-09 16:42    [W:3.619 / U:0.368 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site