diff options
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r-- | arch/x86/kvm/lapic.c | 154 |
1 files changed, 88 insertions, 66 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index e55b5fc344eb..d67206a7b99a 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -133,6 +133,28 @@ static inline int kvm_apic_id(struct kvm_lapic *apic) | |||
133 | return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; | 133 | return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; |
134 | } | 134 | } |
135 | 135 | ||
136 | /* The logical map is definitely wrong if we have multiple | ||
137 | * modes at the same time. (Physical map is always right.) | ||
138 | */ | ||
139 | static inline bool kvm_apic_logical_map_valid(struct kvm_apic_map *map) | ||
140 | { | ||
141 | return !(map->mode & (map->mode - 1)); | ||
142 | } | ||
143 | |||
144 | static inline void | ||
145 | apic_logical_id(struct kvm_apic_map *map, u32 dest_id, u16 *cid, u16 *lid) | ||
146 | { | ||
147 | unsigned lid_bits; | ||
148 | |||
149 | BUILD_BUG_ON(KVM_APIC_MODE_XAPIC_CLUSTER != 4); | ||
150 | BUILD_BUG_ON(KVM_APIC_MODE_XAPIC_FLAT != 8); | ||
151 | BUILD_BUG_ON(KVM_APIC_MODE_X2APIC != 16); | ||
152 | lid_bits = map->mode; | ||
153 | |||
154 | *cid = dest_id >> lid_bits; | ||
155 | *lid = dest_id & ((1 << lid_bits) - 1); | ||
156 | } | ||
157 | |||
136 | static void recalculate_apic_map(struct kvm *kvm) | 158 | static void recalculate_apic_map(struct kvm *kvm) |
137 | { | 159 | { |
138 | struct kvm_apic_map *new, *old = NULL; | 160 | struct kvm_apic_map *new, *old = NULL; |
@@ -146,48 +168,6 @@ static void recalculate_apic_map(struct kvm *kvm) | |||
146 | if (!new) | 168 | if (!new) |
147 | goto out; | 169 | goto out; |
148 | 170 | ||
149 | new->ldr_bits = 8; | ||
150 | /* flat mode is default */ | ||
151 | new->cid_shift = 8; | ||
152 | new->cid_mask = 0; | ||
153 | new->lid_mask = 0xff; | ||
154 | new->broadcast = APIC_BROADCAST; | ||
155 | |||
156 | kvm_for_each_vcpu(i, vcpu, kvm) { | ||
157 | struct kvm_lapic *apic = vcpu->arch.apic; | ||
158 | |||
159 | if (!kvm_apic_present(vcpu)) | ||
160 | continue; | ||
161 | |||
162 | if (apic_x2apic_mode(apic)) { | ||
163 | new->ldr_bits = 32; | ||
164 | new->cid_shift = 16; | ||
165 | new->cid_mask = new->lid_mask = 0xffff; | ||
166 | new->broadcast = X2APIC_BROADCAST; | ||
167 | } else if (kvm_apic_get_reg(apic, APIC_LDR)) { | ||
168 | if (kvm_apic_get_reg(apic, APIC_DFR) == | ||
169 | APIC_DFR_CLUSTER) { | ||
170 | new->cid_shift = 4; | ||
171 | new->cid_mask = 0xf; | ||
172 | new->lid_mask = 0xf; | ||
173 | } else { | ||
174 | new->cid_shift = 8; | ||
175 | new->cid_mask = 0; | ||
176 | new->lid_mask = 0xff; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * All APICs have to be configured in the same mode by an OS. | ||
182 | * We take advatage of this while building logical id loockup | ||
183 | * table. After reset APICs are in software disabled mode, so if | ||
184 | * we find apic with different setting we assume this is the mode | ||
185 | * OS wants all apics to be in; build lookup table accordingly. | ||
186 | */ | ||
187 | if (kvm_apic_sw_enabled(apic)) | ||
188 | break; | ||
189 | } | ||
190 | |||
191 | kvm_for_each_vcpu(i, vcpu, kvm) { | 171 | kvm_for_each_vcpu(i, vcpu, kvm) { |
192 | struct kvm_lapic *apic = vcpu->arch.apic; | 172 | struct kvm_lapic *apic = vcpu->arch.apic; |
193 | u16 cid, lid; | 173 | u16 cid, lid; |
@@ -198,11 +178,25 @@ static void recalculate_apic_map(struct kvm *kvm) | |||
198 | 178 | ||
199 | aid = kvm_apic_id(apic); | 179 | aid = kvm_apic_id(apic); |
200 | ldr = kvm_apic_get_reg(apic, APIC_LDR); | 180 | ldr = kvm_apic_get_reg(apic, APIC_LDR); |
201 | cid = apic_cluster_id(new, ldr); | ||
202 | lid = apic_logical_id(new, ldr); | ||
203 | 181 | ||
204 | if (aid < ARRAY_SIZE(new->phys_map)) | 182 | if (aid < ARRAY_SIZE(new->phys_map)) |
205 | new->phys_map[aid] = apic; | 183 | new->phys_map[aid] = apic; |
184 | |||
185 | if (apic_x2apic_mode(apic)) { | ||
186 | new->mode |= KVM_APIC_MODE_X2APIC; | ||
187 | } else if (ldr) { | ||
188 | ldr = GET_APIC_LOGICAL_ID(ldr); | ||
189 | if (kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_FLAT) | ||
190 | new->mode |= KVM_APIC_MODE_XAPIC_FLAT; | ||
191 | else | ||
192 | new->mode |= KVM_APIC_MODE_XAPIC_CLUSTER; | ||
193 | } | ||
194 | |||
195 | if (!kvm_apic_logical_map_valid(new)) | ||
196 | continue; | ||
197 | |||
198 | apic_logical_id(new, ldr, &cid, &lid); | ||
199 | |||
206 | if (lid && cid < ARRAY_SIZE(new->logical_map)) | 200 | if (lid && cid < ARRAY_SIZE(new->logical_map)) |
207 | new->logical_map[cid][ffs(lid) - 1] = apic; | 201 | new->logical_map[cid][ffs(lid) - 1] = apic; |
208 | } | 202 | } |
@@ -588,15 +582,23 @@ static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) | |||
588 | apic_update_ppr(apic); | 582 | apic_update_ppr(apic); |
589 | } | 583 | } |
590 | 584 | ||
591 | static bool kvm_apic_broadcast(struct kvm_lapic *apic, u32 dest) | 585 | static bool kvm_apic_broadcast(struct kvm_lapic *apic, u32 mda) |
592 | { | 586 | { |
593 | return dest == (apic_x2apic_mode(apic) ? | 587 | if (apic_x2apic_mode(apic)) |
594 | X2APIC_BROADCAST : APIC_BROADCAST); | 588 | return mda == X2APIC_BROADCAST; |
589 | |||
590 | return GET_APIC_DEST_FIELD(mda) == APIC_BROADCAST; | ||
595 | } | 591 | } |
596 | 592 | ||
597 | static bool kvm_apic_match_physical_addr(struct kvm_lapic *apic, u32 dest) | 593 | static bool kvm_apic_match_physical_addr(struct kvm_lapic *apic, u32 mda) |
598 | { | 594 | { |
599 | return kvm_apic_id(apic) == dest || kvm_apic_broadcast(apic, dest); | 595 | if (kvm_apic_broadcast(apic, mda)) |
596 | return true; | ||
597 | |||
598 | if (apic_x2apic_mode(apic)) | ||
599 | return mda == kvm_apic_id(apic); | ||
600 | |||
601 | return mda == SET_APIC_DEST_FIELD(kvm_apic_id(apic)); | ||
600 | } | 602 | } |
601 | 603 | ||
602 | static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda) | 604 | static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda) |
@@ -613,6 +615,7 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda) | |||
613 | && (logical_id & mda & 0xffff) != 0; | 615 | && (logical_id & mda & 0xffff) != 0; |
614 | 616 | ||
615 | logical_id = GET_APIC_LOGICAL_ID(logical_id); | 617 | logical_id = GET_APIC_LOGICAL_ID(logical_id); |
618 | mda = GET_APIC_DEST_FIELD(mda); | ||
616 | 619 | ||
617 | switch (kvm_apic_get_reg(apic, APIC_DFR)) { | 620 | switch (kvm_apic_get_reg(apic, APIC_DFR)) { |
618 | case APIC_DFR_FLAT: | 621 | case APIC_DFR_FLAT: |
@@ -627,10 +630,27 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda) | |||
627 | } | 630 | } |
628 | } | 631 | } |
629 | 632 | ||
633 | /* KVM APIC implementation has two quirks | ||
634 | * - dest always begins at 0 while xAPIC MDA has offset 24, | ||
635 | * - IOxAPIC messages have to be delivered (directly) to x2APIC. | ||
636 | */ | ||
637 | static u32 kvm_apic_mda(unsigned int dest_id, struct kvm_lapic *source, | ||
638 | struct kvm_lapic *target) | ||
639 | { | ||
640 | bool ipi = source != NULL; | ||
641 | bool x2apic_mda = apic_x2apic_mode(ipi ? source : target); | ||
642 | |||
643 | if (!ipi && dest_id == APIC_BROADCAST && x2apic_mda) | ||
644 | return X2APIC_BROADCAST; | ||
645 | |||
646 | return x2apic_mda ? dest_id : SET_APIC_DEST_FIELD(dest_id); | ||
647 | } | ||
648 | |||
630 | bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, | 649 | bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, |
631 | int short_hand, unsigned int dest, int dest_mode) | 650 | int short_hand, unsigned int dest, int dest_mode) |
632 | { | 651 | { |
633 | struct kvm_lapic *target = vcpu->arch.apic; | 652 | struct kvm_lapic *target = vcpu->arch.apic; |
653 | u32 mda = kvm_apic_mda(dest, source, target); | ||
634 | 654 | ||
635 | apic_debug("target %p, source %p, dest 0x%x, " | 655 | apic_debug("target %p, source %p, dest 0x%x, " |
636 | "dest_mode 0x%x, short_hand 0x%x\n", | 656 | "dest_mode 0x%x, short_hand 0x%x\n", |
@@ -640,9 +660,9 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, | |||
640 | switch (short_hand) { | 660 | switch (short_hand) { |
641 | case APIC_DEST_NOSHORT: | 661 | case APIC_DEST_NOSHORT: |
642 | if (dest_mode == APIC_DEST_PHYSICAL) | 662 | if (dest_mode == APIC_DEST_PHYSICAL) |
643 | return kvm_apic_match_physical_addr(target, dest); | 663 | return kvm_apic_match_physical_addr(target, mda); |
644 | else | 664 | else |
645 | return kvm_apic_match_logical_addr(target, dest); | 665 | return kvm_apic_match_logical_addr(target, mda); |
646 | case APIC_DEST_SELF: | 666 | case APIC_DEST_SELF: |
647 | return target == source; | 667 | return target == source; |
648 | case APIC_DEST_ALLINC: | 668 | case APIC_DEST_ALLINC: |
@@ -664,6 +684,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, | |||
664 | struct kvm_lapic **dst; | 684 | struct kvm_lapic **dst; |
665 | int i; | 685 | int i; |
666 | bool ret = false; | 686 | bool ret = false; |
687 | bool x2apic_ipi = src && apic_x2apic_mode(src); | ||
667 | 688 | ||
668 | *r = -1; | 689 | *r = -1; |
669 | 690 | ||
@@ -675,15 +696,15 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, | |||
675 | if (irq->shorthand) | 696 | if (irq->shorthand) |
676 | return false; | 697 | return false; |
677 | 698 | ||
699 | if (irq->dest_id == (x2apic_ipi ? X2APIC_BROADCAST : APIC_BROADCAST)) | ||
700 | return false; | ||
701 | |||
678 | rcu_read_lock(); | 702 | rcu_read_lock(); |
679 | map = rcu_dereference(kvm->arch.apic_map); | 703 | map = rcu_dereference(kvm->arch.apic_map); |
680 | 704 | ||
681 | if (!map) | 705 | if (!map) |
682 | goto out; | 706 | goto out; |
683 | 707 | ||
684 | if (irq->dest_id == map->broadcast) | ||
685 | goto out; | ||
686 | |||
687 | ret = true; | 708 | ret = true; |
688 | 709 | ||
689 | if (irq->dest_mode == APIC_DEST_PHYSICAL) { | 710 | if (irq->dest_mode == APIC_DEST_PHYSICAL) { |
@@ -692,16 +713,20 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, | |||
692 | 713 | ||
693 | dst = &map->phys_map[irq->dest_id]; | 714 | dst = &map->phys_map[irq->dest_id]; |
694 | } else { | 715 | } else { |
695 | u32 mda = irq->dest_id << (32 - map->ldr_bits); | 716 | u16 cid; |
696 | u16 cid = apic_cluster_id(map, mda); | 717 | |
718 | if (!kvm_apic_logical_map_valid(map)) { | ||
719 | ret = false; | ||
720 | goto out; | ||
721 | } | ||
722 | |||
723 | apic_logical_id(map, irq->dest_id, &cid, (u16 *)&bitmap); | ||
697 | 724 | ||
698 | if (cid >= ARRAY_SIZE(map->logical_map)) | 725 | if (cid >= ARRAY_SIZE(map->logical_map)) |
699 | goto out; | 726 | goto out; |
700 | 727 | ||
701 | dst = map->logical_map[cid]; | 728 | dst = map->logical_map[cid]; |
702 | 729 | ||
703 | bitmap = apic_logical_id(map, mda); | ||
704 | |||
705 | if (irq->delivery_mode == APIC_DM_LOWEST) { | 730 | if (irq->delivery_mode == APIC_DM_LOWEST) { |
706 | int l = -1; | 731 | int l = -1; |
707 | for_each_set_bit(i, &bitmap, 16) { | 732 | for_each_set_bit(i, &bitmap, 16) { |
@@ -833,8 +858,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2) | |||
833 | 858 | ||
834 | static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector) | 859 | static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector) |
835 | { | 860 | { |
836 | if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) && | 861 | if (kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) { |
837 | kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) { | ||
838 | int trigger_mode; | 862 | int trigger_mode; |
839 | if (apic_test_vector(vector, apic->regs + APIC_TMR)) | 863 | if (apic_test_vector(vector, apic->regs + APIC_TMR)) |
840 | trigger_mode = IOAPIC_LEVEL_TRIG; | 864 | trigger_mode = IOAPIC_LEVEL_TRIG; |
@@ -1038,7 +1062,7 @@ static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr) | |||
1038 | addr < apic->base_address + LAPIC_MMIO_LENGTH; | 1062 | addr < apic->base_address + LAPIC_MMIO_LENGTH; |
1039 | } | 1063 | } |
1040 | 1064 | ||
1041 | static int apic_mmio_read(struct kvm_io_device *this, | 1065 | static int apic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this, |
1042 | gpa_t address, int len, void *data) | 1066 | gpa_t address, int len, void *data) |
1043 | { | 1067 | { |
1044 | struct kvm_lapic *apic = to_lapic(this); | 1068 | struct kvm_lapic *apic = to_lapic(this); |
@@ -1358,7 +1382,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) | |||
1358 | return ret; | 1382 | return ret; |
1359 | } | 1383 | } |
1360 | 1384 | ||
1361 | static int apic_mmio_write(struct kvm_io_device *this, | 1385 | static int apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this, |
1362 | gpa_t address, int len, const void *data) | 1386 | gpa_t address, int len, const void *data) |
1363 | { | 1387 | { |
1364 | struct kvm_lapic *apic = to_lapic(this); | 1388 | struct kvm_lapic *apic = to_lapic(this); |
@@ -1498,8 +1522,6 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) | |||
1498 | return; | 1522 | return; |
1499 | } | 1523 | } |
1500 | 1524 | ||
1501 | if (!kvm_vcpu_is_bsp(apic->vcpu)) | ||
1502 | value &= ~MSR_IA32_APICBASE_BSP; | ||
1503 | vcpu->arch.apic_base = value; | 1525 | vcpu->arch.apic_base = value; |
1504 | 1526 | ||
1505 | /* update jump label if enable bit changes */ | 1527 | /* update jump label if enable bit changes */ |
@@ -1572,7 +1594,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) | |||
1572 | apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); | 1594 | apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); |
1573 | } | 1595 | } |
1574 | apic->irr_pending = kvm_apic_vid_enabled(vcpu->kvm); | 1596 | apic->irr_pending = kvm_apic_vid_enabled(vcpu->kvm); |
1575 | apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm); | 1597 | apic->isr_count = kvm_x86_ops->hwapic_isr_update ? 1 : 0; |
1576 | apic->highest_isr_cache = -1; | 1598 | apic->highest_isr_cache = -1; |
1577 | update_divide_count(apic); | 1599 | update_divide_count(apic); |
1578 | atomic_set(&apic->lapic_timer.pending, 0); | 1600 | atomic_set(&apic->lapic_timer.pending, 0); |
@@ -1782,7 +1804,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, | |||
1782 | update_divide_count(apic); | 1804 | update_divide_count(apic); |
1783 | start_apic_timer(apic); | 1805 | start_apic_timer(apic); |
1784 | apic->irr_pending = true; | 1806 | apic->irr_pending = true; |
1785 | apic->isr_count = kvm_apic_vid_enabled(vcpu->kvm) ? | 1807 | apic->isr_count = kvm_x86_ops->hwapic_isr_update ? |
1786 | 1 : count_vectors(apic->regs + APIC_ISR); | 1808 | 1 : count_vectors(apic->regs + APIC_ISR); |
1787 | apic->highest_isr_cache = -1; | 1809 | apic->highest_isr_cache = -1; |
1788 | if (kvm_x86_ops->hwapic_irr_update) | 1810 | if (kvm_x86_ops->hwapic_irr_update) |