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

Commit 1b1973ef authored by Radim Krčmář's avatar Radim Krčmář
Browse files
KVM/ARM updates for 4.10-rc4

- Fix for timer setup on VHE machines
- Drop spurious warning when the timer races against
  the vcpu running again
- Prevent a vgic deadlock when the initialization fails
parents 49def185 1193e6ae
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -80,6 +80,11 @@ static inline bool is_kernel_in_hyp_mode(void)
	return false;
}

static inline bool has_vhe(void)
{
	return false;
}

/* The section containing the hypervisor idmap text */
extern char __hyp_idmap_text_start[];
extern char __hyp_idmap_text_end[];
+3 −0
Original line number Diff line number Diff line
@@ -1099,6 +1099,9 @@ static void cpu_init_hyp_mode(void *dummy)
	__cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
	__cpu_init_stage2();

	if (is_kernel_in_hyp_mode())
		kvm_timer_init_vhe();

	kvm_arm_init_debug();
}

+9 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
#include <asm/ptrace.h>
#include <asm/sections.h>
#include <asm/sysreg.h>
#include <asm/cpufeature.h>

/*
 * __boot_cpu_mode records what mode CPUs were booted in.
@@ -80,6 +81,14 @@ static inline bool is_kernel_in_hyp_mode(void)
	return read_sysreg(CurrentEL) == CurrentEL_EL2;
}

static inline bool has_vhe(void)
{
	if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN))
		return true;

	return false;
}

#ifdef CONFIG_ARM64_VHE
extern void verify_cpu_run_el(void);
#else
+1 −0
Original line number Diff line number Diff line
@@ -76,4 +76,5 @@ void kvm_timer_unschedule(struct kvm_vcpu *vcpu);

void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);

void kvm_timer_init_vhe(void);
#endif
+23 −3
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

#include <clocksource/arm_arch_timer.h>
#include <asm/arch_timer.h>
#include <asm/kvm_hyp.h>

#include <kvm/arm_vgic.h>
#include <kvm/arm_arch_timer.h>
@@ -89,9 +90,6 @@ static void kvm_timer_inject_irq_work(struct work_struct *work)
	struct kvm_vcpu *vcpu;

	vcpu = container_of(work, struct kvm_vcpu, arch.timer_cpu.expired);
	vcpu->arch.timer_cpu.armed = false;

	WARN_ON(!kvm_timer_should_fire(vcpu));

	/*
	 * If the vcpu is blocked we want to wake it up so that it will see
@@ -512,3 +510,25 @@ void kvm_timer_init(struct kvm *kvm)
{
	kvm->arch.timer.cntvoff = kvm_phys_timer_read();
}

/*
 * On VHE system, we only need to configure trap on physical timer and counter
 * accesses in EL0 and EL1 once, not for every world switch.
 * The host kernel runs at EL2 with HCR_EL2.TGE == 1,
 * and this makes those bits have no effect for the host kernel execution.
 */
void kvm_timer_init_vhe(void)
{
	/* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */
	u32 cnthctl_shift = 10;
	u64 val;

	/*
	 * Disallow physical timer access for the guest.
	 * Physical counter access is allowed.
	 */
	val = read_sysreg(cnthctl_el2);
	val &= ~(CNTHCTL_EL1PCEN << cnthctl_shift);
	val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
	write_sysreg(val, cnthctl_el2);
}
Loading