Commit 55365ab8 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvmarm-fixes-7.0-1' of...

Merge tag 'kvmarm-fixes-7.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD

KVM/arm64 fixes for 7.0, take #1

- Make sure we don't leak any S1POE state from guest to guest when
  the feature is supported on the HW, but not enabled on the host

- Propagate the ID registers from the host into non-protected VMs
  managed by pKVM, ensuring that the guest sees the intended feature set

- Drop double kern_hyp_va() from unpin_host_sve_state(), which could
  bite us if we were to change kern_hyp_va() to not being idempotent

- Don't leak stage-2 mappings in protected mode

- Correctly align the faulting address when dealing with single page
  stage-2 mappings for PAGE_SIZE > 4kB

- Fix detection of virtualisation-capable GICv5 IRS, due to the
  maintainer being obviously fat fingered...

- Remove duplication of code retrieving the ASID for the purpose of
  S1 PT handling

- Fix slightly abusive const-ification in vgic_set_kvm_info()
parents 70295a47 54e367cb
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -1616,7 +1616,8 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
	(kvm_has_feat((k), ID_AA64MMFR3_EL1, S1PIE, IMP))

#define kvm_has_s1poe(k)				\
	(kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))
	(system_supports_poe() &&			\
	 kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))

#define kvm_has_ras(k)					\
	(kvm_has_feat((k), ID_AA64PFR0_EL1, RAS, IMP))
+2 −0
Original line number Diff line number Diff line
@@ -397,6 +397,8 @@ int kvm_vcpu_allocate_vncr_tlb(struct kvm_vcpu *vcpu);
int kvm_handle_vncr_abort(struct kvm_vcpu *vcpu);
void kvm_handle_s1e2_tlbi(struct kvm_vcpu *vcpu, u32 inst, u64 val);

u16 get_asid_by_regime(struct kvm_vcpu *vcpu, enum trans_regime regime);

#define vncr_fixmap(c)						\
	({							\
		u32 __c = (c);					\
+2 −25
Original line number Diff line number Diff line
@@ -540,31 +540,8 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
	wr->pa |= va & GENMASK_ULL(va_bottom - 1, 0);

	wr->nG = (wi->regime != TR_EL2) && (desc & PTE_NG);
	if (wr->nG) {
		u64 asid_ttbr, tcr;

		switch (wi->regime) {
		case TR_EL10:
			tcr = vcpu_read_sys_reg(vcpu, TCR_EL1);
			asid_ttbr = ((tcr & TCR_A1) ?
				     vcpu_read_sys_reg(vcpu, TTBR1_EL1) :
				     vcpu_read_sys_reg(vcpu, TTBR0_EL1));
			break;
		case TR_EL20:
			tcr = vcpu_read_sys_reg(vcpu, TCR_EL2);
			asid_ttbr = ((tcr & TCR_A1) ?
				     vcpu_read_sys_reg(vcpu, TTBR1_EL2) :
				     vcpu_read_sys_reg(vcpu, TTBR0_EL2));
			break;
		default:
			BUG();
		}

		wr->asid = FIELD_GET(TTBR_ASID_MASK, asid_ttbr);
		if (!kvm_has_feat_enum(vcpu->kvm, ID_AA64MMFR0_EL1, ASIDBITS, 16) ||
		    !(tcr & TCR_ASID16))
			wr->asid &= GENMASK(7, 0);
	}
	if (wr->nG)
		wr->asid = get_asid_by_regime(vcpu, wi->regime);

	return 0;

+34 −3
Original line number Diff line number Diff line
@@ -342,6 +342,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
	/* No restrictions for non-protected VMs. */
	if (!kvm_vm_is_protected(kvm)) {
		hyp_vm->kvm.arch.flags = host_arch_flags;
		hyp_vm->kvm.arch.flags &= ~BIT_ULL(KVM_ARCH_FLAG_ID_REGS_INITIALIZED);

		bitmap_copy(kvm->arch.vcpu_features,
			    host_kvm->arch.vcpu_features,
@@ -391,7 +392,7 @@ static void unpin_host_sve_state(struct pkvm_hyp_vcpu *hyp_vcpu)
	if (!vcpu_has_feature(&hyp_vcpu->vcpu, KVM_ARM_VCPU_SVE))
		return;

	sve_state = kern_hyp_va(hyp_vcpu->vcpu.arch.sve_state);
	sve_state = hyp_vcpu->vcpu.arch.sve_state;
	hyp_unpin_shared_mem(sve_state,
			     sve_state + vcpu_sve_state_size(&hyp_vcpu->vcpu));
}
@@ -471,6 +472,35 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
	return ret;
}

static int vm_copy_id_regs(struct pkvm_hyp_vcpu *hyp_vcpu)
{
	struct pkvm_hyp_vm *hyp_vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
	const struct kvm *host_kvm = hyp_vm->host_kvm;
	struct kvm *kvm = &hyp_vm->kvm;

	if (!test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &host_kvm->arch.flags))
		return -EINVAL;

	if (test_and_set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags))
		return 0;

	memcpy(kvm->arch.id_regs, host_kvm->arch.id_regs, sizeof(kvm->arch.id_regs));

	return 0;
}

static int pkvm_vcpu_init_sysregs(struct pkvm_hyp_vcpu *hyp_vcpu)
{
	int ret = 0;

	if (pkvm_hyp_vcpu_is_protected(hyp_vcpu))
		kvm_init_pvm_id_regs(&hyp_vcpu->vcpu);
	else
		ret = vm_copy_id_regs(hyp_vcpu);

	return ret;
}

static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
			      struct pkvm_hyp_vm *hyp_vm,
			      struct kvm_vcpu *host_vcpu)
@@ -490,8 +520,9 @@ static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
	hyp_vcpu->vcpu.arch.cflags = READ_ONCE(host_vcpu->arch.cflags);
	hyp_vcpu->vcpu.arch.mp_state.mp_state = KVM_MP_STATE_STOPPED;

	if (pkvm_hyp_vcpu_is_protected(hyp_vcpu))
		kvm_init_pvm_id_regs(&hyp_vcpu->vcpu);
	ret = pkvm_vcpu_init_sysregs(hyp_vcpu);
	if (ret)
		goto done;

	ret = pkvm_vcpu_init_traps(hyp_vcpu);
	if (ret)
+5 −7
Original line number Diff line number Diff line
@@ -1754,14 +1754,12 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
	}

	/*
	 * Both the canonical IPA and fault IPA must be hugepage-aligned to
	 * ensure we find the right PFN and lay down the mapping in the right
	 * place.
	 * Both the canonical IPA and fault IPA must be aligned to the
	 * mapping size to ensure we find the right PFN and lay down the
	 * mapping in the right place.
	 */
	if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE) {
		fault_ipa &= ~(vma_pagesize - 1);
		ipa &= ~(vma_pagesize - 1);
	}
	fault_ipa = ALIGN_DOWN(fault_ipa, vma_pagesize);
	ipa = ALIGN_DOWN(ipa, vma_pagesize);

	gfn = ipa >> PAGE_SHIFT;
	mte_allowed = kvm_vma_mte_allowed(vma);
Loading