2104 lines · 52.9 KB · C
RawDownload
// 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 void kvm_init_nested(struct kvm *kvm){	kvm->arch.nested_mmus = NULL;	kvm->arch.nested_mmus_size = 0;	atomic_set(&kvm->arch.vncr_tlb_count, 0);} 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;	struct kvm_s2_mmu *tmp;	int num_mmus, ret = 0; 	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; 	/*	 * Let's treat memory allocation failures as benign: If we fail to	 * allocate anything, return an error and keep the allocated array	 * alive. Userspace may try to recover by initializing the vcpu	 * again, and there is no reason to affect the whole VM for this.	 */	num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU; 	if (num_mmus > kvm->arch.nested_mmus_size) {		tmp = kvzalloc_objs(*tmp, num_mmus, GFP_KERNEL_ACCOUNT);		if (!tmp)			return -ENOMEM; 		write_lock(&kvm->mmu_lock); 		if (kvm->arch.nested_mmus_size) {			memcpy(tmp, kvm->arch.nested_mmus,			       size_mul(sizeof(*tmp), kvm->arch.nested_mmus_size)); 			for (int i = 0; i < kvm->arch.nested_mmus_size; i++)				tmp[i].pgt->mmu = &tmp[i];		} 		swap(kvm->arch.nested_mmus, tmp); 		write_unlock(&kvm->mmu_lock); 		kvfree(tmp);	} 	for (int i = kvm->arch.nested_mmus_size; !ret && i < num_mmus; i++)		ret = init_nested_s2_mmu(kvm, &kvm->arch.nested_mmus[i]); 	if (ret) {		for (int i = kvm->arch.nested_mmus_size; i < num_mmus; i++)			kvm_free_stage2_pgd(&kvm->arch.nested_mmus[i]); 		free_page((unsigned long)vcpu->arch.ctxt.vncr_array);		vcpu->arch.ctxt.vncr_array = NULL; 		return ret;	} 	kvm->arch.nested_mmus_size = num_mmus; 	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; 

Lines 1–500 of 2104.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t