diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 4a9cb1d8070a3338a07a0338c5f1786f1dccb5b5..01a3651a7395dcc8dfa4015a7e1a51f4e1dd35c6 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -131,6 +131,29 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) } #ifdef CONFIG_ARM64_HDBSS +static void kvm_clear_hdbss(struct kvm *kvm) +{ + unsigned long i; + struct kvm_vcpu *vcpu; + struct page *hdbss_pg; + + kvm->arch.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS); + + kvm_for_each_vcpu(i, vcpu, kvm) { + /* Kick vcpus to flush hdbss buffer. */ + kvm_vcpu_kick(vcpu); + + hdbss_pg = phys_to_page(HDBSSBR_BADDR(vcpu->arch.hdbss.br_el2)); + if (hdbss_pg) + __free_pages(hdbss_pg, HDBSSBR_SZ(vcpu->arch.hdbss.br_el2)); + + vcpu->arch.hdbss.br_el2 = 0; + vcpu->arch.hdbss.prod_el2 = 0; + } + + kvm->enable_hdbss = false; +} + static int kvm_cap_arm_enable_hdbss(struct kvm *kvm, struct kvm_enable_cap *cap) { @@ -144,6 +167,11 @@ static int kvm_cap_arm_enable_hdbss(struct kvm *kvm, return -EINVAL; } + if (!is_kernel_in_hyp_mode()) { + kvm_err("Do not support HDBSS in non-VHE mode!\n"); + return -EINVAL; + } + if (size < 0 || size > HDBSS_MAX_SIZE) { kvm_err("Invalid HDBSS buffer size: %d!\n", size); return -EINVAL; @@ -158,6 +186,7 @@ static int kvm_cap_arm_enable_hdbss(struct kvm *kvm, hdbss_pg = alloc_pages(GFP_KERNEL, size); if (!hdbss_pg) { kvm_err("Alloc HDBSS buffer failed!\n"); + kvm_clear_hdbss(kvm); return -EINVAL; } @@ -174,21 +203,7 @@ static int kvm_cap_arm_enable_hdbss(struct kvm *kvm, kvm_info("Enable HDBSS success, HDBSS buffer size: %d\n", size); } else if (kvm->enable_hdbss) { - kvm->arch.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS); - - kvm_for_each_vcpu(i, vcpu, kvm) { - /* Kick vcpus to flush hdbss buffer. */ - kvm_vcpu_kick(vcpu); - - hdbss_pg = phys_to_page(HDBSSBR_BADDR(vcpu->arch.hdbss.br_el2)); - if (hdbss_pg) - __free_pages(hdbss_pg, HDBSSBR_SZ(vcpu->arch.hdbss.br_el2)); - - vcpu->arch.hdbss.br_el2 = 0; - vcpu->arch.hdbss.prod_el2 = 0; - } - - kvm->enable_hdbss = false; + kvm_clear_hdbss(kvm); kvm_info("Disable HDBSS success\n"); }