Add direct MMU handlers to the functions required to support MMIO Signed-off-by: Ben Gardon <bgardon@xxxxxxxxxx> --- arch/x86/kvm/mmu.c | 91 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 72c2289132c43..0a23daea0df50 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -5464,49 +5464,94 @@ static bool mmio_info_in_cache(struct kvm_vcpu *vcpu, u64 addr, bool direct) return vcpu_match_mmio_gva(vcpu, addr); } -/* return true if reserved bit is detected on spte. */ -static bool -walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep) +/* + * Return the level of the lowest level pte added to ptes. + * That pte may be non-present. + */ +static int direct_mmu_get_walk(struct kvm_vcpu *vcpu, u64 addr, u64 *ptes) { - struct kvm_shadow_walk_iterator iterator; - u64 sptes[PT64_ROOT_MAX_LEVEL], spte = 0ull; - int root, leaf; - bool reserved = false; + struct direct_walk_iterator iter; + int leaf = vcpu->arch.mmu->root_level; - if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) - goto exit; + direct_walk_iterator_setup_walk(&iter, vcpu->kvm, + kvm_arch_vcpu_memslots_id(vcpu), addr >> PAGE_SHIFT, + (addr >> PAGE_SHIFT) + 1, MMU_NO_LOCK); + while (direct_walk_iterator_next_pte(&iter)) { + leaf = iter.level; + ptes[leaf - 1] = iter.old_pte; + if (!is_shadow_present_pte(iter.old_pte)) + break; + } + direct_walk_iterator_end_traversal(&iter); + + return leaf; +} + +/* + * Return the level of the lowest level spte added to sptes. + * That spte may be non-present. + */ +static int shadow_mmu_get_walk(struct kvm_vcpu *vcpu, u64 addr, u64 *sptes) +{ + struct kvm_shadow_walk_iterator iterator; + int leaf = vcpu->arch.mmu->root_level; + u64 spte; walk_shadow_page_lockless_begin(vcpu); - for (shadow_walk_init(&iterator, vcpu, addr), - leaf = root = iterator.level; + for (shadow_walk_init(&iterator, vcpu, addr); shadow_walk_okay(&iterator); __shadow_walk_next(&iterator, spte)) { + leaf = iterator.level; spte = mmu_spte_get_lockless(iterator.sptep); - sptes[leaf - 1] = spte; - leaf--; if (!is_shadow_present_pte(spte)) break; - - reserved |= is_shadow_zero_bits_set(vcpu->arch.mmu, spte, - iterator.level); } walk_shadow_page_lockless_end(vcpu); + return leaf; +} + +/* return true if reserved bit is detected on spte. */ +static bool get_mmio_pte(struct kvm_vcpu *vcpu, u64 addr, bool direct, + u64 *ptep) +{ + u64 ptes[PT64_ROOT_MAX_LEVEL]; + int root = vcpu->arch.mmu->root_level; + int leaf; + int level; + bool reserved = false; + + + if (!VALID_PAGE(vcpu->arch.mmu->root_hpa)) { + *ptep = 0ull; + return reserved; + } + + if (direct && vcpu->kvm->arch.direct_mmu_enabled) + leaf = direct_mmu_get_walk(vcpu, addr, ptes); + else + leaf = shadow_mmu_get_walk(vcpu, addr, ptes); + + for (level = root; level >= leaf; level--) { + if (!is_shadow_present_pte(ptes[level - 1])) + break; + reserved |= is_shadow_zero_bits_set(vcpu->arch.mmu, + ptes[level - 1], level); + } + if (reserved) { pr_err("%s: detect reserved bits on spte, addr 0x%llx, dump hierarchy:\n", __func__, addr); - while (root > leaf) { + for (level = root; level >= leaf; level--) pr_err("------ spte 0x%llx level %d.\n", - sptes[root - 1], root); - root--; - } + ptes[level - 1], level); } -exit: - *sptep = spte; + + *ptep = ptes[leaf - 1]; return reserved; } @@ -5518,7 +5563,7 @@ static int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct) if (mmio_info_in_cache(vcpu, addr, direct)) return RET_PF_EMULATE; - reserved = walk_shadow_page_get_mmio_spte(vcpu, addr, &spte); + reserved = get_mmio_pte(vcpu, addr, direct, &spte); if (WARN_ON(reserved)) return -EINVAL; -- 2.23.0.444.g18eeb5a265-goog