KVM: x86: use MSR_ICR instead of a number
[deliverable/linux.git] / arch / x86 / kvm / lapic.c
index fa3c6f7fdca448c5f4465c4a1c205c297cc34d66..3634303218a372c78e0e9f6560a78a7fff68e9d2 100644 (file)
@@ -156,33 +156,45 @@ static void recalculate_apic_map(struct kvm *kvm)
 
        kvm_for_each_vcpu(i, vcpu, kvm) {
                struct kvm_lapic *apic = vcpu->arch.apic;
-               u16 cid, lid;
-               u32 ldr;
 
                if (!kvm_apic_present(vcpu))
                        continue;
 
-               /*
-                * All APICs have to be configured in the same mode by an OS.
-                * We take advatage of this while building logical id loockup
-                * table. After reset APICs are in xapic/flat mode, so if we
-                * find apic with different setting we assume this is the mode
-                * OS wants all apics to be in; build lookup table accordingly.
-                */
                if (apic_x2apic_mode(apic)) {
                        new->ldr_bits = 32;
                        new->cid_shift = 16;
                        new->cid_mask = (1 << KVM_X2APIC_CID_BITS) - 1;
                        new->lid_mask = 0xffff;
                        new->broadcast = X2APIC_BROADCAST;
-               } else if (kvm_apic_sw_enabled(apic) &&
-                               !new->cid_mask /* flat mode */ &&
-                               kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_CLUSTER) {
-                       new->cid_shift = 4;
-                       new->cid_mask = 0xf;
-                       new->lid_mask = 0xf;
+               } else if (kvm_apic_get_reg(apic, APIC_LDR)) {
+                       if (kvm_apic_get_reg(apic, APIC_DFR) ==
+                                                       APIC_DFR_CLUSTER) {
+                               new->cid_shift = 4;
+                               new->cid_mask = 0xf;
+                               new->lid_mask = 0xf;
+                       } else {
+                               new->cid_shift = 8;
+                               new->cid_mask = 0;
+                               new->lid_mask = 0xff;
+                       }
                }
 
+               /*
+                * All APICs have to be configured in the same mode by an OS.
+                * We take advatage of this while building logical id loockup
+                * table. After reset APICs are in software disabled mode, so if
+                * we find apic with different setting we assume this is the mode
+                * OS wants all apics to be in; build lookup table accordingly.
+                */
+               if (kvm_apic_sw_enabled(apic))
+                       break;
+       }
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               struct kvm_lapic *apic = vcpu->arch.apic;
+               u16 cid, lid;
+               u32 ldr;
+
                new->phys_map[kvm_apic_id(apic)] = apic;
 
                ldr = kvm_apic_get_reg(apic, APIC_LDR);
@@ -244,21 +256,17 @@ static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
 
 static inline int apic_lvtt_oneshot(struct kvm_lapic *apic)
 {
-       return ((kvm_apic_get_reg(apic, APIC_LVTT) &
-               apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_ONESHOT);
+       return apic->lapic_timer.timer_mode == APIC_LVT_TIMER_ONESHOT;
 }
 
 static inline int apic_lvtt_period(struct kvm_lapic *apic)
 {
-       return ((kvm_apic_get_reg(apic, APIC_LVTT) &
-               apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_PERIODIC);
+       return apic->lapic_timer.timer_mode == APIC_LVT_TIMER_PERIODIC;
 }
 
 static inline int apic_lvtt_tscdeadline(struct kvm_lapic *apic)
 {
-       return ((kvm_apic_get_reg(apic, APIC_LVTT) &
-               apic->lapic_timer.timer_mode_mask) ==
-                       APIC_LVT_TIMER_TSCDEADLINE);
+       return apic->lapic_timer.timer_mode == APIC_LVT_TIMER_TSCDEADLINE;
 }
 
 static inline int apic_lvt_nmi_mode(u32 lvt_val)
@@ -333,8 +341,12 @@ EXPORT_SYMBOL_GPL(kvm_apic_update_irr);
 
 static inline void apic_set_irr(int vec, struct kvm_lapic *apic)
 {
-       apic->irr_pending = true;
        apic_set_vector(vec, apic->regs + APIC_IRR);
+       /*
+        * irr_pending must be true if any interrupt is pending; set it after
+        * APIC_IRR to avoid race with apic_clear_irr
+        */
+       apic->irr_pending = true;
 }
 
 static inline int apic_search_irr(struct kvm_lapic *apic)
@@ -366,13 +378,15 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
 
        vcpu = apic->vcpu;
 
-       apic_clear_vector(vec, apic->regs + APIC_IRR);
-       if (unlikely(kvm_apic_vid_enabled(vcpu->kvm)))
+       if (unlikely(kvm_apic_vid_enabled(vcpu->kvm))) {
                /* try to update RVI */
+               apic_clear_vector(vec, apic->regs + APIC_IRR);
                kvm_make_request(KVM_REQ_EVENT, vcpu);
-       else {
-               vec = apic_search_irr(apic);
-               apic->irr_pending = (vec != -1);
+       } else {
+               apic->irr_pending = false;
+               apic_clear_vector(vec, apic->regs + APIC_IRR);
+               if (apic_search_irr(apic) != -1)
+                       apic->irr_pending = true;
        }
 }
 
@@ -1461,6 +1475,10 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
        apic->base_address = apic->vcpu->arch.apic_base &
                             MSR_IA32_APICBASE_BASE;
 
+       if ((value & MSR_IA32_APICBASE_ENABLE) &&
+            apic->base_address != APIC_DEFAULT_PHYS_BASE)
+               pr_warn_once("APIC base relocation is unsupported by KVM");
+
        /* with FSB delivery interrupt, we can restart APIC functionality */
        apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is "
                   "0x%lx.\n", apic->vcpu->arch.apic_base, apic->base_address);
@@ -1718,6 +1736,9 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
        apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm) ?
                                1 : count_vectors(apic->regs + APIC_ISR);
        apic->highest_isr_cache = -1;
+       if (kvm_x86_ops->hwapic_irr_update)
+               kvm_x86_ops->hwapic_irr_update(vcpu,
+                               apic_find_highest_irr(apic));
        kvm_x86_ops->hwapic_isr_update(vcpu->kvm, apic_find_highest_isr(apic));
        kvm_make_request(KVM_REQ_EVENT, vcpu);
        kvm_rtc_eoi_tracking_restore_one(vcpu);
@@ -1862,8 +1883,11 @@ int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
        if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
                return 1;
 
+       if (reg == APIC_ICR2)
+               return 1;
+
        /* if this is ICR write vector before command */
-       if (msr == 0x830)
+       if (reg == APIC_ICR)
                apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
        return apic_reg_write(apic, reg, (u32)data);
 }
@@ -1876,9 +1900,15 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
        if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
                return 1;
 
+       if (reg == APIC_DFR || reg == APIC_ICR2) {
+               apic_debug("KVM_APIC_READ: read x2apic reserved register %x\n",
+                          reg);
+               return 1;
+       }
+
        if (apic_reg_read(apic, reg, 4, &low))
                return 1;
-       if (msr == 0x830)
+       if (reg == APIC_ICR)
                apic_reg_read(apic, APIC_ICR2, 4, &high);
 
        *data = (((u64)high) << 32) | low;
@@ -1933,7 +1963,7 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data)
 void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
-       unsigned int sipi_vector;
+       u8 sipi_vector;
        unsigned long pe;
 
        if (!kvm_vcpu_has_lapic(vcpu) || !apic->pending_events)
This page took 0.025749 seconds and 5 git commands to generate.