Skip to content

Commit

Permalink
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Browse files Browse the repository at this point in the history
Pull KVM fixes from Radim Krčmář:
 "ARM fixes:
   - Wrong indentation in the PMU code from the merge window
   - A long-time bug occuring with running ntpd on the host, candidate
     for stable
   - Properly handle (and warn about) the unsupported configuration of
     running on systems with less than 40 bits of PA space
   - More fixes to the PM and hotplug notifier stuff from the merge
     window

  x86:
   - leak of guest xcr0 (typically shows up as SIGILL)
   - new maintainer (who is sending the pull request too)
   - fix for merge window regression
   - fix for guest CPUID"

Paolo Bonzini points out:
 "For the record, this tag is signed by me because I prepared the pull
  request.  Further pull requests for 4.6 will be signed and sent out by
  Radim directly"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: x86: mask CPUID(0xD,0x1).EAX against host value
  kvm: x86: do not leak guest xcr0 into host interrupt handlers
  KVM: MMU: fix permission_fault()
  KVM: new maintainer on the block
  arm64: KVM: unregister notifiers in hyp mode teardown path
  arm64: KVM: Warn when PARange is less than 40 bits
  KVM: arm/arm64: Handle forward time correction gracefully
  arm64: KVM: Add braces to multi-line if statement in virtual PMU code
  • Loading branch information
Linus Torvalds committed Apr 13, 2016
2 parents 1c74a7f + 316314c commit 5e1b59a
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 37 deletions.
2 changes: 1 addition & 1 deletion MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -6252,8 +6252,8 @@ S: Maintained
F: tools/testing/selftests

KERNEL VIRTUAL MACHINE (KVM)
M: Gleb Natapov <gleb@kernel.org>
M: Paolo Bonzini <pbonzini@redhat.com>
M: Radim Krčmář <rkrcmar@redhat.com>
L: kvm@vger.kernel.org
W: http://www.linux-kvm.org
T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
Expand Down
13 changes: 10 additions & 3 deletions arch/arm/kvm/arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1112,10 +1112,17 @@ static void __init hyp_cpu_pm_init(void)
{
cpu_pm_register_notifier(&hyp_init_cpu_pm_nb);
}
static void __init hyp_cpu_pm_exit(void)
{
cpu_pm_unregister_notifier(&hyp_init_cpu_pm_nb);
}
#else
static inline void hyp_cpu_pm_init(void)
{
}
static inline void hyp_cpu_pm_exit(void)
{
}
#endif

static void teardown_common_resources(void)
Expand All @@ -1141,9 +1148,7 @@ static int init_subsystems(void)
/*
* Register CPU Hotplug notifier
*/
cpu_notifier_register_begin();
err = __register_cpu_notifier(&hyp_init_cpu_nb);
cpu_notifier_register_done();
err = register_cpu_notifier(&hyp_init_cpu_nb);
if (err) {
kvm_err("Cannot register KVM init CPU notifier (%d)\n", err);
return err;
Expand Down Expand Up @@ -1193,6 +1198,8 @@ static void teardown_hyp_mode(void)
free_hyp_pgds();
for_each_possible_cpu(cpu)
free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
unregister_cpu_notifier(&hyp_init_cpu_nb);
hyp_cpu_pm_exit();
}

static int init_vhe_mode(void)
Expand Down
6 changes: 2 additions & 4 deletions arch/arm64/include/asm/kvm_arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,7 @@
*/
#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SH0_INNER | \
VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B | \
VTCR_EL2_RES1)
VTCR_EL2_SL0_LVL1 | VTCR_EL2_RES1)
#define VTTBR_X (38 - VTCR_EL2_T0SZ_40B)
#else
/*
Expand All @@ -163,8 +162,7 @@
*/
#define VTCR_EL2_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SH0_INNER | \
VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \
VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B | \
VTCR_EL2_RES1)
VTCR_EL2_SL0_LVL1 | VTCR_EL2_RES1)
#define VTTBR_X (37 - VTCR_EL2_T0SZ_40B)
#endif

Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/include/asm/kvm_asm.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ extern void __vgic_v3_init_lrs(void);

extern u32 __kvm_get_mdcr_el2(void);

extern void __init_stage2_translation(void);
extern u32 __init_stage2_translation(void);

#endif

Expand Down
7 changes: 4 additions & 3 deletions arch/arm64/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,12 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
struct kvm_device_attr *attr);

/* #define kvm_call_hyp(f, ...) __kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__) */

static inline void __cpu_init_stage2(void)
{
kvm_call_hyp(__init_stage2_translation);
u32 parange = kvm_call_hyp(__init_stage2_translation);

WARN_ONCE(parange < 40,
"PARange is %d bits, unsupported configuration!", parange);
}

#endif /* __ARM64_KVM_HOST_H__ */
39 changes: 37 additions & 2 deletions arch/arm64/kvm/hyp/s2-setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,50 @@
#include <asm/kvm_asm.h>
#include <asm/kvm_hyp.h>

void __hyp_text __init_stage2_translation(void)
u32 __hyp_text __init_stage2_translation(void)
{
u64 val = VTCR_EL2_FLAGS;
u64 parange;
u64 tmp;

/*
* Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS
* bits in VTCR_EL2. Amusingly, the PARange is 4 bits, while
* PS is only 3. Fortunately, bit 19 is RES0 in VTCR_EL2...
*/
val |= (read_sysreg(id_aa64mmfr0_el1) & 7) << 16;
parange = read_sysreg(id_aa64mmfr0_el1) & 7;
val |= parange << 16;

/* Compute the actual PARange... */
switch (parange) {
case 0:
parange = 32;
break;
case 1:
parange = 36;
break;
case 2:
parange = 40;
break;
case 3:
parange = 42;
break;
case 4:
parange = 44;
break;
case 5:
default:
parange = 48;
break;
}

/*
* ... and clamp it to 40 bits, unless we have some braindead
* HW that implements less than that. In all cases, we'll
* return that value for the rest of the kernel to decide what
* to do.
*/
val |= 64 - (parange > 40 ? 40 : parange);

/*
* Read the VMIDBits bits from ID_AA64MMFR1_EL1 and set the VS
Expand All @@ -42,4 +75,6 @@ void __hyp_text __init_stage2_translation(void)
VTCR_EL2_VS_8BIT;

write_sysreg(val, vtcr_el2);

return parange;
}
1 change: 1 addition & 0 deletions arch/x86/kvm/cpuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
do_cpuid_1_ent(&entry[i], function, idx);
if (idx == 1) {
entry[i].eax &= kvm_cpuid_D_1_eax_x86_features;
cpuid_mask(&entry[i].eax, CPUID_D_1_EAX);
entry[i].ebx = 0;
if (entry[i].eax & (F(XSAVES)|F(XSAVEC)))
entry[i].ebx =
Expand Down
9 changes: 4 additions & 5 deletions arch/x86/kvm/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,9 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
int index = (pfec >> 1) +
(smap >> (X86_EFLAGS_AC_BIT - PFERR_RSVD_BIT + 1));
bool fault = (mmu->permissions[index] >> pte_access) & 1;
u32 errcode = PFERR_PRESENT_MASK;

WARN_ON(pfec & (PFERR_PK_MASK | PFERR_RSVD_MASK));
pfec |= PFERR_PRESENT_MASK;

if (unlikely(mmu->pkru_mask)) {
u32 pkru_bits, offset;

Expand All @@ -189,15 +188,15 @@ static inline u8 permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
pkru_bits = (kvm_read_pkru(vcpu) >> (pte_pkey * 2)) & 3;

/* clear present bit, replace PFEC.RSVD with ACC_USER_MASK. */
offset = pfec - 1 +
offset = (pfec & ~1) +
((pte_access & PT_USER_MASK) << (PFERR_RSVD_BIT - PT_USER_SHIFT));

pkru_bits &= mmu->pkru_mask >> offset;
pfec |= -pkru_bits & PFERR_PK_MASK;
errcode |= -pkru_bits & PFERR_PK_MASK;
fault |= (pkru_bits != 0);
}

return -(uint32_t)fault & pfec;
return -(u32)fault & errcode;
}

void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/kvm/paging_tmpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
goto error;

if (unlikely(is_rsvd_bits_set(mmu, pte, walker->level))) {
errcode |= PFERR_RSVD_MASK | PFERR_PRESENT_MASK;
errcode = PFERR_RSVD_MASK | PFERR_PRESENT_MASK;
goto error;
}

Expand Down
10 changes: 4 additions & 6 deletions arch/x86/kvm/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,6 @@ static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
if ((xcr0 & XFEATURE_MASK_AVX512) != XFEATURE_MASK_AVX512)
return 1;
}
kvm_put_guest_xcr0(vcpu);
vcpu->arch.xcr0 = xcr0;

if ((xcr0 ^ old_xcr0) & XFEATURE_MASK_EXTEND)
Expand Down Expand Up @@ -6590,8 +6589,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
kvm_x86_ops->prepare_guest_switch(vcpu);
if (vcpu->fpu_active)
kvm_load_guest_fpu(vcpu);
kvm_load_guest_xcr0(vcpu);

vcpu->mode = IN_GUEST_MODE;

srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
Expand All @@ -6618,6 +6615,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
goto cancel_injection;
}

kvm_load_guest_xcr0(vcpu);

if (req_immediate_exit)
smp_send_reschedule(vcpu->cpu);

Expand Down Expand Up @@ -6667,6 +6666,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
vcpu->mode = OUTSIDE_GUEST_MODE;
smp_wmb();

kvm_put_guest_xcr0(vcpu);

/* Interrupt is enabled by handle_external_intr() */
kvm_x86_ops->handle_external_intr(vcpu);

Expand Down Expand Up @@ -7314,7 +7315,6 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
* and assume host would use all available bits.
* Guest xcr0 would be loaded later.
*/
kvm_put_guest_xcr0(vcpu);
vcpu->guest_fpu_loaded = 1;
__kernel_fpu_begin();
__copy_kernel_to_fpregs(&vcpu->arch.guest_fpu.state);
Expand All @@ -7323,8 +7323,6 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)

void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
{
kvm_put_guest_xcr0(vcpu);

if (!vcpu->guest_fpu_loaded) {
vcpu->fpu_counter = 0;
return;
Expand Down
49 changes: 39 additions & 10 deletions virt/kvm/arm/arch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,55 @@ static void kvm_timer_inject_irq_work(struct work_struct *work)
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
* the timer has expired when entering the guest.
*/
kvm_vcpu_kick(vcpu);
}

static u64 kvm_timer_compute_delta(struct kvm_vcpu *vcpu)
{
cycle_t cval, now;

cval = vcpu->arch.timer_cpu.cntv_cval;
now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;

if (now < cval) {
u64 ns;

ns = cyclecounter_cyc2ns(timecounter->cc,
cval - now,
timecounter->mask,
&timecounter->frac);
return ns;
}

return 0;
}

static enum hrtimer_restart kvm_timer_expire(struct hrtimer *hrt)
{
struct arch_timer_cpu *timer;
struct kvm_vcpu *vcpu;
u64 ns;

timer = container_of(hrt, struct arch_timer_cpu, timer);
vcpu = container_of(timer, struct kvm_vcpu, arch.timer_cpu);

/*
* Check that the timer has really expired from the guest's
* PoV (NTP on the host may have forced it to expire
* early). If we should have slept longer, restart it.
*/
ns = kvm_timer_compute_delta(vcpu);
if (unlikely(ns)) {
hrtimer_forward_now(hrt, ns_to_ktime(ns));
return HRTIMER_RESTART;
}

queue_work(wqueue, &timer->expired);
return HRTIMER_NORESTART;
}
Expand Down Expand Up @@ -176,8 +214,6 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
void kvm_timer_schedule(struct kvm_vcpu *vcpu)
{
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
u64 ns;
cycle_t cval, now;

BUG_ON(timer_is_armed(timer));

Expand All @@ -197,14 +233,7 @@ void kvm_timer_schedule(struct kvm_vcpu *vcpu)
return;

/* The timer has not yet expired, schedule a background timer */
cval = timer->cntv_cval;
now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;

ns = cyclecounter_cyc2ns(timecounter->cc,
cval - now,
timecounter->mask,
&timecounter->frac);
timer_arm(timer, ns);
timer_arm(timer, kvm_timer_compute_delta(vcpu));
}

void kvm_timer_unschedule(struct kvm_vcpu *vcpu)
Expand Down
3 changes: 2 additions & 1 deletion virt/kvm/arm/pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,12 @@ static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu)
{
u64 reg = 0;

if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E))
if ((vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMU_PMCR_E)) {
reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0);
reg &= vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
reg &= vcpu_sys_reg(vcpu, PMINTENSET_EL1);
reg &= kvm_pmu_valid_counter_mask(vcpu);
}

return reg;
}
Expand Down

0 comments on commit 5e1b59a

Please sign in to comment.