On Fri, Jan 25, 2019 at 10:46:55AM +0100, Christoffer Dall wrote: > We are currently not implementing the PSCI spec completely, as we do not > take handle the situation where two VCPUs are attempting to turn on a > third VCPU at the same time. The PSCI implementation should make sure > that only one requesting VCPU wins the race and that the other receives > PSCI_RET_ON_PENDING. > > Implement this by changing the VCPU power state to a tristate enum and > ensure only a single VCPU can turn on another VCPU at a given time using > a cmpxchg operation. > > Signed-off-by: Christoffer Dall <christoffer.dall@xxxxxxx> > Acked-by: Marc Zyngier <marc.zyngier@xxxxxxx> > --- > arch/arm/include/asm/kvm_host.h | 10 ++++++++-- > arch/arm64/include/asm/kvm_host.h | 10 ++++++++-- > virt/kvm/arm/arm.c | 24 +++++++++++++++--------- > virt/kvm/arm/psci.c | 21 ++++++++++++++------- > 4 files changed, 45 insertions(+), 20 deletions(-) > > diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h > index b1cfae222441..4dc47fea1ac8 100644 > --- a/arch/arm/include/asm/kvm_host.h > +++ b/arch/arm/include/asm/kvm_host.h > @@ -157,6 +157,12 @@ struct vcpu_reset_state { > bool reset; > }; > > +enum vcpu_power_state { > + KVM_ARM_VCPU_OFF, > + KVM_ARM_VCPU_ON_PENDING, > + KVM_ARM_VCPU_ON, > +}; > + > struct kvm_vcpu_arch { > struct kvm_cpu_context ctxt; > > @@ -184,8 +190,8 @@ struct kvm_vcpu_arch { > * here. > */ > > - /* vcpu power-off state */ > - bool power_off; > + /* vcpu power state */ > + enum vcpu_power_state power_state; > > /* Don't run the guest (internal implementation need) */ > bool pause; > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h > index d43b13421987..0647a409657b 100644 > --- a/arch/arm64/include/asm/kvm_host.h > +++ b/arch/arm64/include/asm/kvm_host.h > @@ -218,6 +218,12 @@ struct vcpu_reset_state { > bool reset; > }; > > +enum vcpu_power_state { > + KVM_ARM_VCPU_OFF, > + KVM_ARM_VCPU_ON_PENDING, > + KVM_ARM_VCPU_ON, > +}; > + > struct kvm_vcpu_arch { > struct kvm_cpu_context ctxt; > > @@ -285,8 +291,8 @@ struct kvm_vcpu_arch { > u32 mdscr_el1; > } guest_debug_preserved; > > - /* vcpu power-off state */ > - bool power_off; > + /* vcpu power state */ > + enum vcpu_power_state power_state; > > /* Don't run the guest (internal implementation need) */ > bool pause; > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c > index 785076176814..1e3195155860 100644 > --- a/virt/kvm/arm/arm.c > +++ b/virt/kvm/arm/arm.c > @@ -411,7 +411,7 @@ static void vcpu_power_off(struct kvm_vcpu *vcpu) > int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, > struct kvm_mp_state *mp_state) > { > - if (vcpu->arch.power_off) > + if (vcpu->arch.power_state != KVM_ARM_VCPU_ON) > mp_state->mp_state = KVM_MP_STATE_STOPPED; > else > mp_state->mp_state = KVM_MP_STATE_RUNNABLE; > @@ -426,7 +426,7 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, > > switch (mp_state->mp_state) { > case KVM_MP_STATE_RUNNABLE: > - vcpu->arch.power_off = false; > + vcpu->arch.power_state = KVM_ARM_VCPU_ON; > break; > case KVM_MP_STATE_STOPPED: > vcpu_power_off(vcpu); > @@ -448,8 +448,9 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, > int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) > { > bool irq_lines = *vcpu_hcr(v) & (HCR_VI | HCR_VF); > - return ((irq_lines || kvm_vgic_vcpu_pending_irq(v)) > - && !v->arch.power_off && !v->arch.pause); > + return (irq_lines || kvm_vgic_vcpu_pending_irq(v)) && > + v->arch.power_state == KVM_ARM_VCPU_ON && > + !v->arch.pause; > } > > bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) > @@ -614,14 +615,19 @@ void kvm_arm_resume_guest(struct kvm *kvm) > } > } > > +static bool vcpu_sleeping(struct kvm_vcpu *vcpu) > +{ > + return vcpu->arch.power_state != KVM_ARM_VCPU_ON || > + vcpu->arch.pause; > +} > + > static void vcpu_req_sleep(struct kvm_vcpu *vcpu) > { > struct swait_queue_head *wq = kvm_arch_vcpu_wq(vcpu); > > - swait_event_interruptible_exclusive(*wq, ((!vcpu->arch.power_off) && > - (!vcpu->arch.pause))); > + swait_event_interruptible_exclusive(*wq, !vcpu_sleeping(vcpu)); > > - if (vcpu->arch.power_off || vcpu->arch.pause) { > + if (vcpu_sleeping(vcpu)) { > /* Awaken to handle a signal, request we sleep again later. */ > kvm_make_request(KVM_REQ_SLEEP, vcpu); > } > @@ -646,7 +652,7 @@ static void check_vcpu_requests(struct kvm_vcpu *vcpu) > vcpu_req_sleep(vcpu); > > if (kvm_check_request(KVM_REQ_VCPU_OFF, vcpu)) { > - vcpu->arch.power_off = true; > + vcpu->arch.power_state = KVM_ARM_VCPU_OFF; > vcpu_req_sleep(vcpu); > } > > @@ -1016,7 +1022,7 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, > if (test_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) > vcpu_power_off(vcpu); > else > - vcpu->arch.power_off = false; > + vcpu->arch.power_state = KVM_ARM_VCPU_ON; > > return 0; > } > diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c > index 20255319e193..5c2d9eeb810c 100644 > --- a/virt/kvm/arm/psci.c > +++ b/virt/kvm/arm/psci.c > @@ -106,6 +106,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) > struct kvm *kvm = source_vcpu->kvm; > struct kvm_vcpu *vcpu = NULL; > unsigned long cpu_id; > + enum vcpu_power_state old_power_state; > > cpu_id = smccc_get_arg1(source_vcpu) & MPIDR_HWID_BITMASK; > if (vcpu_mode_is_32bit(source_vcpu)) > @@ -119,12 +120,18 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) > */ > if (!vcpu) > return PSCI_RET_INVALID_PARAMS; > - if (!vcpu->arch.power_off) { > - if (kvm_psci_version(source_vcpu, kvm) != KVM_ARM_PSCI_0_1) > - return PSCI_RET_ALREADY_ON; > - else > + old_power_state = cmpxchg(&vcpu->arch.power_state, > + KVM_ARM_VCPU_OFF, > + KVM_ARM_VCPU_ON_PENDING); > + > + if (old_power_state != KVM_ARM_VCPU_OFF && > + kvm_psci_version(source_vcpu, kvm) == KVM_ARM_PSCI_0_1) > return PSCI_RET_INVALID_PARAMS; > - } > + > + if (old_power_state == KVM_ARM_VCPU_ON_PENDING) > + return PSCI_RET_ON_PENDING; > + else if (old_power_state == KVM_ARM_VCPU_ON) > + return PSCI_RET_ALREADY_ON; > > reset_state = &vcpu->arch.reset_state; > > @@ -148,7 +155,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) > */ > smp_wmb(); > > - vcpu->arch.power_off = false; > + vcpu->arch.power_state = KVM_ARM_VCPU_ON; > kvm_vcpu_wake_up(vcpu); > > return PSCI_RET_SUCCESS; > @@ -183,7 +190,7 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu) > mpidr = kvm_vcpu_get_mpidr_aff(tmp); > if ((mpidr & target_affinity_mask) == target_affinity) { > matching_cpus++; > - if (!tmp->arch.power_off) > + if (tmp->arch.power_state == KVM_ARM_VCPU_ON) > return PSCI_0_2_AFFINITY_LEVEL_ON; > } > } > -- > 2.18.0 > Reviewed-by: Andrew Jones <drjones@xxxxxxxxxx> _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm