On Thu, 2 Aug 2012 16:56:28 -0300, Marcelo Tosatti <[email protected]> wrote:
> On Tue, Jul 31, 2012 at 04:18:41PM +0530, Nikunj A. Dadhania wrote:
> > From: Nikunj A. Dadhania <[email protected]>
> >
> > Hypervisor code to indicate guest running/pre-empteded status through
> > msr. The page is now pinned during MSR write time and use
> > kmap_atomic/kunmap_atomic to access the shared area vcpu_state area.
> >
> > Suggested-by: Marcelo Tosatti <[email protected]>
> > Signed-off-by: Nikunj A. Dadhania <[email protected]>
> > ---
> > arch/x86/include/asm/kvm_host.h | 7 ++++
> > arch/x86/kvm/cpuid.c | 1 +
> > arch/x86/kvm/x86.c | 71
> > ++++++++++++++++++++++++++++++++++++++-
> > 3 files changed, 77 insertions(+), 2 deletions(-)
[...]
> > +static void kvm_set_atomic(u64 *addr, u64 old, u64 new)
> > +{
> > + int loop = 1000000;
> > + while (1) {
> > + if (cmpxchg(addr, old, new) == old)
> > + break;
> > + loop--;
> > + if (!loop) {
> > + pr_info("atomic cur: %lx old: %lx new: %lx\n",
> > + *addr, old, new);
> > + break;
> > + }
> > + }
> > +}
>
> A generic "kvm_set_atomic" would need that loop, but in the particular
> TLB flush case we know that the only information being transmitted is
> a TLB flush.
>
yes, so the next patch gets rid of this in a neater way.
> So this idea should work:
>
> old = *addr;
> if (cmpxchg(addr, old, IN_GUEST_MODE) == FAILURE)
> kvm_x86_ops->tlb_flush()
> atomic_set(addr, IN_GUEST_MODE);
> } else if {
> if (old & TLB_SHOULD_FLUSH)
> kvm_x86_ops->tlb_flush()
> }
>
> (the actual pseucode above is pretty ugly and
> mus be improved but it should be enough to transmit
> the idea).
>
> Of course as long as you make sure the atomic_set does not
> overwrite information.
>
>
> > + char *kaddr;
> > +
> > + if (!(vcpu->arch.v_state.msr_val & KVM_MSR_ENABLED) ||
> > + !vcpu->arch.v_state.vs_page)
> > + return;
>
> If its not enabled vs_page should be NULL?
>
Yes, it should be:
if (!(enabled && vs_page))
return;
> > +
> > + kaddr = kmap_atomic(vcpu->arch.v_state.vs_page);
> > + kaddr += vcpu->arch.v_state.vs_offset;
> > + vs = kaddr;
> > + kvm_set_atomic(&vs->state, 0, 1 << KVM_VCPU_STATE_IN_GUEST_MODE);
> > + kunmap_atomic(kaddr);
> > +}
> > +
> > +static void kvm_clear_vcpu_state(struct kvm_vcpu *vcpu)
> > +{
> > + struct kvm_vcpu_state *vs;
> > + char *kaddr;
> > +
> > + if (!(vcpu->arch.v_state.msr_val & KVM_MSR_ENABLED) ||
> > + !vcpu->arch.v_state.vs_page)
> > + return;
>
> Like above.
>
> > + kaddr = kmap_atomic(vcpu->arch.v_state.vs_page);
> > + kaddr += vcpu->arch.v_state.vs_offset;
> > + vs = kaddr;
> > + kvm_set_atomic(&vs->state, 1 << KVM_VCPU_STATE_IN_GUEST_MODE, 0);
> > + kunmap_atomic(kaddr);
> > +}
> > +
> > int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
> > {
> > bool pr = false;
> > @@ -1676,6 +1723,18 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32
> > msr, u64 data)
> > return 1;
> > break;
> >
> > + case MSR_KVM_VCPU_STATE:
> > + vcpu->arch.v_state.vs_page = gfn_to_page(vcpu->kvm, data >>
> > PAGE_SHIFT);
> > + vcpu->arch.v_state.vs_offset = data & ~(PAGE_MASK |
> > KVM_MSR_ENABLED);
>
> Assign vs_offset after success.
>
Will do that.
> > +
> > + if (is_error_page(vcpu->arch.v_state.vs_page)) {
> > + kvm_release_page_clean(vcpu->arch.time_page);
C&P error :(
kvm_release_page_clean(vcpu->arch.v_state.vs_page);
> > + vcpu->arch.v_state.vs_page = NULL;
> > + pr_info("KVM: VCPU_STATE - Unable to pin the page\n");
>
> Missing break or return;
>
Right
> > + }
> > + vcpu->arch.v_state.msr_val = data;
> > + break;
> > +
> > case MSR_IA32_MCG_CTL:
>
> Please verify this code carefully again.
>
> Also leaking the page reference.
>
> > vcpu->arch.apf.msr_val = 0;
> > vcpu->arch.st.msr_val = 0;
> > + vcpu->arch.v_state.msr_val = 0;
>
> Add a newline and comment (or even better a new helper).
>
Will do.
Thanks for the detailed review.
Nikunj
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html