Received: by 2002:a05:6a10:9848:0:0:0:0 with SMTP id x8csp1257778pxf; Fri, 19 Mar 2021 03:05:31 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzOuOb/9ipqkASnHrF6cTOlW/yBiJgDKxgjt/WZ2OG+A+lpdPY7hGFLbQFZNivlLxlxbfmc X-Received: by 2002:aa7:c957:: with SMTP id h23mr8344862edt.301.1616148331307; Fri, 19 Mar 2021 03:05:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1616148331; cv=none; d=google.com; s=arc-20160816; b=nvq7bBvQQm9s5y83Al9rsoPVfGe1OWGDRQdNXOquyqr7JPgrNWdV/IrBXC6skT31rn d4yJB9y6grFr4eds5QRnRMFPrxgLuZQ/487IhdaA7OMyoSG/SDigBs8cPmP+r28kph6E 8F9nrfP+U40fEu4AQUaLfhmj29ajF8Jvc1AycPTXJWLlXZnDa1320KNbQmQkk+CJ8K1t z0Q1HtTY/YvJsKm9ktwyFm7nWso2Nse3mX/PB+34HA3xj6vaG/KfmDwLHYsYuvPilMy4 qUkxNrQISebo98vhkWVV/BWWm2WZ62k85BSvGbqAn+6DISSYNUJ02+Tzzdu2Ak0XFSIC kSTg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:dkim-signature; bh=4Q0s6SIE1DtvhBWe0aGHI0Y65bhUADh2FOVOpNiCP+Q=; b=eX5L7IzhwQyzkChp4MmFiR1akppduXVOVNfoVvGV3gPDQC3eMgWgKZC7INlX9OQMw7 +2/iP6IfWvXnaQaGZOU3ZOqcS8LgG8oxswUdEe1+NHhzfk8wwdoyO+deDXgoCyKzmZje i0n5bn+Ca+OjZGb779oHsM6PFIwXjP1YKIUXZS5M6u41r8x7k/Xg3t22UW7VDwwzzAzV k4hkeylzkxxkhERfF0pqTVg7Cj7hKF54Hk/s2RyuGQB8hnEVzSpD9Q7gYe457tnrR9CL MvI+8Vffo5HME1fU1kqvTwvZAbIf8hb0DP3L9t7N2Xt5sXTU0w170sL2801VyGnwl+tC f9OQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=sTVIdYZk; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id g25si3469406ejf.697.2021.03.19.03.05.08; Fri, 19 Mar 2021 03:05:31 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=sTVIdYZk; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230250AbhCSKDj (ORCPT + 99 others); Fri, 19 Mar 2021 06:03:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54298 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230297AbhCSKC5 (ORCPT ); Fri, 19 Mar 2021 06:02:57 -0400 Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 462A2C06174A for ; Fri, 19 Mar 2021 03:02:57 -0700 (PDT) Received: by mail-qk1-x749.google.com with SMTP id p133so9866653qka.17 for ; Fri, 19 Mar 2021 03:02:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=4Q0s6SIE1DtvhBWe0aGHI0Y65bhUADh2FOVOpNiCP+Q=; b=sTVIdYZkAs721hHqacx2zDJTCfgow9HgPl8ZOTSd96Gphpa4bQyQ5kEwgKi2auHYM3 69taDqe1In+7OUbVpuUTwRr0Po7NjzT5JKUDQ3V3cNV1IYMfaepZOpFQ7QvjmgFacju6 6qGd46fH0I1ulWBsSNaf4EB+goVFJkeC7wZ8LsbKIc8Xrz7RM+tDhsGXNy3j/PmwHSfB 13bvomJxTIye1CsgxUvNpK1BKZnB8nYidMmhjWKPvPDdHjLg//W43d95NnxGZLOLRgV0 nEp4XZBLw+HyQfvr+P+eCgOBKxX2F1TvpQ0+BWXd3VOf/D5iIQFQgA3IXICbLk4jVq0m ElAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=4Q0s6SIE1DtvhBWe0aGHI0Y65bhUADh2FOVOpNiCP+Q=; b=ayYRjiiAfdUUiNtb5WDr/bJDNp74oZWJ4bz7JX5x+wFg5IgbU+B6XkZlxJUdA7of63 0/K6soy1HARJFH0NMqbdRcFoUIpebYIT8yLb8zFkgVA7s57G+lv73i1YR6MRPfBPBHtl 6PUxpqEHAu6Gl1sLbT51CSY6HqT5hQY3z6BCEF5ys7l7OseyoJaEIuehw4tbf4z4ij76 qMug+uzHxORQ7Pzeox6PeGjBS39DJB39G+jx/WzYdH52/muF+E6k6KbKV0ppqCFRyrBt OYUyhQudo0NK3ejqtwWGCO1wVkLvNR3y3do6/vktWtSE4XfMnEdCi+zMBQ8QLCF385fO 8vew== X-Gm-Message-State: AOAM532maXYmxh/GiLRfc0vHDvxyIESlMi5bA+qcCICAyRvrhX1Rqh2F hOVIk/M8RyexufRvPW2olxMW9rdt8CBM X-Received: from r2d2-qp.c.googlers.com ([fda3:e722:ac3:10:28:9cb1:c0a8:1652]) (user=qperret job=sendgmr) by 2002:ad4:4d82:: with SMTP id cv2mr8611432qvb.6.1616148176442; Fri, 19 Mar 2021 03:02:56 -0700 (PDT) Date: Fri, 19 Mar 2021 10:01:39 +0000 In-Reply-To: <20210319100146.1149909-1-qperret@google.com> Message-Id: <20210319100146.1149909-32-qperret@google.com> Mime-Version: 1.0 References: <20210319100146.1149909-1-qperret@google.com> X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog Subject: [PATCH v6 31/38] KVM: arm64: Add kvm_pgtable_stage2_find_range() From: Quentin Perret To: catalin.marinas@arm.com, will@kernel.org, maz@kernel.org, james.morse@arm.com, julien.thierry.kdev@gmail.com, suzuki.poulose@arm.com Cc: android-kvm@google.com, seanjc@google.com, mate.toth-pal@arm.com, linux-kernel@vger.kernel.org, robh+dt@kernel.org, linux-arm-kernel@lists.infradead.org, kernel-team@android.com, kvmarm@lists.cs.columbia.edu, tabba@google.com, ardb@kernel.org, mark.rutland@arm.com, dbrazdil@google.com, qperret@google.com Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Since the host stage 2 will be identity mapped, and since it will own most of memory, it would preferable for performance to try and use large block mappings whenever that is possible. To ease this, introduce a new helper in the KVM page-table code which allows to search for large ranges of available IPA space. This will be used in the host memory abort path to greedily idmap large portion of the PA space. Acked-by: Will Deacon Signed-off-by: Quentin Perret --- arch/arm64/include/asm/kvm_pgtable.h | 29 +++++++++ arch/arm64/kvm/hyp/pgtable.c | 89 ++++++++++++++++++++++++++-- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h index eea2e2b0acaa..e1fed14aee17 100644 --- a/arch/arm64/include/asm/kvm_pgtable.h +++ b/arch/arm64/include/asm/kvm_pgtable.h @@ -94,6 +94,16 @@ enum kvm_pgtable_prot { #define PAGE_HYP_RO (KVM_PGTABLE_PROT_R) #define PAGE_HYP_DEVICE (PAGE_HYP | KVM_PGTABLE_PROT_DEVICE) +/** + * struct kvm_mem_range - Range of Intermediate Physical Addresses + * @start: Start of the range. + * @end: End of the range. + */ +struct kvm_mem_range { + u64 start; + u64 end; +}; + /** * enum kvm_pgtable_walk_flags - Flags to control a depth-first page-table walk. * @KVM_PGTABLE_WALK_LEAF: Visit leaf entries, including invalid @@ -397,4 +407,23 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size); int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size, struct kvm_pgtable_walker *walker); +/** + * kvm_pgtable_stage2_find_range() - Find a range of Intermediate Physical + * Addresses with compatible permission + * attributes. + * @pgt: Page-table structure initialised by kvm_pgtable_stage2_init(). + * @addr: Address that must be covered by the range. + * @prot: Protection attributes that the range must be compatible with. + * @range: Range structure used to limit the search space at call time and + * that will hold the result. + * + * The offset of @addr within a page is ignored. An IPA is compatible with @prot + * iff its corresponding stage-2 page-table entry has default ownership and, if + * valid, is mapped with protection attributes identical to @prot. + * + * Return: 0 on success, negative error code on failure. + */ +int kvm_pgtable_stage2_find_range(struct kvm_pgtable *pgt, u64 addr, + enum kvm_pgtable_prot prot, + struct kvm_mem_range *range); #endif /* __ARM64_KVM_PGTABLE_H__ */ diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index f4a514a2e7ae..dc6ef2cfe3eb 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -48,6 +48,8 @@ KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | \ KVM_PTE_LEAF_ATTR_HI_S2_XN) +#define KVM_PTE_LEAF_ATTR_S2_IGNORED GENMASK(58, 55) + #define KVM_INVALID_PTE_OWNER_MASK GENMASK(63, 56) #define KVM_MAX_OWNER_ID 1 @@ -77,15 +79,20 @@ static bool kvm_phys_is_valid(u64 phys) return phys < BIT(id_aa64mmfr0_parange_to_phys_shift(ID_AA64MMFR0_PARANGE_MAX)); } -static bool kvm_block_mapping_supported(u64 addr, u64 end, u64 phys, u32 level) +static bool kvm_level_supports_block_mapping(u32 level) { - u64 granule = kvm_granule_size(level); - /* * Reject invalid block mappings and don't bother with 4TB mappings for * 52-bit PAs. */ - if (level == 0 || (PAGE_SIZE != SZ_4K && level == 1)) + return !(level == 0 || (PAGE_SIZE != SZ_4K && level == 1)); +} + +static bool kvm_block_mapping_supported(u64 addr, u64 end, u64 phys, u32 level) +{ + u64 granule = kvm_granule_size(level); + + if (!kvm_level_supports_block_mapping(level)) return false; if (granule > (end - addr)) @@ -1053,3 +1060,77 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt) pgt->mm_ops->free_pages_exact(pgt->pgd, pgd_sz); pgt->pgd = NULL; } + +#define KVM_PTE_LEAF_S2_COMPAT_MASK (KVM_PTE_LEAF_ATTR_S2_PERMS | \ + KVM_PTE_LEAF_ATTR_LO_S2_MEMATTR | \ + KVM_PTE_LEAF_ATTR_S2_IGNORED) + +static int stage2_check_permission_walker(u64 addr, u64 end, u32 level, + kvm_pte_t *ptep, + enum kvm_pgtable_walk_flags flag, + void * const arg) +{ + kvm_pte_t old_attr, pte = *ptep, *new_attr = arg; + + /* + * Compatible mappings are either invalid and owned by the page-table + * owner (whose id is 0), or valid with matching permission attributes. + */ + if (kvm_pte_valid(pte)) { + old_attr = pte & KVM_PTE_LEAF_S2_COMPAT_MASK; + if (old_attr != *new_attr) + return -EEXIST; + } else if (pte) { + return -EEXIST; + } + + return 0; +} + +int kvm_pgtable_stage2_find_range(struct kvm_pgtable *pgt, u64 addr, + enum kvm_pgtable_prot prot, + struct kvm_mem_range *range) +{ + kvm_pte_t attr; + struct kvm_pgtable_walker check_perm_walker = { + .cb = stage2_check_permission_walker, + .flags = KVM_PGTABLE_WALK_LEAF, + .arg = &attr, + }; + u64 granule, start, end; + u32 level; + int ret; + + ret = stage2_set_prot_attr(prot, &attr); + if (ret) + return ret; + attr &= KVM_PTE_LEAF_S2_COMPAT_MASK; + + for (level = pgt->start_level; level < KVM_PGTABLE_MAX_LEVELS; level++) { + granule = kvm_granule_size(level); + start = ALIGN_DOWN(addr, granule); + end = start + granule; + + if (!kvm_level_supports_block_mapping(level)) + continue; + + if (start < range->start || range->end < end) + continue; + + /* + * Check the presence of existing mappings with incompatible + * permissions within the current block range, and try one level + * deeper if one is found. + */ + ret = kvm_pgtable_walk(pgt, start, granule, &check_perm_walker); + if (ret != -EEXIST) + break; + } + + if (!ret) { + range->start = start; + range->end = end; + } + + return ret; +} -- 2.31.0.rc2.261.g7f71774620-goog