Gleb Natapov wrote on 2012-12-12:
> On Wed, Dec 12, 2012 at 12:56:47PM +0800, Yang Zhang wrote:
>> From: Yang Zhang <[email protected]>
>> 
>> Virtual interrupt delivery avoids KVM to inject vAPIC interrupts
>> manually, which is fully taken care of by the hardware. This needs
>> some special awareness into existing interrupr injection path:
>> 
>> - for pending interrupt, instead of direct injection, we may need
>>   update architecture specific indicators before resuming to guest.
>> - A pending interrupt, which is masked by ISR, should be also
>>   considered in above update action, since hardware will decide
>>   when to inject it at right time. Current has_interrupt and
>>   get_interrupt only returns a valid vector from injection p.o.v.
>> Signed-off-by: Kevin Tian <[email protected]>
>> Signed-off-by: Yang Zhang <[email protected]>
>> ---
>> diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
>> index ebd98d0..537ce4b 100644
>> --- a/arch/x86/kvm/irq.c
>> +++ b/arch/x86/kvm/irq.c
>> @@ -38,37 +38,81 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu
> *vcpu)
>>  EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
>>  
>>  /*
>> + * check if there is pending interrupt from
>> + * non-APIC source without intack.
>> + */
>> +static int kvm_cpu_has_extint(struct kvm_vcpu *v)
>> +{
>> +    if (kvm_apic_accept_pic_intr(v))
>> +            return pic_irqchip(v->kvm)->output;     /* PIC */
>> +    else
>> +            return 0;
>> +}
>> +
>> +/*
>> + * check if there is injectable interrupt:
>> + * when virtual interrupt delivery enabled,
>> + * interrupt from apic will handled by hardware,
>> + * we don't need to check it here.
>> + */
>> +int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
>> +{
>> +    if (!irqchip_in_kernel(v->kvm))
>> +            return v->arch.interrupt.pending;
>> +
>> +    if (kvm_cpu_has_extint(v))
>> +            return 1;
>> +    else if (!kvm_apic_vid_enabled(v))
>> +            return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
>> +
> I think:
>    if (kvm_cpu_has_extint(v))
>         return 1;
>    if(kvm_apic_vid_enabled(v))        return 0; return
>    kvm_apic_has_interrupt(v) != -1; /* LAPIC */
> is clearer.
OK.
 
>> +/*
>>   * Read pending interrupt vector and intack.
>>   */
>>  int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
>>  {
>> -    struct kvm_pic *s;
>> +    int vector;
>> 
>>      if (!irqchip_in_kernel(v->kvm))
>>              return v->arch.interrupt.nr;
>> -    if (kvm_apic_accept_pic_intr(v) && pic_irqchip(v->kvm)->output)
>> -            return kvm_pic_read_irq(v->kvm);        /* PIC */
>> +    vector = kvm_cpu_get_extint(v);
>> +
>> +    if (kvm_apic_vid_enabled(v))
>> +            return vector;                          /* PIC */
>> +    else if (vector == -1)
>> +            vector = kvm_get_apic_interrupt(v);     /* APIC */
>> 
> No need "else" here:
>   if (kvm_apic_vid_enabled(v) || vector != -1)
>     return vector;
>   return kvm_get_apic_interrupt(v);
Ok.

>> -    return kvm_get_apic_interrupt(v);       /* APIC */
>> +    return vector;
>>  }
>>  EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
>> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
>> index 0664c13..0dfbd47 100644
>> --- a/arch/x86/kvm/lapic.c
>> +++ b/arch/x86/kvm/lapic.c
>> @@ -236,12 +236,14 @@ static inline void kvm_apic_set_id(struct kvm_lapic
> *apic, u8 id)
>>  {   apic_set_reg(apic, APIC_ID, id << 24);
>>      recalculate_apic_map(apic->vcpu->kvm);
>>  +   ioapic_update_eoi_exitmap(apic->vcpu->kvm); }
>>  
>>  static inline void kvm_apic_set_ldr(struct kvm_lapic *apic, u32 id) {
>>      apic_set_reg(apic, APIC_LDR, id);
>>      recalculate_apic_map(apic->vcpu->kvm);
>>  +   ioapic_update_eoi_exitmap(apic->vcpu->kvm); }
>>  
>>  static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
>> @@ -577,6 +579,63 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu,
> struct kvm_lapic *source,
>>      return result;
>>  }
>> +static void kvm_apic_update_eoi_exitmap(struct kvm_vcpu *vcpu,
>> +                                    u32 vector, bool set)
>> +{
>> +    kvm_x86_ops->update_eoi_exitmap(vcpu, vector, set);
>> +}
>> +
>> +void kvm_update_eoi_exitmap(struct kvm *kvm, struct kvm_lapic_irq *irq)
>> +{
> We probably should move the whole function into vmx code, not just
> bitmap update logic. Sorry for not mentioning it earlier.
Sure.

>> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
>> index dcb7952..b501d5a 100644
>> --- a/arch/x86/kvm/svm.c
>> +++ b/arch/x86/kvm/svm.c
>> @@ -3573,6 +3573,27 @@ static void update_cr8_intercept(struct kvm_vcpu
> *vcpu, int tpr, int irr)
>>              set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
>>  }
>> +static int svm_has_virtual_interrupt_delivery(struct kvm_vcpu *vcpu)
>> +{
>> +    return 0;
>> +}
>> +
>> +static void svm_update_apic_irq(struct kvm_vcpu *vcpu, int max_irr)
>> +{
>> +    return ;
>> +}
> You do not need this function any more since caller checks for NULL
> pointer.
>> +    .has_virtual_interrupt_delivery = svm_has_virtual_interrupt_delivery,
>> +    .update_apic_irq = svm_update_apic_irq;
> Should not be set.
Sure.
 
>> +    status = vmcs_read16(GUEST_INTR_STATUS);
>> +    old = (u8)status & 0xff;
>> +    if ((u8)vector != old) {
>> +            status &= ~0xff;
>> +            status |= (u8)vector;
>> +            vmcs_write16(GUEST_INTR_STATUS, status);
>> +    }
>> +}
>> +
>> +static void vmx_update_apic_irq(struct kvm_vcpu *vcpu, int max_irr)
>> +{
>> +    if (!enable_apicv_reg_vid || max_irr == -1)
> No need to check enable_apicv_reg_vid since the function will not be
> called if vid is disabled.
Ok.
 
>> diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
>> index cfb7e4d..7c8d9e0 100644
>> --- a/virt/kvm/ioapic.c
>> +++ b/virt/kvm/ioapic.c
>> @@ -115,6 +115,37 @@ static void update_handled_vectors(struct kvm_ioapic
> *ioapic)
>>      smp_wmb();
>>  }
>> +static void ioapic_update_eoi_exitmap_one(struct kvm_ioapic *ioapic, int 
>> pin)
>> +{
>> +    union kvm_ioapic_redirect_entry *e;
>> +
>> +    e = &ioapic->redirtbl[pin];
>> +
>> +    if ((e->fields.trig_mode == IOAPIC_LEVEL_TRIG ||
>> +             kvm_irq_has_notifier(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin))) {
>> +            struct kvm_lapic_irq irqe;
>> +
>> +            irqe.dest_id = e->fields.dest_id;
>> +            irqe.vector = e->fields.vector;
>> +            irqe.dest_mode = e->fields.dest_mode;
>> +            irqe.delivery_mode = e->fields.delivery_mode << 8;
>> +            kvm_update_eoi_exitmap(ioapic->kvm, &irqe);
>> +    }
>> +}
>> +
> There is a bugs in exitbitmap recalculation that I've missed.
> We need to zero all the exit bitmaps for all vcpus before we are
> starting to recalculate them to get rid of stale bits.
Right. I forget it too. So if consider to clear it, we should call 
ioapic_update_eoi_exitmap instead ioapic_update_eoi_exitmap_one when 
programming one program ioapic entry.

Best regards,
Yang


--
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

Reply via email to