Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69bbe136 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull kvm fixes from Paolo Bonzini:
 "Fixes for ARM and aarch64.

  This pull request is coming a bit later than I would have preferred,
  because I and Gleb happened to have holidays around the same weeks of
  August...  sorry about that"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: ARM: Squash len warning
  arm64: KVM: use 'int' instead of 'u32' for variable 'target' in kvm_host.h.
  arm64: KVM: add missing dsb before invalidating Stage-2 TLBs
  arm64: KVM: perform save/restore of PAR_EL1
  arm64: KVM: fix 2-level page tables unmapping
  ARM: KVM: Fix unaligned unmap_range leak
  ARM: KVM: Fix 64-bit coprocessor handling
parents da2ad2a2 c566ccfc
Loading
Loading
Loading
Loading
+19 −7
Original line number Diff line number Diff line
@@ -146,7 +146,11 @@ static bool pm_fake(struct kvm_vcpu *vcpu,
#define access_pmintenclr pm_fake

/* Architected CP15 registers.
 * Important: Must be sorted ascending by CRn, CRM, Op1, Op2
 * CRn denotes the primary register number, but is copied to the CRm in the
 * user space API for 64-bit register access in line with the terminology used
 * in the ARM ARM.
 * Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit
 *            registers preceding 32-bit ones.
 */
static const struct coproc_reg cp15_regs[] = {
	/* CSSELR: swapped by interrupt.S. */
@@ -154,8 +158,8 @@ static const struct coproc_reg cp15_regs[] = {
			NULL, reset_unknown, c0_CSSELR },

	/* TTBR0/TTBR1: swapped by interrupt.S. */
	{ CRm( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
	{ CRm( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
	{ CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
	{ CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },

	/* TTBCR: swapped by interrupt.S. */
	{ CRn( 2), CRm( 0), Op1( 0), Op2( 2), is32,
@@ -182,7 +186,7 @@ static const struct coproc_reg cp15_regs[] = {
			NULL, reset_unknown, c6_IFAR },

	/* PAR swapped by interrupt.S */
	{ CRn( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
	{ CRm64( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },

	/*
	 * DC{C,I,CI}SW operations:
@@ -399,12 +403,13 @@ static bool index_to_params(u64 id, struct coproc_params *params)
			      | KVM_REG_ARM_OPC1_MASK))
			return false;
		params->is_64bit = true;
		params->CRm = ((id & KVM_REG_ARM_CRM_MASK)
		/* CRm to CRn: see cp15_to_index for details */
		params->CRn = ((id & KVM_REG_ARM_CRM_MASK)
			       >> KVM_REG_ARM_CRM_SHIFT);
		params->Op1 = ((id & KVM_REG_ARM_OPC1_MASK)
			       >> KVM_REG_ARM_OPC1_SHIFT);
		params->Op2 = 0;
		params->CRn = 0;
		params->CRm = 0;
		return true;
	default:
		return false;
@@ -898,7 +903,14 @@ static u64 cp15_to_index(const struct coproc_reg *reg)
	if (reg->is_64) {
		val |= KVM_REG_SIZE_U64;
		val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT);
		val |= (reg->CRm << KVM_REG_ARM_CRM_SHIFT);
		/*
		 * CRn always denotes the primary coproc. reg. nr. for the
		 * in-kernel representation, but the user space API uses the
		 * CRm for the encoding, because it is modelled after the
		 * MRRC/MCRR instructions: see the ARM ARM rev. c page
		 * B3-1445
		 */
		val |= (reg->CRn << KVM_REG_ARM_CRM_SHIFT);
	} else {
		val |= KVM_REG_SIZE_U32;
		val |= (reg->Op1 << KVM_REG_ARM_OPC1_SHIFT);
+3 −0
Original line number Diff line number Diff line
@@ -135,6 +135,8 @@ static inline int cmp_reg(const struct coproc_reg *i1,
		return -1;
	if (i1->CRn != i2->CRn)
		return i1->CRn - i2->CRn;
	if (i1->is_64 != i2->is_64)
		return i2->is_64 - i1->is_64;
	if (i1->CRm != i2->CRm)
		return i1->CRm - i2->CRm;
	if (i1->Op1 != i2->Op1)
@@ -145,6 +147,7 @@ static inline int cmp_reg(const struct coproc_reg *i1,

#define CRn(_x)		.CRn = _x
#define CRm(_x) 	.CRm = _x
#define CRm64(_x)       .CRn = _x, .CRm = 0
#define Op1(_x) 	.Op1 = _x
#define Op2(_x) 	.Op2 = _x
#define is64		.is_64 = true
+5 −1
Original line number Diff line number Diff line
@@ -114,7 +114,11 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu,

/*
 * A15-specific CP15 registers.
 * Important: Must be sorted ascending by CRn, CRM, Op1, Op2
 * CRn denotes the primary register number, but is copied to the CRm in the
 * user space API for 64-bit register access in line with the terminology used
 * in the ARM ARM.
 * Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit
 *            registers preceding 32-bit ones.
 */
static const struct coproc_reg a15_regs[] = {
	/* MPIDR: we use VMPIDR for guest access. */
+2 −1
Original line number Diff line number Diff line
@@ -63,7 +63,8 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
		      struct kvm_exit_mmio *mmio)
{
	unsigned long rt, len;
	unsigned long rt;
	int len;
	bool is_write, sign_extend;

	if (kvm_vcpu_dabt_isextabt(vcpu)) {
+15 −21
Original line number Diff line number Diff line
@@ -85,6 +85,12 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
	return p;
}

static bool page_empty(void *ptr)
{
	struct page *ptr_page = virt_to_page(ptr);
	return page_count(ptr_page) == 1;
}

static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr)
{
	pmd_t *pmd_table = pmd_offset(pud, 0);
@@ -103,12 +109,6 @@ static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr)
	put_page(virt_to_page(pmd));
}

static bool pmd_empty(pmd_t *pmd)
{
	struct page *pmd_page = virt_to_page(pmd);
	return page_count(pmd_page) == 1;
}

static void clear_pte_entry(struct kvm *kvm, pte_t *pte, phys_addr_t addr)
{
	if (pte_present(*pte)) {
@@ -118,12 +118,6 @@ static void clear_pte_entry(struct kvm *kvm, pte_t *pte, phys_addr_t addr)
	}
}

static bool pte_empty(pte_t *pte)
{
	struct page *pte_page = virt_to_page(pte);
	return page_count(pte_page) == 1;
}

static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
			unsigned long long start, u64 size)
{
@@ -132,37 +126,37 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
	pmd_t *pmd;
	pte_t *pte;
	unsigned long long addr = start, end = start + size;
	u64 range;
	u64 next;

	while (addr < end) {
		pgd = pgdp + pgd_index(addr);
		pud = pud_offset(pgd, addr);
		if (pud_none(*pud)) {
			addr += PUD_SIZE;
			addr = pud_addr_end(addr, end);
			continue;
		}

		pmd = pmd_offset(pud, addr);
		if (pmd_none(*pmd)) {
			addr += PMD_SIZE;
			addr = pmd_addr_end(addr, end);
			continue;
		}

		pte = pte_offset_kernel(pmd, addr);
		clear_pte_entry(kvm, pte, addr);
		range = PAGE_SIZE;
		next = addr + PAGE_SIZE;

		/* If we emptied the pte, walk back up the ladder */
		if (pte_empty(pte)) {
		if (page_empty(pte)) {
			clear_pmd_entry(kvm, pmd, addr);
			range = PMD_SIZE;
			if (pmd_empty(pmd)) {
			next = pmd_addr_end(addr, end);
			if (page_empty(pmd) && !page_empty(pud)) {
				clear_pud_entry(kvm, pud, addr);
				range = PUD_SIZE;
				next = pud_addr_end(addr, end);
			}
		}

		addr += range;
		addr = next;
	}
}

Loading