This callback will do any platform-specific handling needed for converting pages between shared/private. Signed-off-by: Michael Roth <michael.roth@xxxxxxx> --- arch/x86/include/asm/kvm-x86-ops.h | 1 + arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/mmu/mmu.c | 13 +++++++++++++ include/linux/kvm_host.h | 4 ++++ virt/kvm/kvm_main.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 72183da010b8..a8aaf532c2ab 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -132,6 +132,7 @@ KVM_X86_OP(complete_emulated_msr) KVM_X86_OP(vcpu_deliver_sipi_vector) KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons); KVM_X86_OP_OPTIONAL_RET0(fault_is_private); +KVM_X86_OP_OPTIONAL_RET0(update_mem_attr) #undef KVM_X86_OP #undef KVM_X86_OP_OPTIONAL diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f856d689dda0..2da3fb2d5d1b 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1644,6 +1644,8 @@ struct kvm_x86_ops { void (*load_mmu_pgd)(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level); bool (*fault_is_private)(struct kvm *kvm, gpa_t gpa, u64 error_code, bool *private_fault); + int (*update_mem_attr)(struct kvm_memory_slot *slot, unsigned int attr, + gfn_t start, gfn_t end); bool (*has_wbinvd_exit)(void); diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index fb3f34b7391c..053bd77bbf52 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -7251,4 +7251,17 @@ void kvm_arch_set_memory_attributes(struct kvm *kvm, linfo_update_mixed(gfn, slot, level, mixed); } } + +void kvm_arch_post_set_memory_attributes(struct kvm *kvm, + struct kvm_memory_slot *slot, + unsigned long attrs, + gfn_t start, gfn_t end) +{ + int ret; + + ret = static_call(kvm_x86_update_mem_attr)(slot, attrs, start, end); + if (ret) + pr_warn_ratelimited("Failed to update GFN range 0x%llx-0x%llx with attributes 0x%lx. Ret: %d\n", + start, end, attrs, ret); +} #endif diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index fdc59479b3e2..d200b8f45583 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -2330,6 +2330,10 @@ void kvm_arch_set_memory_attributes(struct kvm *kvm, struct kvm_memory_slot *slot, unsigned long attrs, gfn_t start, gfn_t end); +void kvm_arch_post_set_memory_attributes(struct kvm *kvm, + struct kvm_memory_slot *slot, + unsigned long attrs, + gfn_t start, gfn_t end); static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn) { diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index b68574ff6c30..8ec985f1c57d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2561,6 +2561,32 @@ static void kvm_mem_attrs_changed(struct kvm *kvm, unsigned long attrs, kvm_flush_remote_tlbs(kvm); } +static void kvm_post_mem_attrs_changed(struct kvm *kvm, unsigned long attrs, + gfn_t start_orig, gfn_t end_orig) +{ + struct kvm_memory_slot *slot; + struct kvm_memslots *slots; + struct kvm_memslot_iter iter; + int i; + + for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) { + slots = __kvm_memslots(kvm, i); + + kvm_for_each_memslot_in_gfn_range(&iter, slots, start_orig, end_orig) { + gfn_t start, end; + + slot = iter.slot; + start = max(start_orig, slot->base_gfn); + end = min(end_orig, slot->base_gfn + slot->npages); + + if (start >= end) + continue; + + kvm_arch_post_set_memory_attributes(kvm, slot, attrs, start, end); + } + } +} + static int kvm_vm_ioctl_set_mem_attributes(struct kvm *kvm, struct kvm_memory_attributes *attrs) { @@ -2602,6 +2628,9 @@ static int kvm_vm_ioctl_set_mem_attributes(struct kvm *kvm, kvm_mmu_invalidate_end(kvm); KVM_MMU_UNLOCK(kvm); + if (i > start) + kvm_post_mem_attrs_changed(kvm, attrs->attributes, start, i); + mutex_unlock(&kvm->slots_lock); attrs->address = i << PAGE_SHIFT; -- 2.25.1