aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2009-07-05 10:39:36 -0400
committerAvi Kivity <avi@redhat.com>2009-09-10 01:33:08 -0400
commit0105d1a526404cfc9779552a6198bfd0e5fc937a (patch)
treeedf269da022574fe380b73473daef4b763b25672 /arch
parentfc61b800f9506ca47bf1439342a79847f2353562 (diff)
KVM: x2apic interface to lapic
This patch implements MSR interface to local apic as defines by x2apic Intel specification. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kvm/lapic.c223
-rw-r--r--arch/x86/kvm/lapic.h2
-rw-r--r--arch/x86/kvm/x86.c7
3 files changed, 173 insertions, 59 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 62ea2abfd961..683345a121b7 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -32,6 +32,7 @@
32#include <asm/current.h> 32#include <asm/current.h>
33#include <asm/apicdef.h> 33#include <asm/apicdef.h>
34#include <asm/atomic.h> 34#include <asm/atomic.h>
35#include <asm/apicdef.h>
35#include "kvm_cache_regs.h" 36#include "kvm_cache_regs.h"
36#include "irq.h" 37#include "irq.h"
37#include "trace.h" 38#include "trace.h"
@@ -158,6 +159,11 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu)
158 apic_set_reg(apic, APIC_LVR, v); 159 apic_set_reg(apic, APIC_LVR, v);
159} 160}
160 161
162static inline int apic_x2apic_mode(struct kvm_lapic *apic)
163{
164 return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
165}
166
161static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { 167static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
162 LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */ 168 LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */
163 LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ 169 LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */
@@ -284,7 +290,12 @@ int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
284int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) 290int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
285{ 291{
286 int result = 0; 292 int result = 0;
287 u8 logical_id; 293 u32 logical_id;
294
295 if (apic_x2apic_mode(apic)) {
296 logical_id = apic_get_reg(apic, APIC_LDR);
297 return logical_id & mda;
298 }
288 299
289 logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR)); 300 logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR));
290 301
@@ -477,7 +488,10 @@ static void apic_send_ipi(struct kvm_lapic *apic)
477 irq.level = icr_low & APIC_INT_ASSERT; 488 irq.level = icr_low & APIC_INT_ASSERT;
478 irq.trig_mode = icr_low & APIC_INT_LEVELTRIG; 489 irq.trig_mode = icr_low & APIC_INT_LEVELTRIG;
479 irq.shorthand = icr_low & APIC_SHORT_MASK; 490 irq.shorthand = icr_low & APIC_SHORT_MASK;
480 irq.dest_id = GET_APIC_DEST_FIELD(icr_high); 491 if (apic_x2apic_mode(apic))
492 irq.dest_id = icr_high;
493 else
494 irq.dest_id = GET_APIC_DEST_FIELD(icr_high);
481 495
482 apic_debug("icr_high 0x%x, icr_low 0x%x, " 496 apic_debug("icr_high 0x%x, icr_low 0x%x, "
483 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " 497 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
@@ -538,6 +552,12 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
538 return 0; 552 return 0;
539 553
540 switch (offset) { 554 switch (offset) {
555 case APIC_ID:
556 if (apic_x2apic_mode(apic))
557 val = kvm_apic_id(apic);
558 else
559 val = kvm_apic_id(apic) << 24;
560 break;
541 case APIC_ARBPRI: 561 case APIC_ARBPRI:
542 printk(KERN_WARNING "Access APIC ARBPRI register " 562 printk(KERN_WARNING "Access APIC ARBPRI register "
543 "which is for P6\n"); 563 "which is for P6\n");
@@ -564,28 +584,26 @@ static inline struct kvm_lapic *to_lapic(struct kvm_io_device *dev)
564 return container_of(dev, struct kvm_lapic, dev); 584 return container_of(dev, struct kvm_lapic, dev);
565} 585}
566 586
567static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr) 587static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
568{ 588 void *data)
569 return apic_hw_enabled(apic) &&
570 addr >= apic->base_address &&
571 addr < apic->base_address + LAPIC_MMIO_LENGTH;
572}
573
574static int apic_mmio_read(struct kvm_io_device *this,
575 gpa_t address, int len, void *data)
576{ 589{
577 struct kvm_lapic *apic = to_lapic(this);
578 unsigned int offset = address - apic->base_address;
579 unsigned char alignment = offset & 0xf; 590 unsigned char alignment = offset & 0xf;
580 u32 result; 591 u32 result;
581 if (!apic_mmio_in_range(apic, address)) 592 /* this bitmask has a bit cleared for each reserver register */
582 return -EOPNOTSUPP; 593 static const u64 rmask = 0x43ff01ffffffe70cULL;
583 594
584 if ((alignment + len) > 4) { 595 if ((alignment + len) > 4) {
585 printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d", 596 printk(KERN_ERR "KVM_APIC_READ: alignment error %x %d\n",
586 (unsigned long)address, len); 597 offset, len);
587 return 0; 598 return 1;
588 } 599 }
600
601 if (offset > 0x3f0 || !(rmask & (1ULL << (offset >> 4)))) {
602 printk(KERN_ERR "KVM_APIC_READ: read reserved register %x\n",
603 offset);
604 return 1;
605 }
606
589 result = __apic_read(apic, offset & ~0xf); 607 result = __apic_read(apic, offset & ~0xf);
590 608
591 trace_kvm_apic_read(offset, result); 609 trace_kvm_apic_read(offset, result);
@@ -604,6 +622,27 @@ static int apic_mmio_read(struct kvm_io_device *this,
604 return 0; 622 return 0;
605} 623}
606 624
625static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr)
626{
627 return apic_hw_enabled(apic) &&
628 addr >= apic->base_address &&
629 addr < apic->base_address + LAPIC_MMIO_LENGTH;
630}
631
632static int apic_mmio_read(struct kvm_io_device *this,
633 gpa_t address, int len, void *data)
634{
635 struct kvm_lapic *apic = to_lapic(this);
636 u32 offset = address - apic->base_address;
637
638 if (!apic_mmio_in_range(apic, address))
639 return -EOPNOTSUPP;
640
641 apic_reg_read(apic, offset, len, data);
642
643 return 0;
644}
645
607static void update_divide_count(struct kvm_lapic *apic) 646static void update_divide_count(struct kvm_lapic *apic)
608{ 647{
609 u32 tmp1, tmp2, tdcr; 648 u32 tmp1, tmp2, tdcr;
@@ -657,42 +696,18 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
657 apic->vcpu->kvm->arch.vapics_in_nmi_mode--; 696 apic->vcpu->kvm->arch.vapics_in_nmi_mode--;
658} 697}
659 698
660static int apic_mmio_write(struct kvm_io_device *this, 699static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
661 gpa_t address, int len, const void *data)
662{ 700{
663 struct kvm_lapic *apic = to_lapic(this); 701 int ret = 0;
664 unsigned int offset = address - apic->base_address;
665 unsigned char alignment = offset & 0xf;
666 u32 val;
667 if (!apic_mmio_in_range(apic, address))
668 return -EOPNOTSUPP;
669
670 /*
671 * APIC register must be aligned on 128-bits boundary.
672 * 32/64/128 bits registers must be accessed thru 32 bits.
673 * Refer SDM 8.4.1
674 */
675 if (len != 4 || alignment) {
676 /* Don't shout loud, $infamous_os would cause only noise. */
677 apic_debug("apic write: bad size=%d %lx\n",
678 len, (long)address);
679 return 0;
680 }
681
682 val = *(u32 *) data;
683 702
684 /* too common printing */ 703 trace_kvm_apic_write(reg, val);
685 if (offset != APIC_EOI)
686 apic_debug("%s: offset 0x%x with length 0x%x, and value is "
687 "0x%x\n", __func__, offset, len, val);
688 704
689 offset &= 0xff0; 705 switch (reg) {
690
691 trace_kvm_apic_write(offset, val);
692
693 switch (offset) {
694 case APIC_ID: /* Local APIC ID */ 706 case APIC_ID: /* Local APIC ID */
695 apic_set_reg(apic, APIC_ID, val); 707 if (!apic_x2apic_mode(apic))
708 apic_set_reg(apic, APIC_ID, val);
709 else
710 ret = 1;
696 break; 711 break;
697 712
698 case APIC_TASKPRI: 713 case APIC_TASKPRI:
@@ -705,11 +720,17 @@ static int apic_mmio_write(struct kvm_io_device *this,
705 break; 720 break;
706 721
707 case APIC_LDR: 722 case APIC_LDR:
708 apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK); 723 if (!apic_x2apic_mode(apic))
724 apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK);
725 else
726 ret = 1;
709 break; 727 break;
710 728
711 case APIC_DFR: 729 case APIC_DFR:
712 apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); 730 if (!apic_x2apic_mode(apic))
731 apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
732 else
733 ret = 1;
713 break; 734 break;
714 735
715 case APIC_SPIV: { 736 case APIC_SPIV: {
@@ -739,7 +760,9 @@ static int apic_mmio_write(struct kvm_io_device *this,
739 break; 760 break;
740 761
741 case APIC_ICR2: 762 case APIC_ICR2:
742 apic_set_reg(apic, APIC_ICR2, val & 0xff000000); 763 if (!apic_x2apic_mode(apic))
764 val &= 0xff000000;
765 apic_set_reg(apic, APIC_ICR2, val);
743 break; 766 break;
744 767
745 case APIC_LVT0: 768 case APIC_LVT0:
@@ -753,8 +776,8 @@ static int apic_mmio_write(struct kvm_io_device *this,
753 if (!apic_sw_enabled(apic)) 776 if (!apic_sw_enabled(apic))
754 val |= APIC_LVT_MASKED; 777 val |= APIC_LVT_MASKED;
755 778
756 val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4]; 779 val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4];
757 apic_set_reg(apic, offset, val); 780 apic_set_reg(apic, reg, val);
758 781
759 break; 782 break;
760 783
@@ -762,7 +785,7 @@ static int apic_mmio_write(struct kvm_io_device *this,
762 hrtimer_cancel(&apic->lapic_timer.timer); 785 hrtimer_cancel(&apic->lapic_timer.timer);
763 apic_set_reg(apic, APIC_TMICT, val); 786 apic_set_reg(apic, APIC_TMICT, val);
764 start_apic_timer(apic); 787 start_apic_timer(apic);
765 return 0; 788 break;
766 789
767 case APIC_TDCR: 790 case APIC_TDCR:
768 if (val & 4) 791 if (val & 4)
@@ -771,11 +794,58 @@ static int apic_mmio_write(struct kvm_io_device *this,
771 update_divide_count(apic); 794 update_divide_count(apic);
772 break; 795 break;
773 796
797 case APIC_ESR:
798 if (apic_x2apic_mode(apic) && val != 0) {
799 printk(KERN_ERR "KVM_WRITE:ESR not zero %x\n", val);
800 ret = 1;
801 }
802 break;
803
804 case APIC_SELF_IPI:
805 if (apic_x2apic_mode(apic)) {
806 apic_reg_write(apic, APIC_ICR, 0x40000 | (val & 0xff));
807 } else
808 ret = 1;
809 break;
774 default: 810 default:
775 apic_debug("Local APIC Write to read-only register %x\n", 811 ret = 1;
776 offset);
777 break; 812 break;
778 } 813 }
814 if (ret)
815 apic_debug("Local APIC Write to read-only register %x\n", reg);
816 return ret;
817}
818
819static int apic_mmio_write(struct kvm_io_device *this,
820 gpa_t address, int len, const void *data)
821{
822 struct kvm_lapic *apic = to_lapic(this);
823 unsigned int offset = address - apic->base_address;
824 u32 val;
825
826 if (!apic_mmio_in_range(apic, address))
827 return -EOPNOTSUPP;
828
829 /*
830 * APIC register must be aligned on 128-bits boundary.
831 * 32/64/128 bits registers must be accessed thru 32 bits.
832 * Refer SDM 8.4.1
833 */
834 if (len != 4 || (offset & 0xf)) {
835 /* Don't shout loud, $infamous_os would cause only noise. */
836 apic_debug("apic write: bad size=%d %lx\n", len, (long)address);
837 return;
838 }
839
840 val = *(u32*)data;
841
842 /* too common printing */
843 if (offset != APIC_EOI)
844 apic_debug("%s: offset 0x%x with length 0x%x, and value is "
845 "0x%x\n", __func__, offset, len, val);
846
847 apic_reg_write(apic, offset & 0xff0, val);
848
779 return 0; 849 return 0;
780} 850}
781 851
@@ -834,6 +904,11 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
834 value &= ~MSR_IA32_APICBASE_BSP; 904 value &= ~MSR_IA32_APICBASE_BSP;
835 905
836 vcpu->arch.apic_base = value; 906 vcpu->arch.apic_base = value;
907 if (apic_x2apic_mode(apic)) {
908 u32 id = kvm_apic_id(apic);
909 u32 ldr = ((id & ~0xf) << 16) | (1 << (id & 0xf));
910 apic_set_reg(apic, APIC_LDR, ldr);
911 }
837 apic->base_address = apic->vcpu->arch.apic_base & 912 apic->base_address = apic->vcpu->arch.apic_base &
838 MSR_IA32_APICBASE_BASE; 913 MSR_IA32_APICBASE_BASE;
839 914
@@ -1130,3 +1205,35 @@ void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
1130 1205
1131 vcpu->arch.apic->vapic_addr = vapic_addr; 1206 vcpu->arch.apic->vapic_addr = vapic_addr;
1132} 1207}
1208
1209int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
1210{
1211 struct kvm_lapic *apic = vcpu->arch.apic;
1212 u32 reg = (msr - APIC_BASE_MSR) << 4;
1213
1214 if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
1215 return 1;
1216
1217 /* if this is ICR write vector before command */
1218 if (msr == 0x830)
1219 apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
1220 return apic_reg_write(apic, reg, (u32)data);
1221}
1222
1223int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
1224{
1225 struct kvm_lapic *apic = vcpu->arch.apic;
1226 u32 reg = (msr - APIC_BASE_MSR) << 4, low, high = 0;
1227
1228 if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
1229 return 1;
1230
1231 if (apic_reg_read(apic, reg, 4, &low))
1232 return 1;
1233 if (msr == 0x830)
1234 apic_reg_read(apic, APIC_ICR2, 4, &high);
1235
1236 *data = (((u64)high) << 32) | low;
1237
1238 return 0;
1239}
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index bc1c5243c865..40010b09c4aa 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -46,4 +46,6 @@ void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
46void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu); 46void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
47void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu); 47void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
48 48
49int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data);
50int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
49#endif 51#endif
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 086f93137e3c..a50c83232e76 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -867,6 +867,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
867 case MSR_IA32_APICBASE: 867 case MSR_IA32_APICBASE:
868 kvm_set_apic_base(vcpu, data); 868 kvm_set_apic_base(vcpu, data);
869 break; 869 break;
870 case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
871 return kvm_x2apic_msr_write(vcpu, msr, data);
870 case MSR_IA32_MISC_ENABLE: 872 case MSR_IA32_MISC_ENABLE:
871 vcpu->arch.ia32_misc_enable_msr = data; 873 vcpu->arch.ia32_misc_enable_msr = data;
872 break; 874 break;
@@ -1065,6 +1067,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
1065 case MSR_IA32_APICBASE: 1067 case MSR_IA32_APICBASE:
1066 data = kvm_get_apic_base(vcpu); 1068 data = kvm_get_apic_base(vcpu);
1067 break; 1069 break;
1070 case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
1071 return kvm_x2apic_msr_read(vcpu, msr, pdata);
1072 break;
1068 case MSR_IA32_MISC_ENABLE: 1073 case MSR_IA32_MISC_ENABLE:
1069 data = vcpu->arch.ia32_misc_enable_msr; 1074 data = vcpu->arch.ia32_misc_enable_msr;
1070 break; 1075 break;
@@ -1469,7 +1474,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
1469 0 /* TM2 */ | F(SSSE3) | 0 /* CNXT-ID */ | 0 /* Reserved */ | 1474 0 /* TM2 */ | F(SSSE3) | 0 /* CNXT-ID */ | 0 /* Reserved */ |
1470 0 /* Reserved */ | F(CX16) | 0 /* xTPR Update, PDCM */ | 1475 0 /* Reserved */ | F(CX16) | 0 /* xTPR Update, PDCM */ |
1471 0 /* Reserved, DCA */ | F(XMM4_1) | 1476 0 /* Reserved, DCA */ | F(XMM4_1) |
1472 F(XMM4_2) | 0 /* x2APIC */ | F(MOVBE) | F(POPCNT) | 1477 F(XMM4_2) | F(X2APIC) | F(MOVBE) | F(POPCNT) |
1473 0 /* Reserved, XSAVE, OSXSAVE */; 1478 0 /* Reserved, XSAVE, OSXSAVE */;
1474 /* cpuid 0x80000001.ecx */ 1479 /* cpuid 0x80000001.ecx */
1475 const u32 kvm_supported_word6_x86_features = 1480 const u32 kvm_supported_word6_x86_features =