| // SPDX-License-Identifier: GPL-2.0-only | |
| /* | |
| * Copyright (C) 2017 - Columbia University and Linaro Ltd. | |
| * Author: Jintack Lim <jintack.lim@linaro.org> | |
| */ | |
| #include <linux/bitfield.h> | |
| #include <linux/kvm.h> | |
| #include <linux/kvm_host.h> | |
| #include <asm/fixmap.h> | |
| #include <asm/kvm_arm.h> | |
| #include <asm/kvm_emulate.h> | |
| #include <asm/kvm_mmu.h> | |
| #include <asm/kvm_nested.h> | |
| #include <asm/sysreg.h> | |
| #include "sys_regs.h" | |
| #include "vgic/vgic.h" | |
| struct vncr_tlb { | |
| /* The guest's VNCR_EL2 */ | |
| u64 gva; | |
| struct s1_walk_info wi; | |
| struct s1_walk_result wr; | |
| u64 hpa; | |
| bool hpa_writable; | |
| /* -1 when not mapped on a CPU */ | |
| atomic_t cpu; | |
| /* | |
| * true if the TLB is valid. Can only be changed with the | |
| * mmu_lock held. | |
| */ | |
| bool valid; | |
| }; | |
| /* | |
| * Ratio of live shadow S2 MMU per vcpu. This is a trade-off between | |
| * memory usage and potential number of different sets of S2 PTs in | |
| * the guests. Running out of S2 MMUs only affects performance (we | |
| * will invalidate them more often). | |
| */ | |
| #define S2_MMU_PER_VCPU 2 | |
| int kvm_init_nested(struct kvm *kvm) | |
| { | |
| kvm->arch.nested_mmus = kvmalloc_objs(struct kvm_s2_mmu *, | |
| KVM_MAX_VCPUS * S2_MMU_PER_VCPU, | |
| GFP_KERNEL_ACCOUNT); | |
| kvm->arch.nested_mmus_size = 0; | |
| atomic_set(&kvm->arch.vncr_tlb_count, 0); | |
| return kvm->arch.nested_mmus ? 0 : -ENOMEM; | |
| } | |
| void kvm_destroy_nested(struct kvm *kvm) | |
| { | |
| for (int i = 0; i < kvm->arch.nested_mmus_size; i+= S2_MMU_PER_VCPU) | |
| kvfree(kvm->arch.nested_mmus[i]); | |
| kvm->arch.nested_mmus_size = 0; | |
| kvfree(kvm->arch.nested_mmus); | |
| } | |
| static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu) | |
| { | |
| /* | |
| * We only initialise the IPA range on the canonical MMU, which | |
| * defines the contract between KVM and userspace on where the | |
| * "hardware" is in the IPA space. This affects the validity of MMIO | |
| * exits forwarded to userspace, for example. | |
| * | |
| * For nested S2s, we use the PARange as exposed to the guest, as it | |
| * is allowed to use it at will to expose whatever memory map it | |
| * wants to its own guests as it would be on real HW. | |
| */ | |
| return kvm_init_stage2_mmu(kvm, mmu, kvm_get_pa_bits(kvm)); | |
| } | |
| int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu) | |
| { | |
| struct kvm *kvm = vcpu->kvm; | |
| int num_mmus; | |
| lockdep_assert_held(&kvm->arch.config_lock); | |
| if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features) && | |
| !cpus_have_final_cap(ARM64_HAS_HCR_NV1)) | |
| return -EINVAL; | |
| if (!vcpu->arch.ctxt.vncr_array) | |
| vcpu->arch.ctxt.vncr_array = (u64 *)__get_free_page(GFP_KERNEL_ACCOUNT | | |
| __GFP_ZERO); | |
| if (!vcpu->arch.ctxt.vncr_array) | |
| return -ENOMEM; | |
| num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU; | |
| if (num_mmus > kvm->arch.nested_mmus_size) { | |
| struct kvm_s2_mmu *tmp; | |
| int i, ret = 0; | |
| tmp = kvzalloc_objs(*tmp, S2_MMU_PER_VCPU, GFP_KERNEL_ACCOUNT); | |
| if (!tmp) | |
| ret = -ENOMEM; | |
| for (i = 0; !ret && i < S2_MMU_PER_VCPU; i++) { | |
| ret = init_nested_s2_mmu(kvm, &tmp[i]); | |
| if (ret) | |
| break; | |
| } | |
| if (ret) { | |
| while (--i >= 0) | |
| kvm_free_stage2_pgd(&tmp[i]); | |
| kvfree(tmp); | |
| free_page((unsigned long)vcpu->arch.ctxt.vncr_array); | |
| vcpu->arch.ctxt.vncr_array = NULL; | |
| return ret; | |
| } | |
| guard(write_lock)(&kvm->mmu_lock); | |
| for (i = 0; i < S2_MMU_PER_VCPU; i++) | |
| kvm->arch.nested_mmus[i + kvm->arch.nested_mmus_size] = &tmp[i]; | |
| kvm->arch.nested_mmus_size += S2_MMU_PER_VCPU; | |
| } | |
| return 0; | |
| } | |
| struct s2_walk_info { | |
| u64 baddr; | |
| unsigned int max_oa_bits; | |
| unsigned int pgshift; | |
| unsigned int sl; | |
| unsigned int t0sz; | |
| bool be; | |
| bool ha; | |
| }; | |
| static u32 compute_fsc(int level, u32 fsc) | |
| { | |
| return fsc | (level & 0x3); | |
| } | |
| static int esr_s2_fault(struct kvm_vcpu *vcpu, int level, u32 fsc) | |
| { | |
| u32 esr; | |
| esr = kvm_vcpu_get_esr(vcpu) & ~ESR_ELx_FSC; | |
| esr |= compute_fsc(level, fsc); | |
| return esr; | |
| } | |
| static int get_ia_size(struct s2_walk_info *wi) | |
| { | |
| return 64 - wi->t0sz; | |
| } | |
| static int check_base_s2_limits(struct kvm_vcpu *vcpu, struct s2_walk_info *wi, | |
| int level, int input_size, int stride) | |
| { | |
| int start_size, pa_max; | |
| pa_max = kvm_get_pa_bits(vcpu->kvm); | |
| /* Check translation limits */ | |
| switch (BIT(wi->pgshift)) { | |
| case SZ_64K: | |
| if (level == 0 || (level == 1 && pa_max <= 42)) | |
| return -EFAULT; | |
| break; | |
| case SZ_16K: | |
| if (level == 0 || (level == 1 && pa_max <= 40)) | |
| return -EFAULT; | |
| break; | |
| case SZ_4K: | |
| if (level < 0 || (level == 0 && pa_max <= 42)) | |
| return -EFAULT; | |
| break; | |
| } | |
| /* Check input size limits */ | |
| if (input_size > pa_max) | |
| return -EFAULT; | |
| /* Check number of entries in starting level table */ | |
| start_size = input_size - ((3 - level) * stride + wi->pgshift); | |
| if (start_size < 1 || start_size > stride + 4) | |
| return -EFAULT; | |
| return 0; | |
| } | |
| /* Check if output is within boundaries */ | |
| static int check_output_size(struct s2_walk_info *wi, phys_addr_t output) | |
| { | |
| unsigned int output_size = wi->max_oa_bits; | |
| if (output_size != 48 && (output & GENMASK_ULL(47, output_size))) | |
| return -1; | |
| return 0; | |
| } | |
| static int read_guest_s2_desc(struct kvm_vcpu *vcpu, phys_addr_t pa, u64 *desc, | |
| struct s2_walk_info *wi) | |
| { | |
| u64 val; | |
| int r; | |
| r = kvm_read_guest(vcpu->kvm, pa, &val, sizeof(val)); | |
| if (r) | |
| return r; | |
| /* | |
| * Handle reversedescriptors if endianness differs between the | |
| * host and the guest hypervisor. | |
| */ | |
| if (wi->be) | |
| *desc = be64_to_cpu((__force __be64)val); | |
| else | |
| *desc = le64_to_cpu((__force __le64)val); | |
| return 0; | |
| } | |
| static int swap_guest_s2_desc(struct kvm_vcpu *vcpu, phys_addr_t pa, u64 old, u64 new, | |
| struct s2_walk_info *wi) | |
| { | |
| if (wi->be) { | |
| old = (__force u64)cpu_to_be64(old); | |
| new = (__force u64)cpu_to_be64(new); | |
| } else { | |
| old = (__force u64)cpu_to_le64(old); | |
| new = (__force u64)cpu_to_le64(new); | |
| } | |
| return __kvm_at_swap_desc(vcpu->kvm, pa, old, new); | |
| } | |
| /* | |
| * This is essentially a C-version of the pseudo code from the ARM ARM | |
| * AArch64.TranslationTableWalk function. I strongly recommend looking at | |
| * that pseudocode in trying to understand this. | |
| * | |
| * Must be called with the kvm->srcu read lock held | |
| */ | |
| static int walk_nested_s2_pgd(struct kvm_vcpu *vcpu, phys_addr_t ipa, | |
| struct s2_walk_info *wi, struct kvm_s2_trans *out) | |
| { | |
| int first_block_level, level, stride, input_size, base_lower_bound; | |
| phys_addr_t base_addr; | |
| unsigned int addr_top, addr_bottom; | |
| u64 desc, new_desc; /* page table entry */ | |
| int ret; | |
| phys_addr_t paddr; | |
| switch (BIT(wi->pgshift)) { | |
| default: | |
| case SZ_64K: | |
| case SZ_16K: | |
| level = 3 - wi->sl; | |
| first_block_level = 2; | |
| break; | |
| case SZ_4K: | |
| level = 2 - wi->sl; | |
| first_block_level = 1; | |
| break; | |
| } | |
| stride = wi->pgshift - 3; | |
| input_size = get_ia_size(wi); | |
| if (input_size > 48 || input_size < 25) | |
| return -EFAULT; | |
| ret = check_base_s2_limits(vcpu, wi, level, input_size, stride); | |
| if (WARN_ON(ret)) { | |
| out->esr = compute_fsc(0, ESR_ELx_FSC_FAULT); | |
| return ret; | |
| } | |
| base_lower_bound = 3 + input_size - ((3 - level) * stride + | |
| wi->pgshift); | |
| base_addr = wi->baddr & GENMASK_ULL(47, base_lower_bound); | |
| if (check_output_size(wi, base_addr)) { | |
| /* R_BFHQH */ | |
| out->esr = compute_fsc(0, ESR_ELx_FSC_ADDRSZ); | |
| return 1; | |
| } | |
| addr_top = input_size - 1; | |
| while (1) { | |
| phys_addr_t index; | |
| addr_bottom = (3 - level) * stride + wi->pgshift; | |
| index = (ipa & GENMASK_ULL(addr_top, addr_bottom)) | |
| >> (addr_bottom - 3); | |
| paddr = base_addr | index; | |
| ret = read_guest_s2_desc(vcpu, paddr, &desc, wi); | |
| if (ret < 0) { | |
| out->esr = ESR_ELx_FSC_SEA_TTW(level); | |
| return ret; | |
| } | |
| new_desc = desc; | |
| /* Check for valid descriptor at this point */ | |
| if (!(desc & KVM_PTE_VALID)) { | |
| out->esr = compute_fsc(level, ESR_ELx_FSC_FAULT); | |
| out->desc = desc; | |
| return 1; | |
| } | |
| if (FIELD_GET(KVM_PTE_TYPE, desc) == KVM_PTE_TYPE_BLOCK) { | |
| if (level < 3) | |
| break; | |
| out->esr = compute_fsc(level, ESR_ELx_FSC_FAULT); | |
| out->desc = desc; | |
| return 1; | |
| } | |
| /* We're at the final level */ | |
| if (level == 3) | |
| break; | |
| if (check_output_size(wi, desc)) { | |
| out->esr = compute_fsc(level, ESR_ELx_FSC_ADDRSZ); | |
| out->desc = desc; | |
| return 1; | |
| } | |
| base_addr = desc & GENMASK_ULL(47, wi->pgshift); | |
| level += 1; | |
| addr_top = addr_bottom - 1; | |
| } | |
| if (level < first_block_level) { | |
| out->esr = compute_fsc(level, ESR_ELx_FSC_FAULT); | |
| out->desc = desc; | |
| return 1; | |
| } | |
| if (check_output_size(wi, desc)) { | |
| out->esr = compute_fsc(level, ESR_ELx_FSC_ADDRSZ); | |
| out->desc = desc; | |
| return 1; | |
| } | |
| if (wi->ha) | |
| new_desc |= KVM_PTE_LEAF_ATTR_LO_S2_AF; | |
| if (new_desc != desc) { | |
| ret = swap_guest_s2_desc(vcpu, paddr, desc, new_desc, wi); | |
| if (ret == -EAGAIN) | |
| return ret; | |
| if (ret) { | |
| out->esr = ESR_ELx_FSC_SEA_TTW(level); | |
| out->desc = desc; | |
| return 1; | |
| } | |
| desc = new_desc; | |
| } | |
| if (!(desc & KVM_PTE_LEAF_ATTR_LO_S2_AF)) { | |
| out->esr = compute_fsc(level, ESR_ELx_FSC_ACCESS); | |
| out->desc = desc; | |
| return 1; | |
| } | |
| addr_bottom += contiguous_bit_shift(desc, wi, level); | |
| /* Calculate and return the result */ | |
| paddr = (desc & GENMASK_ULL(47, addr_bottom)) | | |
| (ipa & GENMASK_ULL(addr_bottom - 1, 0)); | |
| out->output = paddr; | |
| out->block_size = 1UL << ((3 - level) * stride + wi->pgshift); | |
| out->readable = desc & KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R; | |
| out->writable = desc & KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W; | |
| out->level = level; | |
| out->desc = desc; | |
| return 0; | |
| } | |
| #define _has_tgran_2(__r, __sz) \ | |
| ({ \ | |
| u64 _s1, _s2, _mmfr0 = __r; \ | |
| \ | |
| _s2 = SYS_FIELD_GET(ID_AA64MMFR0_EL1, \ | |
| TGRAN##__sz##_2, _mmfr0); \ | |
| \ | |
| _s1 = SYS_FIELD_GET(ID_AA64MMFR0_EL1, \ | |
| TGRAN##__sz, _mmfr0); \ | |
| \ | |
| ((_s2 != ID_AA64MMFR0_EL1_TGRAN##__sz##_2_NI && \ | |
| _s2 != ID_AA64MMFR0_EL1_TGRAN##__sz##_2_TGRAN##__sz) || \ | |
| (_s2 == ID_AA64MMFR0_EL1_TGRAN##__sz##_2_TGRAN##__sz && \ | |
| _s1 != ID_AA64MMFR0_EL1_TGRAN##__sz##_NI)); \ | |
| }) | |
| static bool has_tgran_2(u64 mmfr0, unsigned int shift) | |
| { | |
| switch (shift) { | |
| case 12: | |
| return _has_tgran_2(mmfr0, 4); | |
| case 14: | |
| return _has_tgran_2(mmfr0, 16); | |
| case 16: | |
| return _has_tgran_2(mmfr0, 64); | |
| default: | |
| BUG(); | |
| } | |
| } | |
| static unsigned int fallback_tgran2_shift(u64 mmfr0) | |
| { | |
| if (has_tgran_2(mmfr0, PAGE_SHIFT)) | |
| return PAGE_SHIFT; | |
| else if (has_tgran_2(mmfr0, 12)) | |
| return 12; | |
| else if (has_tgran_2(mmfr0, 14)) | |
| return 14; | |
| else if (has_tgran_2(mmfr0, 16)) | |
| return 16; | |
| else | |
| return PAGE_SHIFT; | |
| } | |
| static unsigned int vtcr_to_tg0_pgshift(struct kvm *kvm, u64 vtcr) | |
| { | |
| u64 tg0 = FIELD_GET(VTCR_EL2_TG0_MASK, vtcr); | |
| u64 mmfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64MMFR0_EL1); | |
| unsigned int shift; | |
| switch (tg0) { | |
| case VTCR_EL2_TG0_4K: | |
| shift = 12; | |
| break; | |
| case VTCR_EL2_TG0_16K: | |
| shift = 14; | |
| break; | |
| case VTCR_EL2_TG0_64K: | |
| /* IMPDEF: treat any other value as 64k, subject to fallback */ | |
| default: | |
| shift = 16; | |
| } | |
| /* | |
| * If TGx is programmed to an unimplemented value (not advertised in | |
| * ID_AA64MMFR0_EL1), we should treat it as if an implemented value is | |
| * written, as per the architecture. Choose an available one while | |
| * prioritizing PAGE_SIZE. | |
| */ | |
| if (!has_tgran_2(mmfr0, shift)) | |
| return fallback_tgran2_shift(mmfr0); | |
| return shift; | |
| } | |
| static size_t vtcr_to_tg0_pgsize(struct kvm *kvm, u64 vtcr) | |
| { | |
| return BIT(vtcr_to_tg0_pgshift(kvm, vtcr)); | |
| } | |
| static void setup_s2_walk(struct kvm_vcpu *vcpu, struct s2_walk_info *wi) | |
| { | |
| u64 vtcr = vcpu_read_sys_reg(vcpu, VTCR_EL2); | |
| wi->baddr = vcpu_read_sys_reg(vcpu, VTTBR_EL2); | |
| wi->t0sz = vtcr & VTCR_EL2_T0SZ_MASK; | |
| wi->pgshift = vtcr_to_tg0_pgshift(vcpu->kvm, vtcr); | |
| wi->sl = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr); | |
| /* Global limit for now, should eventually be per-VM */ | |
| wi->max_oa_bits = min(get_kvm_ipa_limit(), | |
| ps_to_output_size(FIELD_GET(VTCR_EL2_PS_MASK, vtcr), false)); | |
| wi->ha = vtcr & VTCR_EL2_HA; | |
| wi->be = vcpu_read_sys_reg(vcpu, SCTLR_EL2) & SCTLR_ELx_EE; | |
| } | |
| int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa, | |
| struct kvm_s2_trans *result) | |
| { | |
| struct s2_walk_info wi; | |
| int ret; | |
| result->esr = 0; | |
| if (!vcpu_has_nv(vcpu)) | |
| return 0; | |
| setup_s2_walk(vcpu, &wi); | |
| ret = walk_nested_s2_pgd(vcpu, gipa, &wi, result); | |
| if (ret) | |
| result->esr |= (kvm_vcpu_get_esr(vcpu) & ~ESR_ELx_FSC); | |
| return ret; | |
| } | |
| static unsigned int __ttl_to_size(u8 ttl) | |
| { | |
| int level = ttl & 3; | |
| int gran = (ttl >> 2) & 3; | |
| unsigned int max_size = 0; | |
| switch (gran) { | |
| case TLBI_TTL_TG_4K: | |
| switch (level) { | |
| case 0: | |
| break; | |
| case 1: | |
| max_size = SZ_1G; | |
| break; | |
| case 2: | |
| max_size = SZ_2M; | |
| break; | |
| case 3: | |
| max_size = SZ_4K; | |
| break; | |
| } | |
| break; | |
| case TLBI_TTL_TG_16K: | |
| switch (level) { | |
| case 0: | |
| case 1: | |
| break; | |
| case 2: | |
| max_size = SZ_32M; | |
| break; | |
| case 3: | |
| max_size = SZ_16K; | |
| break; | |
| } | |
| break; | |
| case TLBI_TTL_TG_64K: | |
| switch (level) { | |
| case 0: | |
| case 1: | |
| /* No 52bit IPA support */ | |
| break; | |
| case 2: | |
| max_size = SZ_512M; | |
| break; | |
| case 3: | |
| max_size = SZ_64K; | |
| break; | |
| } | |
| break; | |
| default: /* No size information */ | |
| break; | |
| } | |
| return max_size; | |
| } | |
| static unsigned int ttl_to_size(u8 ttl) | |
| { | |
| return __ttl_to_size(ttl) ?: SZ_1G; | |
| } | |
| static u8 pgshift_level_to_ttl(u16 shift, s8 level) | |
| { | |
| u8 ttl; | |
| /* | |
| * If we don't have a proper level, fallback to the maximum | |
| * size. | |
| */ | |
| if (level < 0) | |
| return 0; | |
| switch(shift) { | |
| case 12: | |
| ttl = TLBI_TTL_TG_4K; | |
| break; | |
| case 14: | |
| ttl = TLBI_TTL_TG_16K; | |
| break; | |
| case 16: | |
| ttl = TLBI_TTL_TG_64K; | |
| break; | |
| default: | |
| BUG(); | |
| } | |
| ttl <<= 2; | |
| ttl |= level & 3; | |
| return ttl; | |
| } | |
| /* | |
| * Compute the equivalent of the TTL field by parsing the shadow PT. The | |
| * granule size is extracted from the cached VTCR_EL2.TG0 while the level is | |
| * retrieved from first entry carrying the level as a tag. | |
| */ | |
| static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr) | |
| { | |
| size_t tg0_size = vtcr_to_tg0_pgsize(kvm_s2_mmu_to_kvm(mmu), mmu->tlb_vtcr); | |
| u64 tmp, sz = 0; | |
| kvm_pte_t pte; | |
| u8 ttl, level; | |
| lockdep_assert_held_write(&kvm_s2_mmu_to_kvm(mmu)->mmu_lock); | |
| switch (tg0_size) { | |
| case SZ_4K: | |
| ttl = (TLBI_TTL_TG_4K << 2); | |
| break; | |
| case SZ_16K: | |
| ttl = (TLBI_TTL_TG_16K << 2); | |
| break; | |
| case SZ_64K: | |
| default: /* IMPDEF: treat any other value as 64k */ | |
| ttl = (TLBI_TTL_TG_64K << 2); | |
| break; | |
| } | |
| tmp = addr; | |
| again: | |
| /* Iteratively compute the block sizes for a particular granule size */ | |
| switch (tg0_size) { | |
| case SZ_4K: | |
| if (sz < SZ_4K) sz = SZ_4K; | |
| else if (sz < SZ_2M) sz = SZ_2M; | |
| else if (sz < SZ_1G) sz = SZ_1G; | |
| else sz = 0; | |
| break; | |
| case SZ_16K: | |
| if (sz < SZ_16K) sz = SZ_16K; | |
| else if (sz < SZ_32M) sz = SZ_32M; | |
| else sz = 0; | |
| break; | |
| case SZ_64K: | |
| default: /* IMPDEF: treat any other value as 64k */ | |
| if (sz < SZ_64K) sz = SZ_64K; | |
| else if (sz < SZ_512M) sz = SZ_512M; | |
| else sz = 0; | |
| break; | |
| } | |
| if (sz == 0) | |
| return 0; | |
| tmp &= ~(sz - 1); | |
| if (kvm_pgtable_get_leaf(mmu->pgt, tmp, &pte, NULL)) | |
| goto again; | |
| if (!(pte & PTE_VALID)) | |
| goto again; | |
| level = FIELD_GET(KVM_NV_GUEST_MAP_SZ, pte); | |
| if (!level) | |
| goto again; | |
| ttl |= level; | |
| /* | |
| * We now have found some level information in the shadow S2. Check | |
| * that the resulting range is actually including the original IPA. | |
| */ | |
| sz = ttl_to_size(ttl); | |
| if (addr < (tmp + sz)) | |
| return ttl; | |
| return 0; | |
| } | |
| unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val) | |
| { | |
| struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu); | |
| unsigned long max_size; | |
| u8 ttl; | |
| ttl = FIELD_GET(TLBI_TTL_MASK, val); | |
| if (!ttl || !kvm_has_feat(kvm, ID_AA64MMFR2_EL1, TTL, IMP)) { | |
| /* No TTL, check the shadow S2 for a hint */ | |
| u64 addr = (val & GENMASK_ULL(35, 0)) << 12; | |
| ttl = get_guest_mapping_ttl(mmu, addr); | |
| } | |
| /* | |
| * Don't use the default 1GB fallback, as we can adapt to the | |
| * max mapping size we allow at S2. | |
| */ | |
| max_size = __ttl_to_size(ttl); | |
| if (!max_size) { | |
| /* Compute the maximum extent of the invalidation */ | |
| switch (vtcr_to_tg0_pgsize(kvm, mmu->tlb_vtcr)) { | |
| case SZ_4K: | |
| max_size = SZ_1G; | |
| break; | |
| case SZ_16K: | |
| max_size = SZ_32M; | |
| break; | |
| case SZ_64K: | |
| default: /* IMPDEF: treat any other value as 64k */ | |
| /* | |
| * No, we do not support 52bit IPA in nested yet. Once | |
| * we do, this should be 4TB. | |
| */ | |
| max_size = SZ_512M; | |
| break; | |
| } | |
| } | |
| WARN_ON(!max_size); | |
| return max_size; | |
| } | |
| /* | |
| * We can have multiple *different* MMU contexts with the same VMID: | |
| * | |
| * - S2 being enabled or not, hence differing by the HCR_EL2.VM bit | |
| * | |
| * - Multiple vcpus using private S2s (huh huh...), hence differing by the | |
| * VBBTR_EL2.BADDR address | |
| * | |
| * - A combination of the above... | |
| * | |
| * We can always identify which MMU context to pick at run-time. However, | |
| * TLB invalidation involving a VMID must take action on all the TLBs using | |
| * this particular VMID. This translates into applying the same invalidation | |
| * operation to all the contexts that are using this VMID. Moar phun! | |
| */ | |
| void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid, | |
| const union tlbi_info *info, | |
| void (*tlbi_callback)(struct kvm_s2_mmu *, | |
| const union tlbi_info *)) | |
| { | |
| write_lock(&kvm->mmu_lock); | |
| for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { | |
| struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; | |
| if (!kvm_s2_mmu_valid(mmu)) | |
| continue; | |
| if (vmid == get_vmid(mmu->tlb_vttbr)) | |
| tlbi_callback(mmu, info); | |
| } | |
| write_unlock(&kvm->mmu_lock); | |
| } | |
| struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu) | |
| { | |
| struct kvm *kvm = vcpu->kvm; | |
| bool nested_stage2_enabled; | |
| u64 vttbr, vtcr, hcr; | |
| lockdep_assert_held_write(&kvm->mmu_lock); | |
| vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2); | |
| vtcr = vcpu_read_sys_reg(vcpu, VTCR_EL2); | |
| hcr = vcpu_read_sys_reg(vcpu, HCR_EL2); | |
| nested_stage2_enabled = hcr & HCR_VM; | |
| /* Don't consider the CnP bit for the vttbr match */ | |
| vttbr &= ~VTTBR_CNP_BIT; | |
| /* | |
| * Two possibilities when looking up a S2 MMU context: | |
| * | |
| * - either S2 is enabled in the guest, and we need a context that is | |
| * S2-enabled and matches the full VTTBR (VMID+BADDR) and VTCR, | |
| * which makes it safe from a TLB conflict perspective (a broken | |
| * guest won't be able to generate them), | |
| * | |
| * - or S2 is disabled, and we need a context that is S2-disabled | |
| * and matches the VMID only, as all TLBs are tagged by VMID even | |
| * if S2 translation is disabled. | |
| */ | |
| for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { | |
| struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; | |
| if (!kvm_s2_mmu_valid(mmu)) | |
| continue; | |
| if (nested_stage2_enabled && | |
| mmu->nested_stage2_enabled && | |
| vttbr == mmu->tlb_vttbr && | |
| vtcr == mmu->tlb_vtcr) | |
| return mmu; | |
| if (!nested_stage2_enabled && | |
| !mmu->nested_stage2_enabled && | |
| get_vmid(vttbr) == get_vmid(mmu->tlb_vttbr)) | |
| return mmu; | |
| } | |
| return NULL; | |
| } | |
| static struct kvm_s2_mmu *get_s2_mmu_nested(struct kvm_vcpu *vcpu) | |
| { | |
| struct kvm *kvm = vcpu->kvm; | |
| struct kvm_s2_mmu *s2_mmu; | |
| int i; | |
| lockdep_assert_held_write(&vcpu->kvm->mmu_lock); | |
| s2_mmu = lookup_s2_mmu(vcpu); | |
| if (s2_mmu) | |
| goto out; | |
| /* | |
| * Make sure we don't always search from the same point, or we | |
| * will always reuse a potentially active context, leaving | |
| * free contexts unused. | |
| */ | |
| for (i = kvm->arch.nested_mmus_next; | |
| i < (kvm->arch.nested_mmus_size + kvm->arch.nested_mmus_next); | |
| i++) { | |
| s2_mmu = kvm->arch.nested_mmus[i % kvm->arch.nested_mmus_size]; | |
| if (atomic_read(&s2_mmu->refcnt) == 0) | |
| break; | |
| } | |
| BUG_ON(atomic_read(&s2_mmu->refcnt)); /* We have struct MMUs to spare */ | |
| /* Set the scene for the next search */ | |
| kvm->arch.nested_mmus_next = (i + 1) % kvm->arch.nested_mmus_size; | |
| /* Make sure we don't forget to do the laundry */ | |
| if (kvm_s2_mmu_valid(s2_mmu)) { | |
| kvm_nested_s2_ptdump_remove_debugfs(s2_mmu); | |
| s2_mmu->pending_unmap = true; | |
| } | |
| /* | |
| * The virtual VMID (modulo CnP) will be used as a key when matching | |
| * an existing kvm_s2_mmu. | |
| * | |
| * We cache VTCR at allocation time, once and for all. It'd be great | |
| * if the guest didn't screw that one up, as this is not very | |
| * forgiving... | |
| */ | |
| s2_mmu->tlb_vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2) & ~VTTBR_CNP_BIT; | |
| s2_mmu->tlb_vtcr = vcpu_read_sys_reg(vcpu, VTCR_EL2); | |
| s2_mmu->nested_stage2_enabled = vcpu_read_sys_reg(vcpu, HCR_EL2) & HCR_VM; | |
| kvm_nested_s2_ptdump_create_debugfs(s2_mmu); | |
| out: | |
| atomic_inc(&s2_mmu->refcnt); | |
| /* | |
| * Set the vCPU request to perform an unmap, even if the pending unmap | |
| * originates from another vCPU. This guarantees that the MMU has been | |
| * completely unmapped before any vCPU actually uses it, and allows | |
| * multiple vCPUs to lend a hand with completing the unmap. | |
| */ | |
| if (s2_mmu->pending_unmap) | |
| kvm_make_request(KVM_REQ_NESTED_S2_UNMAP, vcpu); | |
| return s2_mmu; | |
| } | |
| void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu) | |
| { | |
| /* CnP being set denotes an invalid entry */ | |
| mmu->tlb_vttbr = VTTBR_CNP_BIT; | |
| mmu->nested_stage2_enabled = false; | |
| atomic_set(&mmu->refcnt, 0); | |
| } | |
| void kvm_vcpu_load_hw_mmu(struct kvm_vcpu *vcpu) | |
| { | |
| /* | |
| * If the vCPU kept its reference on the MMU after the last put, | |
| * keep rolling with it. | |
| */ | |
| if (is_hyp_ctxt(vcpu)) { | |
| if (!vcpu->arch.hw_mmu) | |
| vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu; | |
| } else { | |
| if (!vcpu->arch.hw_mmu) { | |
| scoped_guard(write_lock, &vcpu->kvm->mmu_lock) | |
| vcpu->arch.hw_mmu = get_s2_mmu_nested(vcpu); | |
| } | |
| if (__vcpu_sys_reg(vcpu, HCR_EL2) & HCR_NV) | |
| kvm_make_request(KVM_REQ_MAP_L1_VNCR_EL2, vcpu); | |
| } | |
| } | |
| /* | |
| * Unmapping an L1 VNCR can happen concurrently without the mmu lock being | |
| * effective (vcpu_put() vs TLBI handling). The atomic_xchg below ensures | |
| * that only one CPU sets it to -1 while getting a valid CPU number back. | |
| */ | |
| static int unmap_l1_vncr(struct vncr_tlb *vt) | |
| { | |
| int cpu = atomic_xchg_relaxed(&vt->cpu, -1); | |
| if (cpu != -1) | |
| clear_fixmap(vncr_fixmap(cpu)); | |
| return cpu; | |
| } | |
| static void this_cpu_reset_vncr_fixmap(struct kvm_vcpu *vcpu) | |
| { | |
| if (!host_data_test_flag(L1_VNCR_MAPPED)) | |
| return; | |
| BUG_ON(is_hyp_ctxt(vcpu)); | |
| /* | |
| * Unconditionally unmap the local VNCR if we have lost the race | |
| * against a concurrent TLBI. Otherwise we could end-up running | |
| * another vcpu with VNCR still mapped if the TLBI thread is | |
| * preempted between the exchange and the clear_fixmap(). | |
| * | |
| * Note that we do not care about the TLBI nuking the fixmap behind | |
| * the back of an running vcpu. This will only generate a fault and | |
| * possibly a retranslation. | |
| */ | |
| if (unmap_l1_vncr(vcpu->arch.vncr_tlb) == -1) | |
| clear_fixmap(vncr_fixmap(smp_processor_id())); | |
| host_data_clear_flag(L1_VNCR_MAPPED); | |
| } | |
| void kvm_vcpu_put_hw_mmu(struct kvm_vcpu *vcpu) | |
| { | |
| /* Unconditionally drop the VNCR mapping if we have one */ | |
| this_cpu_reset_vncr_fixmap(vcpu); | |
| /* | |
| * Keep a reference on the associated stage-2 MMU if the vCPU is | |
| * scheduling out and not in WFI emulation, suggesting it is likely to | |
| * reuse the MMU sometime soon. | |
| */ | |
| if (vcpu->scheduled_out && !vcpu_get_flag(vcpu, IN_WFI)) | |
| return; | |
| if (kvm_is_nested_s2_mmu(vcpu->kvm, vcpu->arch.hw_mmu)) | |
| atomic_dec(&vcpu->arch.hw_mmu->refcnt); | |
| vcpu->arch.hw_mmu = NULL; | |
| } | |
| /* | |
| * Returns non-zero if permission fault is handled by injecting it to the next | |
| * level hypervisor. | |
| */ | |
| int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu, struct kvm_s2_trans *trans) | |
| { | |
| bool forward_fault = false; | |
| trans->esr = 0; | |
| if (!kvm_vcpu_trap_is_permission_fault(vcpu)) | |
| return 0; | |
| if (kvm_vcpu_trap_is_iabt(vcpu)) { | |
| if (vcpu_mode_priv(vcpu)) | |
| forward_fault = !kvm_s2_trans_exec_el1(vcpu->kvm, trans); | |
| else | |
| forward_fault = !kvm_s2_trans_exec_el0(vcpu->kvm, trans); | |
| } else { | |
| bool write_fault = kvm_is_write_fault(vcpu); | |
| forward_fault = ((write_fault && !trans->writable) || | |
| (!write_fault && !trans->readable)); | |
| } | |
| if (forward_fault) | |
| trans->esr = esr_s2_fault(vcpu, trans->level, ESR_ELx_FSC_PERM); | |
| return forward_fault; | |
| } | |
| int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2) | |
| { | |
| vcpu_write_sys_reg(vcpu, vcpu->arch.fault.far_el2, FAR_EL2); | |
| vcpu_write_sys_reg(vcpu, vcpu->arch.fault.hpfar_el2, HPFAR_EL2); | |
| return kvm_inject_nested_sync(vcpu, esr_el2); | |
| } | |
| u16 get_asid_by_regime(struct kvm_vcpu *vcpu, enum trans_regime regime) | |
| { | |
| enum vcpu_sysreg ttbr_elx; | |
| u64 tcr; | |
| u16 asid; | |
| switch (regime) { | |
| case TR_EL10: | |
| tcr = vcpu_read_sys_reg(vcpu, TCR_EL1); | |
| ttbr_elx = (tcr & TCR_A1) ? TTBR1_EL1 : TTBR0_EL1; | |
| break; | |
| case TR_EL20: | |
| tcr = vcpu_read_sys_reg(vcpu, TCR_EL2); | |
| ttbr_elx = (tcr & TCR_A1) ? TTBR1_EL2 : TTBR0_EL2; | |
| break; | |
| default: | |
| BUG(); | |
| } | |
| asid = FIELD_GET(TTBRx_EL1_ASID, vcpu_read_sys_reg(vcpu, ttbr_elx)); | |
| if (!kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR0_EL1, ASIDBITS, 16) || | |
| !(tcr & TCR_ASID16)) | |
| asid &= GENMASK(7, 0); | |
| return asid; | |
| } | |
| static void invalidate_vncr(struct kvm *kvm, struct vncr_tlb *vt) | |
| { | |
| BUG_ON(!vt->valid); | |
| vt->valid = false; | |
| unmap_l1_vncr(vt); | |
| atomic_dec(&kvm->arch.vncr_tlb_count); | |
| } | |
| static bool vncr_tlb_intersects(struct vncr_tlb *vt, u64 addr, | |
| u64 scope_start, u64 scope_size) | |
| { | |
| u64 tlb_size, tlb_start, tlb_end, scope_end; | |
| tlb_size = ttl_to_size(pgshift_level_to_ttl(vt->wi.pgshift, vt->wr.level)); | |
| tlb_start = addr & ~(tlb_size - 1); | |
| tlb_end = tlb_start + tlb_size - 1; | |
| scope_end = scope_start + scope_size - 1; | |
| return !(tlb_end < scope_start || tlb_start > scope_end); | |
| } | |
| /* | |
| * VNCR TLB invalidation occurs from MMU notifiers or TLBI instructions, and | |
| * either can race against a vcpu not being onlined yet (no pseudo-TLB | |
| * allocated). Similarly, the TLB might be invalid. Skip those, as they | |
| * obviously don't participate in the invalidation at this stage. | |
| */ | |
| #define kvm_for_each_vncr_tlb(idx, vcpup, tlbp, kvm) \ | |
| kvm_for_each_vcpu(idx, vcpup, kvm) \ | |
| if (((tlbp) = vcpup->arch.vncr_tlb) && \ | |
| (tlbp)->valid) | |
| static void kvm_invalidate_vncr_ipa(struct kvm *kvm, u64 start, u64 end) | |
| { | |
| struct kvm_vcpu *vcpu; | |
| struct vncr_tlb *vt; | |
| unsigned long i; | |
| lockdep_assert_held_write(&kvm->mmu_lock); | |
| if (!kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY)) | |
| return; | |
| /* | |
| * Note that invalidating the VNCR on the back of an MMU notifier | |
| * doesn't require messing with the invalidation counter for a | |
| * parallel walk. The notifier itself will have bumped the counter, | |
| * making sure we rewalk. | |
| */ | |
| kvm_for_each_vncr_tlb(i, vcpu, vt, kvm) | |
| if (vncr_tlb_intersects(vt, vt->wr.pa, start, end - start)) | |
| invalidate_vncr(kvm, vt); | |
| } | |
| struct s1e2_tlbi_scope { | |
| enum { | |
| TLBI_ALL, | |
| TLBI_VA, | |
| TLBI_VAA, | |
| TLBI_ASID, | |
| } type; | |
| u16 asid; | |
| u64 va; | |
| u64 size; | |
| }; | |
| static void invalidate_vncr_va(struct kvm *kvm, | |
| struct s1e2_tlbi_scope *scope) | |
| { | |
| struct kvm_vcpu *vcpu; | |
| struct vncr_tlb *vt; | |
| unsigned long i; | |
| lockdep_assert_held_write(&kvm->mmu_lock); | |
| /* | |
| * We might be performing a parallel S1 walk, so bump up the | |
| * invalidation counter even in the absence of an actual VNCR TLB | |
| * invalidation, as this could indicate that the guest has gone | |
| * through a BBM sequence. | |
| */ | |
| kvm->mmu_invalidate_seq++; | |
| smp_wmb(); | |
| kvm_for_each_vncr_tlb(i, vcpu, vt, kvm) { | |
| switch (scope->type) { | |
| case TLBI_ALL: | |
| break; | |
| case TLBI_VA: | |
| if (!vncr_tlb_intersects(vt, vt->gva, scope->va, scope->size)) | |
| continue; | |
| if (vt->wr.nG && vt->wr.asid != scope->asid) | |
| continue; | |
| break; | |
| case TLBI_VAA: | |
| if (!vncr_tlb_intersects(vt, vt->gva, scope->va, scope->size)) | |
| continue; | |
| break; | |
| case TLBI_ASID: | |
| if (!vt->wr.nG || vt->wr.asid != scope->asid) | |
| continue; | |
| break; | |
| } | |
| invalidate_vncr(kvm, vt); | |
| } | |
| } | |
| #define tlbi_va_s1_to_va(v) (u64)sign_extend64((v) << 12, 48) | |
| static void compute_s1_tlbi_range(struct kvm_vcpu *vcpu, u32 inst, u64 val, | |
| struct s1e2_tlbi_scope *scope) | |
| { | |
| switch (inst) { | |
| case OP_TLBI_ALLE2: | |
| case OP_TLBI_ALLE2IS: | |
| case OP_TLBI_ALLE2OS: | |
| case OP_TLBI_VMALLE1: | |
| case OP_TLBI_VMALLE1IS: | |
| case OP_TLBI_VMALLE1OS: | |
| case OP_TLBI_ALLE2NXS: | |
| case OP_TLBI_ALLE2ISNXS: | |
| case OP_TLBI_ALLE2OSNXS: | |
| case OP_TLBI_VMALLE1NXS: | |
| case OP_TLBI_VMALLE1ISNXS: | |
| case OP_TLBI_VMALLE1OSNXS: | |
| scope->type = TLBI_ALL; | |
| break; | |
| case OP_TLBI_VAE2: | |
| case OP_TLBI_VAE2IS: | |
| case OP_TLBI_VAE2OS: | |
| case OP_TLBI_VAE1: | |
| case OP_TLBI_VAE1IS: | |
| case OP_TLBI_VAE1OS: | |
| case OP_TLBI_VAE2NXS: | |
| case OP_TLBI_VAE2ISNXS: | |
| case OP_TLBI_VAE2OSNXS: | |
| case OP_TLBI_VAE1NXS: | |
| case OP_TLBI_VAE1ISNXS: | |
| case OP_TLBI_VAE1OSNXS: | |
| case OP_TLBI_VALE2: | |
| case OP_TLBI_VALE2IS: | |
| case OP_TLBI_VALE2OS: | |
| case OP_TLBI_VALE1: | |
| case OP_TLBI_VALE1IS: | |
| case OP_TLBI_VALE1OS: | |
| case OP_TLBI_VALE2NXS: | |
| case OP_TLBI_VALE2ISNXS: | |
| case OP_TLBI_VALE2OSNXS: | |
| case OP_TLBI_VALE1NXS: | |
| case OP_TLBI_VALE1ISNXS: | |
| case OP_TLBI_VALE1OSNXS: | |
| scope->type = TLBI_VA; | |
| scope->size = ttl_to_size(FIELD_GET(TLBI_TTL_MASK, val)); | |
| scope->va = tlbi_va_s1_to_va(val) & ~(scope->size - 1); | |
| scope->asid = FIELD_GET(TLBIR_ASID_MASK, val); | |
| break; | |
| case OP_TLBI_ASIDE1: | |
| case OP_TLBI_ASIDE1IS: | |
| case OP_TLBI_ASIDE1OS: | |
| case OP_TLBI_ASIDE1NXS: | |
| case OP_TLBI_ASIDE1ISNXS: | |
| case OP_TLBI_ASIDE1OSNXS: | |
| scope->type = TLBI_ASID; | |
| scope->asid = FIELD_GET(TLBIR_ASID_MASK, val); | |
| break; | |
| case OP_TLBI_VAAE1: | |
| case OP_TLBI_VAAE1IS: | |
| case OP_TLBI_VAAE1OS: | |
| case OP_TLBI_VAAE1NXS: | |
| case OP_TLBI_VAAE1ISNXS: | |
| case OP_TLBI_VAAE1OSNXS: | |
| case OP_TLBI_VAALE1: | |
| case OP_TLBI_VAALE1IS: | |
| case OP_TLBI_VAALE1OS: | |
| case OP_TLBI_VAALE1NXS: | |
| case OP_TLBI_VAALE1ISNXS: | |
| case OP_TLBI_VAALE1OSNXS: | |
| scope->type = TLBI_VAA; | |
| scope->size = ttl_to_size(FIELD_GET(TLBI_TTL_MASK, val)); | |
| scope->va = tlbi_va_s1_to_va(val) & ~(scope->size - 1); | |
| break; | |
| case OP_TLBI_RVAE2: | |
| case OP_TLBI_RVAE2IS: | |
| case OP_TLBI_RVAE2OS: | |
| case OP_TLBI_RVAE1: | |
| case OP_TLBI_RVAE1IS: | |
| case OP_TLBI_RVAE1OS: | |
| case OP_TLBI_RVAE2NXS: | |
| case OP_TLBI_RVAE2ISNXS: | |
| case OP_TLBI_RVAE2OSNXS: | |
| case OP_TLBI_RVAE1NXS: | |
| case OP_TLBI_RVAE1ISNXS: | |
| case OP_TLBI_RVAE1OSNXS: | |
| case OP_TLBI_RVALE2: | |
| case OP_TLBI_RVALE2IS: | |
| case OP_TLBI_RVALE2OS: | |
| case OP_TLBI_RVALE1: | |
| case OP_TLBI_RVALE1IS: | |
| case OP_TLBI_RVALE1OS: | |
| case OP_TLBI_RVALE2NXS: | |
| case OP_TLBI_RVALE2ISNXS: | |
| case OP_TLBI_RVALE2OSNXS: | |
| case OP_TLBI_RVALE1NXS: | |
| case OP_TLBI_RVALE1ISNXS: | |
| case OP_TLBI_RVALE1OSNXS: | |
| scope->type = TLBI_VA; | |
| scope->va = decode_range_tlbi(val, &scope->size, &scope->asid); | |
| break; | |
| case OP_TLBI_RVAAE1: | |
| case OP_TLBI_RVAAE1IS: | |
| case OP_TLBI_RVAAE1OS: | |
| case OP_TLBI_RVAAE1NXS: | |
| case OP_TLBI_RVAAE1ISNXS: | |
| case OP_TLBI_RVAAE1OSNXS: | |
| case OP_TLBI_RVAALE1: | |
| case OP_TLBI_RVAALE1IS: | |
| case OP_TLBI_RVAALE1OS: | |
| case OP_TLBI_RVAALE1NXS: | |
| case OP_TLBI_RVAALE1ISNXS: | |
| case OP_TLBI_RVAALE1OSNXS: | |
| scope->type = TLBI_VAA; | |
| scope->va = decode_range_tlbi(val, &scope->size, NULL); | |
| break; | |
| } | |
| } | |
| void kvm_handle_s1e2_tlbi(struct kvm_vcpu *vcpu, u32 inst, u64 val) | |
| { | |
| struct s1e2_tlbi_scope scope = {}; | |
| compute_s1_tlbi_range(vcpu, inst, val, &scope); | |
| guard(write_lock)(&vcpu->kvm->mmu_lock); | |
| invalidate_vncr_va(vcpu->kvm, &scope); | |
| } | |
| static void kvm_invalidate_vncr_ipa_all(struct kvm *kvm) | |
| { | |
| struct kvm_pgtable *pgt = kvm->arch.mmu.pgt; | |
| lockdep_assert_held_write(&kvm->mmu_lock); | |
| /* if the mmu lock was dropped, pgt teardown may have raced. */ | |
| if (pgt) | |
| kvm_invalidate_vncr_ipa(kvm, 0, BIT(pgt->ia_bits)); | |
| } | |
| void kvm_nested_s2_wp(struct kvm *kvm) | |
| { | |
| int i; | |
| lockdep_assert_held_write(&kvm->mmu_lock); | |
| if (!kvm->arch.nested_mmus_size) | |
| return; | |
| for (i = 0; i < kvm->arch.nested_mmus_size; i++) { | |
| struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; | |
| if (kvm_s2_mmu_valid(mmu)) | |
| kvm_stage2_wp_range(mmu, 0, kvm_phys_size(mmu)); | |
| } | |
| kvm_invalidate_vncr_ipa_all(kvm); | |
| } | |
| void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block) | |
| { | |
| int i; | |
| lockdep_assert_held_write(&kvm->mmu_lock); | |
| if (!kvm->arch.nested_mmus_size) | |
| return; | |
| for (i = 0; i < kvm->arch.nested_mmus_size; i++) { | |
| struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; | |
| if (kvm_s2_mmu_valid(mmu)) | |
| kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu), may_block); | |
| } | |
| kvm_invalidate_vncr_ipa_all(kvm); | |
| } | |
| void kvm_nested_s2_flush(struct kvm *kvm) | |
| { | |
| int i; | |
| lockdep_assert_held_write(&kvm->mmu_lock); | |
| if (!kvm->arch.nested_mmus_size) | |
| return; | |
| for (i = 0; i < kvm->arch.nested_mmus_size; i++) { | |
| struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; | |
| if (kvm_s2_mmu_valid(mmu)) | |
| kvm_stage2_flush_range(mmu, 0, kvm_phys_size(mmu)); | |
| } | |
| } | |
| void kvm_arch_flush_shadow_all(struct kvm *kvm) | |
| { | |
| for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { | |
| struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; | |
| if (!WARN_ON(atomic_read(&mmu->refcnt))) | |
| kvm_free_stage2_pgd(mmu); | |
| } | |
| kvm_uninit_stage2_mmu(kvm); | |
| } | |
| /* | |
| * Dealing with VNCR_EL2 exposed by the *guest* is a complicated matter: | |
| * | |
| * - We introduce an internal representation of a vcpu-private TLB, | |
| * representing the mapping between the guest VA contained in VNCR_EL2, | |
| * the IPA the guest's EL2 PTs point to, and the actual PA this lives at. | |
| * | |
| * - On translation fault from a nested VNCR access, we create such a TLB. | |
| * If there is no mapping to describe, the guest inherits the fault. | |
| * Crucially, no actual mapping is done at this stage. | |
| * | |
| * - On vcpu_load() in a non-HYP context with HCR_EL2.NV==1, if the above | |
| * TLB exists, we map it in the fixmap for this CPU, and run with it. We | |
| * have to respect the permissions dictated by the guest, but not the | |
| * memory type (FWB is a must). | |
| * | |
| * - Note that we usually don't do a vcpu_load() on the back of a fault | |
| * (unless we are preempted), so the resolution of a translation fault | |
| * must go via a request that will map the VNCR page in the fixmap. | |
| * vcpu_load() might as well use the same mechanism. | |
| * | |
| * - On vcpu_put() in a non-HYP context with HCR_EL2.NV==1, if the TLB was | |
| * mapped, we unmap it. Yes it is that simple. The TLB still exists | |
| * though, and may be reused at a later load. | |
| * | |
| * - On permission fault, we simply forward the fault to the guest's EL2. | |
| * Get out of my way. | |
| * | |
| * - On any TLBI for the EL2&0 translation regime, we must find any TLB that | |
| * intersects with the TLBI request, invalidate it, and unmap the page | |
| * from the fixmap. Because we need to look at all the vcpu-private TLBs, | |
| * this requires some wide-ranging locking to ensure that nothing races | |
| * against it. This requires some refcounting to avoid the search when | |
| * no such TLB is present (see below). | |
| * | |
| * - On MMU notifiers, we must invalidate our TLB in a similar way, but | |
| * looking at the IPA instead. The funny part is that there may not be a | |
| * stage-2 mapping for this page if L1 hasn't accessed it using LD/ST | |
| * instructions. | |
| * | |
| * - vncr_tlb_count tracks the number of valid VNCR TLBs VM-wide. This isn't | |
| * the number of *mapped* L1 VNCR pages, which is likely be a subset (and | |
| * by definition, a TLBI handled from L1 runs with the canonical VNCR | |
| * page, not the L1's). The innermost trap handling code checks this to | |
| * find out whether to return to the guest ASAP (no L1 TLBs) or to visit | |
| * this part of the world for some extra invalidation work. | |
| */ | |
| int kvm_vcpu_allocate_vncr_tlb(struct kvm_vcpu *vcpu) | |
| { | |
| if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY)) | |
| return 0; | |
| if (!vcpu->arch.vncr_tlb) { | |
| struct vncr_tlb *vt = kzalloc_obj(*vcpu->arch.vncr_tlb, | |
| GFP_KERNEL_ACCOUNT); | |
| /* | |
| * Taking the lock on assignment ensures that the TLB is | |
| * seen as initialised when following the pointer (release | |
| * semantics of the unlock), and avoids having acquires on | |
| * each user which already take the lock. | |
| */ | |
| scoped_guard(write_lock, &vcpu->kvm->mmu_lock) | |
| vcpu->arch.vncr_tlb = vt; | |
| } | |
| if (!vcpu->arch.vncr_tlb) | |
| return -ENOMEM; | |
| return 0; | |
| } | |
| static u64 read_vncr_el2(struct kvm_vcpu *vcpu) | |
| { | |
| return (u64)sign_extend64(__vcpu_sys_reg(vcpu, VNCR_EL2), 48); | |
| } | |
| static int kvm_translate_vncr(struct kvm_vcpu *vcpu, bool *is_gmem) | |
| { | |
| struct kvm_memory_slot *memslot; | |
| bool write_fault, writable; | |
| unsigned long mmu_seq; | |
| struct vncr_tlb *vt; | |
| struct page *page; | |
| u64 va, pfn, gfn; | |
| int ret; | |
| vt = vcpu->arch.vncr_tlb; | |
| /* | |
| * If we're about to walk the EL2 S1 PTs, we must invalidate the | |
| * current TLB, as it could be sampled from another vcpu doing a | |
| * TLBI *IS. A real CPU wouldn't do that, but we only keep a single | |
| * translation, so not much of a choice. | |
| * | |
| * We also prepare the next walk wilst we're at it. | |
| */ | |
| scoped_guard(write_lock, &vcpu->kvm->mmu_lock) { | |
| this_cpu_reset_vncr_fixmap(vcpu); | |
| if (vt->valid) | |
| invalidate_vncr(vcpu->kvm, vt); | |
| vt->wi = (struct s1_walk_info) { | |
| .regime = TR_EL20, | |
| .as_el0 = false, | |
| .pan = false, | |
| }; | |
| vt->wr = (struct s1_walk_result){}; | |
| } | |
| guard(srcu)(&vcpu->kvm->srcu); | |
| va = read_vncr_el2(vcpu); | |
| mmu_seq = vcpu->kvm->mmu_invalidate_seq; | |
| smp_rmb(); | |
| ret = __kvm_translate_va(vcpu, &vt->wi, &vt->wr, va); | |
| if (ret) | |
| return ret; | |
| write_fault = kvm_is_write_fault(vcpu); | |
| gfn = vt->wr.pa >> PAGE_SHIFT; | |
| memslot = gfn_to_memslot(vcpu->kvm, gfn); | |
| if (!memslot) { | |
| fail_s1_walk(&vt->wr, ESR_ELx_FSC_EXTABT, false); | |
| return -EFAULT; | |
| } | |
| *is_gmem = kvm_slot_has_gmem(memslot); | |
| if (!*is_gmem) { | |
| pfn = __kvm_faultin_pfn(memslot, gfn, write_fault ? FOLL_WRITE : 0, | |
| &writable, &page); | |
| if (is_error_noslot_pfn(pfn)) { | |
| fail_s1_walk(&vt->wr, ESR_ELx_FSC_EXTABT, false); | |
| return -EFAULT; | |
| } | |
| } else { | |
| ret = kvm_gmem_get_pfn(vcpu->kvm, memslot, gfn, &pfn, &page, NULL); | |
| if (ret) { | |
| kvm_prepare_memory_fault_exit(vcpu, vt->wr.pa, PAGE_SIZE, | |
| write_fault, false, false); | |
| return ret; | |
| } | |
| writable = !(memslot->flags & KVM_MEM_READONLY); | |
| } | |
| /* | |
| * FIXME: This check is too restrictive as KVM allows cacheable memory | |
| * attributes for PFNMAP VMAs that have cacheable attributes in host | |
| * stage-1. | |
| */ | |
| if (!pfn_is_map_memory(pfn)) { | |
| kvm_release_faultin_page(vcpu->kvm, page, true, false); | |
| fail_s1_walk(&vt->wr, ESR_ELx_FSC_EXTABT, false); | |
| return -EINVAL; | |
| } | |
| scoped_guard(write_lock, &vcpu->kvm->mmu_lock) { | |
| if (mmu_invalidate_retry(vcpu->kvm, mmu_seq)) { | |
| kvm_release_faultin_page(vcpu->kvm, page, true, false); | |
| return -EAGAIN; | |
| } | |
| vt->gva = va; | |
| vt->hpa = pfn << PAGE_SHIFT; | |
| vt->hpa_writable = writable; | |
| vt->valid = true; | |
| atomic_set(&vt->cpu, -1); | |
| kvm_make_request(KVM_REQ_MAP_L1_VNCR_EL2, vcpu); | |
| kvm_release_faultin_page(vcpu->kvm, page, false, vt->wr.pw && vt->hpa_writable); | |
| } | |
| if (vt->wr.pw && vt->hpa_writable) | |
| mark_page_dirty(vcpu->kvm, gfn); | |
| return 0; | |
| } | |
| static void handle_vncr_perm(struct kvm_vcpu *vcpu) | |
| { | |
| struct vncr_tlb *vt = vcpu->arch.vncr_tlb; | |
| u64 esr = kvm_vcpu_get_esr(vcpu); | |
| u64 fsc; | |
| /* | |
| * Promote to an external abort if the stage-1 permits writes but the | |
| * HPA is read-only (e.g. RO memslot). | |
| */ | |
| if (kvm_is_write_fault(vcpu) && vt->wr.pw && !vt->hpa_writable) | |
| fsc = ESR_ELx_FSC_EXTABT; | |
| /* | |
| * Otherwise, inject a permission fault using the guest's translation | |
| * level rather than the host's. | |
| */ | |
| else | |
| fsc = ESR_ELx_FSC_PERM_L(vt->wr.level); | |
| esr &= ~ESR_ELx_FSC; | |
| esr |= FIELD_PREP(ESR_ELx_FSC, fsc); | |
| kvm_inject_nested_sync(vcpu, esr); | |
| } | |
| int kvm_handle_vncr_abort(struct kvm_vcpu *vcpu) | |
| { | |
| struct vncr_tlb *vt = vcpu->arch.vncr_tlb; | |
| u64 esr = kvm_vcpu_get_esr(vcpu); | |
| bool is_gmem = false; | |
| bool perm; | |
| int ret; | |
| WARN_ON_ONCE(!(esr & ESR_ELx_VNCR)); | |
| if (kvm_vcpu_abt_issea(vcpu)) | |
| return kvm_handle_guest_sea(vcpu); | |
| if (!esr_fsc_is_translation_fault(esr) && !esr_fsc_is_permission_fault(esr)) { | |
| KVM_BUG(1, vcpu->kvm, "Unhandled VNCR abort, ESR=%llx\n", esr); | |
| return -EIO; | |
| } | |
| /* | |
| * Speculatively increment the TLB count to make sure concurrent | |
| * TLBIs will take the slow path, and will interact with the retry | |
| * mechanism. Drop it again on error. | |
| */ | |
| atomic_inc(&vcpu->kvm->arch.vncr_tlb_count); | |
| smp_mb__after_atomic(); | |
| ret = kvm_translate_vncr(vcpu, &is_gmem); | |
| if (ret) { | |
| smp_mb__before_atomic(); | |
| atomic_dec(&vcpu->kvm->arch.vncr_tlb_count); | |
| } | |
| switch (ret) { | |
| case -EAGAIN: | |
| /* Let's try again... */ | |
| return 1; | |
| case -ENOMEM: | |
| /* | |
| * For guest_memfd, this indicates that it failed to | |
| * create a folio to back the memory. Inform userspace. | |
| */ | |
| if (is_gmem) | |
| return 0; | |
| /* Otherwise, let's try again... */ | |
| break; | |
| case -EFAULT: | |
| case -EIO: | |
| case -EHWPOISON: | |
| if (is_gmem) | |
| return 0; | |
| fallthrough; | |
| case -EINVAL: | |
| case -ENOENT: | |
| case -EACCES: | |
| /* | |
| * Translation failed, inject the corresponding | |
| * exception back to EL2. | |
| */ | |
| esr &= ~ESR_ELx_FSC; | |
| esr |= FIELD_PREP(ESR_ELx_FSC, vt->wr.fst); | |
| kvm_inject_nested_sync(vcpu, esr); | |
| break; | |
| case 0: | |
| perm = kvm_is_write_fault(vcpu) ? vt->wr.pw && vt->hpa_writable : vt->wr.pr; | |
| if (!perm) | |
| handle_vncr_perm(vcpu); | |
| break; | |
| } | |
| return 1; | |
| } | |
| static void kvm_map_l1_vncr(struct kvm_vcpu *vcpu) | |
| { | |
| struct vncr_tlb *vt = vcpu->arch.vncr_tlb; | |
| pgprot_t prot; | |
| guard(preempt)(); | |
| guard(read_lock)(&vcpu->kvm->mmu_lock); | |
| /* | |
| * The request to map VNCR may have raced against some other | |
| * event, such as an interrupt, and may not be valid anymore. | |
| */ | |
| if (is_hyp_ctxt(vcpu)) | |
| return; | |
| /* | |
| * Check that the pseudo-TLB is valid and that VNCR_EL2 still | |
| * contains the expected value. If it doesn't, we simply bail out | |
| * without a mapping -- a transformed MSR/MRS will generate the | |
| * fault and allows us to populate the pseudo-TLB. | |
| */ | |
| if (!vt->valid) | |
| return; | |
| /* We cache the MMU state in the TLB. Check that it matches. */ | |
| if (!!(vcpu_read_sys_reg(vcpu, SCTLR_EL2) & SCTLR_ELx_M) != s1_walk_translated(&vt->wr)) | |
| return; | |
| if (read_vncr_el2(vcpu) != vt->gva) | |
| return; | |
| if (vt->wr.nG && get_asid_by_regime(vcpu, TR_EL20) != vt->wr.asid) | |
| return; | |
| if (vt->hpa_writable && vt->wr.pw && vt->wr.pr) | |
| prot = PAGE_KERNEL; | |
| else if (vt->wr.pr) | |
| prot = PAGE_KERNEL_RO; | |
| else | |
| prot = PAGE_NONE; | |
| /* | |
| * We can't map write-only (or no permission at all) in the kernel, | |
| * but the guest can do it if using POE, so we'll have to turn a | |
| * translation fault into a permission fault at runtime. | |
| * FIXME: WO doesn't work at all, need POE support in the kernel. | |
| */ | |
| if (pgprot_val(prot) != pgprot_val(PAGE_NONE)) { | |
| atomic_set(&vt->cpu, smp_processor_id()); | |
| __set_fixmap(vncr_fixmap(atomic_read(&vt->cpu)), vt->hpa, prot); | |
| host_data_set_flag(L1_VNCR_MAPPED); | |
| } | |
| } | |
| /* | |
| * Our emulated CPU doesn't support all the possible features. For the | |
| * sake of simplicity (and probably mental sanity), wipe out a number | |
| * of feature bits we don't intend to support for the time being. | |
| * This list should get updated as new features get added to the NV | |
| * support, and new extension to the architecture. | |
| */ | |
| u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val) | |
| { | |
| u64 orig_val = val; | |
| switch (reg) { | |
| case SYS_ID_AA64ISAR1_EL1: | |
| /* Support everything but LS64 and Spec Invalidation */ | |
| val &= ~(ID_AA64ISAR1_EL1_LS64 | | |
| ID_AA64ISAR1_EL1_SPECRES); | |
| break; | |
| case SYS_ID_AA64PFR0_EL1: | |
| /* No RME, AMU, MPAM, or S-EL2 */ | |
| val &= ~(ID_AA64PFR0_EL1_RME | | |
| ID_AA64PFR0_EL1_AMU | | |
| ID_AA64PFR0_EL1_MPAM | | |
| ID_AA64PFR0_EL1_SEL2 | | |
| ID_AA64PFR0_EL1_EL3 | | |
| ID_AA64PFR0_EL1_EL2 | | |
| ID_AA64PFR0_EL1_EL1 | | |
| ID_AA64PFR0_EL1_EL0); | |
| /* 64bit only at any EL */ | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL0, IMP); | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL1, IMP); | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL2, IMP); | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL3, IMP); | |
| break; | |
| case SYS_ID_AA64PFR1_EL1: | |
| /* Only support BTI, SSBS, CSV2_frac */ | |
| val &= ~(ID_AA64PFR1_EL1_PFAR | | |
| ID_AA64PFR1_EL1_MTEX | | |
| ID_AA64PFR1_EL1_THE | | |
| ID_AA64PFR1_EL1_GCS | | |
| ID_AA64PFR1_EL1_MTE_frac | | |
| ID_AA64PFR1_EL1_NMI | | |
| ID_AA64PFR1_EL1_SME | | |
| ID_AA64PFR1_EL1_RES0 | | |
| ID_AA64PFR1_EL1_MPAM_frac | | |
| ID_AA64PFR1_EL1_MTE); | |
| break; | |
| case SYS_ID_AA64PFR2_EL1: | |
| /* GICv5 is not yet supported for NV */ | |
| val &= ~ID_AA64PFR2_EL1_GCIE; | |
| break; | |
| case SYS_ID_AA64MMFR0_EL1: | |
| /* Hide ExS, Secure Memory */ | |
| val &= ~(ID_AA64MMFR0_EL1_EXS | | |
| ID_AA64MMFR0_EL1_TGRAN4_2 | | |
| ID_AA64MMFR0_EL1_TGRAN16_2 | | |
| ID_AA64MMFR0_EL1_TGRAN64_2 | | |
| ID_AA64MMFR0_EL1_SNSMEM); | |
| /* Hide CNTPOFF if present */ | |
| val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64MMFR0_EL1, ECV, IMP); | |
| /* Disallow unsupported S2 page sizes */ | |
| switch (PAGE_SIZE) { | |
| case SZ_64K: | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN16_2, NI); | |
| fallthrough; | |
| case SZ_16K: | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN4_2, NI); | |
| fallthrough; | |
| case SZ_4K: | |
| /* Support everything */ | |
| break; | |
| } | |
| /* | |
| * Since we can't support a guest S2 page size smaller | |
| * than the host's own page size (due to KVM only | |
| * populating its own S2 using the kernel's page | |
| * size), advertise the limitation using FEAT_GTG. | |
| */ | |
| switch (PAGE_SIZE) { | |
| case SZ_4K: | |
| if (_has_tgran_2(orig_val, 4)) | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN4_2, IMP); | |
| fallthrough; | |
| case SZ_16K: | |
| if (_has_tgran_2(orig_val, 16)) | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN16_2, IMP); | |
| fallthrough; | |
| case SZ_64K: | |
| if (_has_tgran_2(orig_val, 64)) | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR0_EL1, TGRAN64_2, IMP); | |
| break; | |
| } | |
| /* Cap PARange to 48bits */ | |
| val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64MMFR0_EL1, PARANGE, 48); | |
| break; | |
| case SYS_ID_AA64MMFR1_EL1: | |
| val &= ~(ID_AA64MMFR1_EL1_CMOW | | |
| ID_AA64MMFR1_EL1_nTLBPA | | |
| ID_AA64MMFR1_EL1_ETS); | |
| /* FEAT_E2H0 implies no VHE */ | |
| if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features)) | |
| val &= ~ID_AA64MMFR1_EL1_VH; | |
| val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64MMFR1_EL1, HAFDBS, AF); | |
| break; | |
| case SYS_ID_AA64MMFR2_EL1: | |
| val &= ~(ID_AA64MMFR2_EL1_BBM | | |
| ID_AA64MMFR2_EL1_TTL | | |
| GENMASK_ULL(47, 44) | | |
| ID_AA64MMFR2_EL1_ST | | |
| ID_AA64MMFR2_EL1_CCIDX | | |
| ID_AA64MMFR2_EL1_VARange); | |
| /* Force TTL support */ | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR2_EL1, TTL, IMP); | |
| break; | |
| case SYS_ID_AA64MMFR4_EL1: | |
| /* | |
| * You get EITHER | |
| * | |
| * - FEAT_VHE without FEAT_E2H0 | |
| * - FEAT_NV limited to FEAT_NV2(p1)/NV3 | |
| * - HCR_EL2.NV1 being RES0 | |
| * | |
| * OR | |
| * | |
| * - FEAT_E2H0 without FEAT_VHE nor FEAT_NV | |
| * | |
| * Life is too short for anything else. | |
| */ | |
| if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features)) { | |
| val = 0; | |
| } else { | |
| val &= ID_AA64MMFR4_EL1_NV_frac; | |
| if (cpus_have_final_cap(ARM64_HAS_NV3)) | |
| val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64MMFR4_EL1, NV_frac, NV3); | |
| else if (cpus_have_final_cap(ARM64_HAS_NV2P1)) | |
| val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64MMFR4_EL1, NV_frac, NV2P1); | |
| else | |
| val = SYS_FIELD_PREP_ENUM(ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY); | |
| val |= SYS_FIELD_PREP_ENUM(ID_AA64MMFR4_EL1, E2H0, NI_NV1); | |
| } | |
| break; | |
| case SYS_ID_AA64DFR0_EL1: | |
| /* Only limited support for PMU, Debug, BPs, WPs, and HPMN0 */ | |
| val &= ~(ID_AA64DFR0_EL1_ExtTrcBuff | | |
| ID_AA64DFR0_EL1_BRBE | | |
| ID_AA64DFR0_EL1_MTPMU | | |
| ID_AA64DFR0_EL1_TraceBuffer | | |
| ID_AA64DFR0_EL1_TraceFilt | | |
| ID_AA64DFR0_EL1_PMSVer | | |
| ID_AA64DFR0_EL1_CTX_CMPs | | |
| ID_AA64DFR0_EL1_SEBEP | | |
| ID_AA64DFR0_EL1_PMSS | | |
| ID_AA64DFR0_EL1_TraceVer); | |
| /* | |
| * FEAT_Debugv8p9 requires support for extended breakpoints / | |
| * watchpoints. | |
| */ | |
| val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8); | |
| break; | |
| } | |
| return val; | |
| } | |
| u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *vcpu, | |
| enum vcpu_sysreg sr, u64 v) | |
| { | |
| struct resx resx; | |
| resx = kvm_get_sysreg_resx(vcpu->kvm, sr); | |
| v &= ~resx.res0; | |
| v |= resx.res1; | |
| return v; | |
| } | |
| static __always_inline void set_sysreg_masks(struct kvm *kvm, int sr, struct resx resx) | |
| { | |
| BUILD_BUG_ON(!__builtin_constant_p(sr)); | |
| BUILD_BUG_ON(sr < __SANITISED_REG_START__); | |
| BUILD_BUG_ON(sr >= NR_SYS_REGS); | |
| kvm_set_sysreg_resx(kvm, sr, resx); | |
| } | |
| int kvm_init_nv_sysregs(struct kvm_vcpu *vcpu) | |
| { | |
| struct kvm *kvm = vcpu->kvm; | |
| struct resx resx; | |
| lockdep_assert_held(&kvm->arch.config_lock); | |
| if (kvm->arch.sysreg_masks) | |
| goto out; | |
| kvm->arch.sysreg_masks = kzalloc_obj(*(kvm->arch.sysreg_masks), | |
| GFP_KERNEL_ACCOUNT); | |
| if (!kvm->arch.sysreg_masks) | |
| return -ENOMEM; | |
| /* VTTBR_EL2 */ | |
| resx = (typeof(resx)){}; | |
| if (!kvm_has_feat_enum(kvm, ID_AA64MMFR1_EL1, VMIDBits, 16)) | |
| resx.res0 |= GENMASK(63, 56); | |
| if (!kvm_has_feat(kvm, ID_AA64MMFR2_EL1, CnP, IMP)) | |
| resx.res0 |= VTTBR_CNP_BIT; | |
| set_sysreg_masks(kvm, VTTBR_EL2, resx); | |
| /* VTCR_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, VTCR_EL2); | |
| set_sysreg_masks(kvm, VTCR_EL2, resx); | |
| /* VMPIDR_EL2 */ | |
| resx.res0 = GENMASK(63, 40) | GENMASK(30, 24); | |
| resx.res1 = BIT(31); | |
| set_sysreg_masks(kvm, VMPIDR_EL2, resx); | |
| /* HCR_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, HCR_EL2); | |
| set_sysreg_masks(kvm, HCR_EL2, resx); | |
| /* NVHCR_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, NVHCR_EL2); | |
| set_sysreg_masks(kvm, NVHCR_EL2, resx); | |
| /* HCRX_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, HCRX_EL2); | |
| set_sysreg_masks(kvm, HCRX_EL2, resx); | |
| /* HFG[RW]TR_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, HFGRTR_EL2); | |
| set_sysreg_masks(kvm, HFGRTR_EL2, resx); | |
| resx = get_reg_fixed_bits(kvm, HFGWTR_EL2); | |
| set_sysreg_masks(kvm, HFGWTR_EL2, resx); | |
| /* HDFG[RW]TR_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, HDFGRTR_EL2); | |
| set_sysreg_masks(kvm, HDFGRTR_EL2, resx); | |
| resx = get_reg_fixed_bits(kvm, HDFGWTR_EL2); | |
| set_sysreg_masks(kvm, HDFGWTR_EL2, resx); | |
| /* HFGITR_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, HFGITR_EL2); | |
| set_sysreg_masks(kvm, HFGITR_EL2, resx); | |
| /* HAFGRTR_EL2 - not a lot to see here */ | |
| resx = get_reg_fixed_bits(kvm, HAFGRTR_EL2); | |
| set_sysreg_masks(kvm, HAFGRTR_EL2, resx); | |
| /* HFG[RW]TR2_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, HFGRTR2_EL2); | |
| set_sysreg_masks(kvm, HFGRTR2_EL2, resx); | |
| resx = get_reg_fixed_bits(kvm, HFGWTR2_EL2); | |
| set_sysreg_masks(kvm, HFGWTR2_EL2, resx); | |
| /* HDFG[RW]TR2_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, HDFGRTR2_EL2); | |
| set_sysreg_masks(kvm, HDFGRTR2_EL2, resx); | |
| resx = get_reg_fixed_bits(kvm, HDFGWTR2_EL2); | |
| set_sysreg_masks(kvm, HDFGWTR2_EL2, resx); | |
| /* HFGITR2_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, HFGITR2_EL2); | |
| set_sysreg_masks(kvm, HFGITR2_EL2, resx); | |
| /* TCR2_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, TCR2_EL2); | |
| set_sysreg_masks(kvm, TCR2_EL2, resx); | |
| /* SCTLR_EL1 */ | |
| resx = get_reg_fixed_bits(kvm, SCTLR_EL1); | |
| set_sysreg_masks(kvm, SCTLR_EL1, resx); | |
| /* SCTLR_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, SCTLR_EL2); | |
| set_sysreg_masks(kvm, SCTLR_EL2, resx); | |
| /* SCTLR2_ELx */ | |
| resx = get_reg_fixed_bits(kvm, SCTLR2_EL1); | |
| set_sysreg_masks(kvm, SCTLR2_EL1, resx); | |
| resx = get_reg_fixed_bits(kvm, SCTLR2_EL2); | |
| set_sysreg_masks(kvm, SCTLR2_EL2, resx); | |
| /* MDCR_EL2 */ | |
| resx = get_reg_fixed_bits(kvm, MDCR_EL2); | |
| set_sysreg_masks(kvm, MDCR_EL2, resx); | |
| /* CNTHCTL_EL2 */ | |
| resx.res0 = GENMASK(63, 20); | |
| resx.res1 = 0; | |
| if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, RME, IMP)) | |
| resx.res0 |= CNTHCTL_CNTPMASK | CNTHCTL_CNTVMASK; | |
| if (!kvm_has_feat(kvm, ID_AA64MMFR0_EL1, ECV, CNTPOFF)) { | |
| resx.res0 |= CNTHCTL_ECV; | |
| if (!kvm_has_feat(kvm, ID_AA64MMFR0_EL1, ECV, IMP)) | |
| resx.res0 |= (CNTHCTL_EL1TVT | CNTHCTL_EL1TVCT | | |
| CNTHCTL_EL1NVPCT | CNTHCTL_EL1NVVCT); | |
| } | |
| if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, VH, IMP)) | |
| resx.res0 |= GENMASK(11, 8); | |
| set_sysreg_masks(kvm, CNTHCTL_EL2, resx); | |
| /* ICH_HCR_EL2 */ | |
| resx.res0 = ICH_HCR_EL2_RES0; | |
| resx.res1 = ICH_HCR_EL2_RES1; | |
| if (!(vgic_ich_vtr() & ICH_VTR_EL2_TDS)) | |
| resx.res0 |= ICH_HCR_EL2_TDIR; | |
| /* No GICv4 is presented to the guest */ | |
| resx.res0 |= ICH_HCR_EL2_DVIM | ICH_HCR_EL2_vSGIEOICount; | |
| set_sysreg_masks(kvm, ICH_HCR_EL2, resx); | |
| /* VNCR_EL2 */ | |
| resx.res0 = VNCR_EL2_RES0; | |
| resx.res1 = VNCR_EL2_RES1; | |
| set_sysreg_masks(kvm, VNCR_EL2, resx); | |
| /* ZCR_EL2 - bits 8:4 are RAZ/WI so treat them as RES0 */ | |
| resx.res0 = ZCR_ELx_RES0 | GENMASK_ULL(8, 4); | |
| resx.res1 = ZCR_ELx_RES1; | |
| set_sysreg_masks(kvm, ZCR_EL2, resx); | |
| out: | |
| for (enum vcpu_sysreg sr = __SANITISED_REG_START__; sr < NR_SYS_REGS; sr++) | |
| __vcpu_rmw_sys_reg(vcpu, sr, |=, 0); | |
| return 0; | |
| } | |
| void check_nested_vcpu_requests(struct kvm_vcpu *vcpu) | |
| { | |
| if (kvm_check_request(KVM_REQ_NESTED_S2_UNMAP, vcpu)) { | |
| struct kvm_s2_mmu *mmu = vcpu->arch.hw_mmu; | |
| write_lock(&vcpu->kvm->mmu_lock); | |
| if (mmu->pending_unmap) { | |
| kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu), true); | |
| mmu->pending_unmap = false; | |
| } | |
| write_unlock(&vcpu->kvm->mmu_lock); | |
| } | |
| if (kvm_check_request(KVM_REQ_MAP_L1_VNCR_EL2, vcpu)) | |
| kvm_map_l1_vncr(vcpu); | |
| /* Must be last, as may switch context! */ | |
| if (kvm_check_request(KVM_REQ_GUEST_HYP_IRQ_PENDING, vcpu)) | |
| kvm_inject_nested_irq(vcpu); | |
| } | |
| /* | |
| * One of the many architectural bugs in FEAT_NV2 is that the guest hypervisor | |
| * can write to HCR_EL2 behind our back, potentially changing the exception | |
| * routing / masking for even the host context. | |
| * | |
| * What follows is some slop to (1) react to exception routing / masking and (2) | |
| * preserve the pending SError state across translation regimes. | |
| */ | |
| void kvm_nested_flush_hwstate(struct kvm_vcpu *vcpu) | |
| { | |
| if (!vcpu_has_nv(vcpu)) | |
| return; | |
| if (unlikely(vcpu_test_and_clear_flag(vcpu, NESTED_SERROR_PENDING))) | |
| kvm_inject_serror_esr(vcpu, vcpu_get_vsesr(vcpu)); | |
| } | |
| void kvm_nested_sync_hwstate(struct kvm_vcpu *vcpu) | |
| { | |
| unsigned long *hcr = vcpu_hcr(vcpu); | |
| if (!vcpu_has_nv(vcpu)) | |
| return; | |
| /* | |
| * We previously decided that an SError was deliverable to the guest. | |
| * Reap the pending state from HCR_EL2 and... | |
| */ | |
| if (unlikely(__test_and_clear_bit(__ffs(HCR_VSE), hcr))) | |
| vcpu_set_flag(vcpu, NESTED_SERROR_PENDING); | |
| /* | |
| * Re-attempt SError injection in case the deliverability has changed, | |
| * which is necessary to faithfully emulate WFI the case of a pending | |
| * SError being a wakeup condition. | |
| */ | |
| if (unlikely(vcpu_test_and_clear_flag(vcpu, NESTED_SERROR_PENDING))) | |
| kvm_inject_serror_esr(vcpu, vcpu_get_vsesr(vcpu)); | |
| } | |
| /* | |
| * KVM unconditionally sets most of these traps anyway but use an allowlist | |
| * to document the guest hypervisor traps that may take precedence and guard | |
| * against future changes to the non-nested trap configuration. | |
| */ | |
| #define NV_MDCR_GUEST_INCLUDE (MDCR_EL2_TDE | \ | |
| MDCR_EL2_TDA | \ | |
| MDCR_EL2_TDRA | \ | |
| MDCR_EL2_TTRF | \ | |
| MDCR_EL2_TPMS | \ | |
| MDCR_EL2_TPM | \ | |
| MDCR_EL2_TPMCR | \ | |
| MDCR_EL2_TDCC | \ | |
| MDCR_EL2_TDOSA) | |
| void kvm_nested_setup_mdcr_el2(struct kvm_vcpu *vcpu) | |
| { | |
| u64 guest_mdcr = __vcpu_sys_reg(vcpu, MDCR_EL2); | |
| if (is_nested_ctxt(vcpu)) | |
| vcpu->arch.mdcr_el2 |= (guest_mdcr & NV_MDCR_GUEST_INCLUDE); | |
| /* | |
| * In yet another example where FEAT_NV2 is fscking broken, accesses | |
| * to MDSCR_EL1 are redirected to the VNCR despite having an effect | |
| * at EL2. Use a big hammer to apply sanity. | |
| * | |
| * Unless of course we have FEAT_FGT, in which case we can precisely | |
| * trap MDSCR_EL1. | |
| */ | |
| else if (!cpus_have_final_cap(ARM64_HAS_FGT)) | |
| vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; | |
| } |