diff options
-rw-r--r-- | drivers/kvm/Makefile | 2 | ||||
-rw-r--r-- | drivers/kvm/irq.c | 53 | ||||
-rw-r--r-- | drivers/kvm/irq.h | 41 | ||||
-rw-r--r-- | drivers/kvm/kvm.h | 3 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 52 | ||||
-rw-r--r-- | drivers/kvm/lapic.c | 933 | ||||
-rw-r--r-- | drivers/kvm/svm.c | 6 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 6 | ||||
-rw-r--r-- | include/linux/kvm.h | 4 |
9 files changed, 1067 insertions, 33 deletions
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile index 952dff38eb6c..3bf7276b032d 100644 --- a/drivers/kvm/Makefile +++ b/drivers/kvm/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for Kernel-based Virtual Machine module | 2 | # Makefile for Kernel-based Virtual Machine module |
3 | # | 3 | # |
4 | 4 | ||
5 | kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o | 5 | kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o lapic.o |
6 | obj-$(CONFIG_KVM) += kvm.o | 6 | obj-$(CONFIG_KVM) += kvm.o |
7 | kvm-intel-objs = vmx.o | 7 | kvm-intel-objs = vmx.o |
8 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o | 8 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o |
diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c index b08005ca7050..0b4430a0cae0 100644 --- a/drivers/kvm/irq.c +++ b/drivers/kvm/irq.c | |||
@@ -30,14 +30,13 @@ | |||
30 | */ | 30 | */ |
31 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v) | 31 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v) |
32 | { | 32 | { |
33 | struct kvm_pic *s = pic_irqchip(v->kvm); | 33 | struct kvm_pic *s; |
34 | 34 | ||
35 | if (s->output) /* PIC */ | 35 | if (kvm_apic_has_interrupt(v) == -1) { /* LAPIC */ |
36 | return 1; | 36 | s = pic_irqchip(v->kvm); /* PIC */ |
37 | /* | 37 | return s->output; |
38 | * TODO: APIC | 38 | } |
39 | */ | 39 | return 1; |
40 | return 0; | ||
41 | } | 40 | } |
42 | EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); | 41 | EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); |
43 | 42 | ||
@@ -46,16 +45,36 @@ EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); | |||
46 | */ | 45 | */ |
47 | int kvm_cpu_get_interrupt(struct kvm_vcpu *v) | 46 | int kvm_cpu_get_interrupt(struct kvm_vcpu *v) |
48 | { | 47 | { |
49 | struct kvm_pic *s = pic_irqchip(v->kvm); | 48 | struct kvm_pic *s; |
50 | int vector; | 49 | int vector; |
51 | 50 | ||
52 | s->output = 0; | 51 | vector = kvm_get_apic_interrupt(v); /* APIC */ |
53 | vector = kvm_pic_read_irq(s); | 52 | if (vector == -1) { |
54 | if (vector != -1) | 53 | s = pic_irqchip(v->kvm); |
55 | return vector; | 54 | s->output = 0; /* PIC */ |
56 | /* | 55 | vector = kvm_pic_read_irq(s); |
57 | * TODO: APIC | 56 | } |
58 | */ | 57 | return vector; |
59 | return -1; | ||
60 | } | 58 | } |
61 | EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); | 59 | EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); |
60 | |||
61 | static void vcpu_kick_intr(void *info) | ||
62 | { | ||
63 | #ifdef DEBUG | ||
64 | struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info; | ||
65 | printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu); | ||
66 | #endif | ||
67 | } | ||
68 | |||
69 | void kvm_vcpu_kick(struct kvm_vcpu *vcpu) | ||
70 | { | ||
71 | int ipi_pcpu = vcpu->cpu; | ||
72 | |||
73 | if (vcpu->guest_mode) | ||
74 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); | ||
75 | } | ||
76 | |||
77 | void kvm_ioapic_update_eoi(struct kvm *kvm, int vector) | ||
78 | { | ||
79 | /* TODO: for kernel IOAPIC */ | ||
80 | } | ||
diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h index bdb2fc34804b..57e23bdac530 100644 --- a/drivers/kvm/irq.h +++ b/drivers/kvm/irq.h | |||
@@ -26,7 +26,6 @@ | |||
26 | 26 | ||
27 | typedef void irq_request_func(void *opaque, int level); | 27 | typedef void irq_request_func(void *opaque, int level); |
28 | 28 | ||
29 | struct kvm_pic; | ||
30 | struct kvm_kpic_state { | 29 | struct kvm_kpic_state { |
31 | u8 last_irr; /* edge detection */ | 30 | u8 last_irr; /* edge detection */ |
32 | u8 irr; /* interrupt request register */ | 31 | u8 irr; /* interrupt request register */ |
@@ -61,4 +60,44 @@ int kvm_pic_read_irq(struct kvm_pic *s); | |||
61 | int kvm_cpu_get_interrupt(struct kvm_vcpu *v); | 60 | int kvm_cpu_get_interrupt(struct kvm_vcpu *v); |
62 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v); | 61 | int kvm_cpu_has_interrupt(struct kvm_vcpu *v); |
63 | 62 | ||
63 | struct kvm_lapic { | ||
64 | unsigned long base_address; | ||
65 | struct kvm_io_device dev; | ||
66 | struct { | ||
67 | atomic_t pending; | ||
68 | s64 period; /* unit: ns */ | ||
69 | u32 divide_count; | ||
70 | ktime_t last_update; | ||
71 | struct hrtimer dev; | ||
72 | } timer; | ||
73 | struct kvm_vcpu *vcpu; | ||
74 | struct page *regs_page; | ||
75 | void *regs; | ||
76 | }; | ||
77 | |||
78 | #ifdef DEBUG | ||
79 | #define ASSERT(x) \ | ||
80 | do { \ | ||
81 | if (!(x)) { \ | ||
82 | printk(KERN_EMERG "assertion failed %s: %d: %s\n", \ | ||
83 | __FILE__, __LINE__, #x); \ | ||
84 | BUG(); \ | ||
85 | } \ | ||
86 | } while (0) | ||
87 | #else | ||
88 | #define ASSERT(x) do { } while (0) | ||
89 | #endif | ||
90 | |||
91 | void kvm_vcpu_kick(struct kvm_vcpu *vcpu); | ||
92 | int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); | ||
93 | int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu); | ||
94 | int kvm_create_lapic(struct kvm_vcpu *vcpu); | ||
95 | void kvm_free_apic(struct kvm_lapic *apic); | ||
96 | u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); | ||
97 | void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); | ||
98 | void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); | ||
99 | u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); | ||
100 | void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); | ||
101 | void kvm_ioapic_update_eoi(struct kvm *kvm, int vector); | ||
102 | |||
64 | #endif | 103 | #endif |
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index e0a2f13faf8b..a5790cb21ffc 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -324,6 +324,7 @@ struct kvm_vcpu { | |||
324 | u64 pdptrs[4]; /* pae */ | 324 | u64 pdptrs[4]; /* pae */ |
325 | u64 shadow_efer; | 325 | u64 shadow_efer; |
326 | u64 apic_base; | 326 | u64 apic_base; |
327 | struct kvm_lapic *apic; /* kernel irqchip context */ | ||
327 | u64 ia32_misc_enable_msr; | 328 | u64 ia32_misc_enable_msr; |
328 | 329 | ||
329 | struct kvm_mmu mmu; | 330 | struct kvm_mmu mmu; |
@@ -569,8 +570,6 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0); | |||
569 | void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0); | 570 | void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0); |
570 | void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0); | 571 | void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0); |
571 | unsigned long get_cr8(struct kvm_vcpu *vcpu); | 572 | unsigned long get_cr8(struct kvm_vcpu *vcpu); |
572 | u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); | ||
573 | void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); | ||
574 | void lmsw(struct kvm_vcpu *vcpu, unsigned long msw); | 573 | void lmsw(struct kvm_vcpu *vcpu, unsigned long msw); |
575 | 574 | ||
576 | int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); | 575 | int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); |
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index f879efbefcdf..401e3cdc4607 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -281,6 +281,7 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_init); | |||
281 | void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) | 281 | void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) |
282 | { | 282 | { |
283 | kvm_mmu_destroy(vcpu); | 283 | kvm_mmu_destroy(vcpu); |
284 | kvm_free_apic(vcpu->apic); | ||
284 | free_page((unsigned long)vcpu->pio_data); | 285 | free_page((unsigned long)vcpu->pio_data); |
285 | free_page((unsigned long)vcpu->run); | 286 | free_page((unsigned long)vcpu->run); |
286 | } | 287 | } |
@@ -598,25 +599,38 @@ void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) | |||
598 | inject_gp(vcpu); | 599 | inject_gp(vcpu); |
599 | return; | 600 | return; |
600 | } | 601 | } |
601 | vcpu->cr8 = cr8; | 602 | if (irqchip_in_kernel(vcpu->kvm)) |
603 | kvm_lapic_set_tpr(vcpu, cr8); | ||
604 | else | ||
605 | vcpu->cr8 = cr8; | ||
602 | } | 606 | } |
603 | EXPORT_SYMBOL_GPL(set_cr8); | 607 | EXPORT_SYMBOL_GPL(set_cr8); |
604 | 608 | ||
605 | unsigned long get_cr8(struct kvm_vcpu *vcpu) | 609 | unsigned long get_cr8(struct kvm_vcpu *vcpu) |
606 | { | 610 | { |
607 | return vcpu->cr8; | 611 | if (irqchip_in_kernel(vcpu->kvm)) |
612 | return kvm_lapic_get_cr8(vcpu); | ||
613 | else | ||
614 | return vcpu->cr8; | ||
608 | } | 615 | } |
609 | EXPORT_SYMBOL_GPL(get_cr8); | 616 | EXPORT_SYMBOL_GPL(get_cr8); |
610 | 617 | ||
611 | u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) | 618 | u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) |
612 | { | 619 | { |
613 | return vcpu->apic_base; | 620 | if (irqchip_in_kernel(vcpu->kvm)) |
621 | return vcpu->apic_base; | ||
622 | else | ||
623 | return vcpu->apic_base; | ||
614 | } | 624 | } |
615 | EXPORT_SYMBOL_GPL(kvm_get_apic_base); | 625 | EXPORT_SYMBOL_GPL(kvm_get_apic_base); |
616 | 626 | ||
617 | void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) | 627 | void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) |
618 | { | 628 | { |
619 | vcpu->apic_base = data; | 629 | /* TODO: reserve bits check */ |
630 | if (irqchip_in_kernel(vcpu->kvm)) | ||
631 | kvm_lapic_set_base(vcpu, data); | ||
632 | else | ||
633 | vcpu->apic_base = data; | ||
620 | } | 634 | } |
621 | EXPORT_SYMBOL_GPL(kvm_set_apic_base); | 635 | EXPORT_SYMBOL_GPL(kvm_set_apic_base); |
622 | 636 | ||
@@ -986,15 +1000,31 @@ static int emulator_write_std(unsigned long addr, | |||
986 | return X86EMUL_UNHANDLEABLE; | 1000 | return X86EMUL_UNHANDLEABLE; |
987 | } | 1001 | } |
988 | 1002 | ||
1003 | /* | ||
1004 | * Only apic need an MMIO device hook, so shortcut now.. | ||
1005 | */ | ||
1006 | static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, | ||
1007 | gpa_t addr) | ||
1008 | { | ||
1009 | struct kvm_io_device *dev; | ||
1010 | |||
1011 | if (vcpu->apic) { | ||
1012 | dev = &vcpu->apic->dev; | ||
1013 | if (dev->in_range(dev, addr)) | ||
1014 | return dev; | ||
1015 | } | ||
1016 | return NULL; | ||
1017 | } | ||
1018 | |||
989 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, | 1019 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, |
990 | gpa_t addr) | 1020 | gpa_t addr) |
991 | { | 1021 | { |
992 | /* | 1022 | struct kvm_io_device *dev; |
993 | * Note that its important to have this wrapper function because | 1023 | |
994 | * in the very near future we will be checking for MMIOs against | 1024 | dev = vcpu_find_pervcpu_dev(vcpu, addr); |
995 | * the LAPIC as well as the general MMIO bus | 1025 | if (dev == NULL) |
996 | */ | 1026 | dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); |
997 | return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); | 1027 | return dev; |
998 | } | 1028 | } |
999 | 1029 | ||
1000 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, | 1030 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, |
@@ -2256,6 +2286,8 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, | |||
2256 | { | 2286 | { |
2257 | if (irq->irq < 0 || irq->irq >= 256) | 2287 | if (irq->irq < 0 || irq->irq >= 256) |
2258 | return -EINVAL; | 2288 | return -EINVAL; |
2289 | if (irqchip_in_kernel(vcpu->kvm)) | ||
2290 | return -ENXIO; | ||
2259 | vcpu_load(vcpu); | 2291 | vcpu_load(vcpu); |
2260 | 2292 | ||
2261 | set_bit(irq->irq, vcpu->irq_pending); | 2293 | set_bit(irq->irq, vcpu->irq_pending); |
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c new file mode 100644 index 000000000000..4b5c77d8900d --- /dev/null +++ b/drivers/kvm/lapic.c | |||
@@ -0,0 +1,933 @@ | |||
1 | |||
2 | /* | ||
3 | * Local APIC virtualization | ||
4 | * | ||
5 | * Copyright (C) 2006 Qumranet, Inc. | ||
6 | * Copyright (C) 2007 Novell | ||
7 | * Copyright (C) 2007 Intel | ||
8 | * | ||
9 | * Authors: | ||
10 | * Dor Laor <dor.laor@qumranet.com> | ||
11 | * Gregory Haskins <ghaskins@novell.com> | ||
12 | * Yaozu (Eddie) Dong <eddie.dong@intel.com> | ||
13 | * | ||
14 | * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation. | ||
15 | * | ||
16 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
17 | * the COPYING file in the top-level directory. | ||
18 | */ | ||
19 | |||
20 | #include "kvm.h" | ||
21 | #include <linux/kvm.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/highmem.h> | ||
24 | #include <linux/smp.h> | ||
25 | #include <linux/hrtimer.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <asm/processor.h> | ||
29 | #include <asm/msr.h> | ||
30 | #include <asm/page.h> | ||
31 | #include <asm/current.h> | ||
32 | #include <asm/apicdef.h> | ||
33 | #include <asm/atomic.h> | ||
34 | #include <asm/div64.h> | ||
35 | #include "irq.h" | ||
36 | |||
37 | #define PRId64 "d" | ||
38 | #define PRIx64 "llx" | ||
39 | #define PRIu64 "u" | ||
40 | #define PRIo64 "o" | ||
41 | |||
42 | #define APIC_BUS_CYCLE_NS 1 | ||
43 | |||
44 | /* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ | ||
45 | #define apic_debug(fmt, arg...) | ||
46 | |||
47 | #define APIC_LVT_NUM 6 | ||
48 | /* 14 is the version for Xeon and Pentium 8.4.8*/ | ||
49 | #define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16)) | ||
50 | #define LAPIC_MMIO_LENGTH (1 << 12) | ||
51 | /* followed define is not in apicdef.h */ | ||
52 | #define APIC_SHORT_MASK 0xc0000 | ||
53 | #define APIC_DEST_NOSHORT 0x0 | ||
54 | #define APIC_DEST_MASK 0x800 | ||
55 | #define MAX_APIC_VECTOR 256 | ||
56 | |||
57 | #define VEC_POS(v) ((v) & (32 - 1)) | ||
58 | #define REG_POS(v) (((v) >> 5) << 4) | ||
59 | static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off) | ||
60 | { | ||
61 | return *((u32 *) (apic->regs + reg_off)); | ||
62 | } | ||
63 | |||
64 | static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) | ||
65 | { | ||
66 | *((u32 *) (apic->regs + reg_off)) = val; | ||
67 | } | ||
68 | |||
69 | static inline int apic_test_and_set_vector(int vec, void *bitmap) | ||
70 | { | ||
71 | return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); | ||
72 | } | ||
73 | |||
74 | static inline int apic_test_and_clear_vector(int vec, void *bitmap) | ||
75 | { | ||
76 | return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); | ||
77 | } | ||
78 | |||
79 | static inline void apic_set_vector(int vec, void *bitmap) | ||
80 | { | ||
81 | set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); | ||
82 | } | ||
83 | |||
84 | static inline void apic_clear_vector(int vec, void *bitmap) | ||
85 | { | ||
86 | clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); | ||
87 | } | ||
88 | |||
89 | static inline int apic_hw_enabled(struct kvm_lapic *apic) | ||
90 | { | ||
91 | return (apic)->vcpu->apic_base & MSR_IA32_APICBASE_ENABLE; | ||
92 | } | ||
93 | |||
94 | static inline int apic_sw_enabled(struct kvm_lapic *apic) | ||
95 | { | ||
96 | return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; | ||
97 | } | ||
98 | |||
99 | static inline int apic_enabled(struct kvm_lapic *apic) | ||
100 | { | ||
101 | return apic_sw_enabled(apic) && apic_hw_enabled(apic); | ||
102 | } | ||
103 | |||
104 | #define LVT_MASK \ | ||
105 | (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK) | ||
106 | |||
107 | #define LINT_MASK \ | ||
108 | (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \ | ||
109 | APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER) | ||
110 | |||
111 | static inline int kvm_apic_id(struct kvm_lapic *apic) | ||
112 | { | ||
113 | return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff; | ||
114 | } | ||
115 | |||
116 | static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type) | ||
117 | { | ||
118 | return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); | ||
119 | } | ||
120 | |||
121 | static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type) | ||
122 | { | ||
123 | return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; | ||
124 | } | ||
125 | |||
126 | static inline int apic_lvtt_period(struct kvm_lapic *apic) | ||
127 | { | ||
128 | return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC; | ||
129 | } | ||
130 | |||
131 | static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { | ||
132 | LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */ | ||
133 | LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ | ||
134 | LVT_MASK | APIC_MODE_MASK, /* LVTPC */ | ||
135 | LINT_MASK, LINT_MASK, /* LVT0-1 */ | ||
136 | LVT_MASK /* LVTERR */ | ||
137 | }; | ||
138 | |||
139 | static int find_highest_vector(void *bitmap) | ||
140 | { | ||
141 | u32 *word = bitmap; | ||
142 | int word_offset = MAX_APIC_VECTOR >> 5; | ||
143 | |||
144 | while ((word_offset != 0) && (word[(--word_offset) << 2] == 0)) | ||
145 | continue; | ||
146 | |||
147 | if (likely(!word_offset && !word[0])) | ||
148 | return -1; | ||
149 | else | ||
150 | return fls(word[word_offset << 2]) - 1 + (word_offset << 5); | ||
151 | } | ||
152 | |||
153 | static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) | ||
154 | { | ||
155 | return apic_test_and_set_vector(vec, apic->regs + APIC_IRR); | ||
156 | } | ||
157 | |||
158 | static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) | ||
159 | { | ||
160 | apic_clear_vector(vec, apic->regs + APIC_IRR); | ||
161 | } | ||
162 | |||
163 | static inline int apic_find_highest_irr(struct kvm_lapic *apic) | ||
164 | { | ||
165 | int result; | ||
166 | |||
167 | result = find_highest_vector(apic->regs + APIC_IRR); | ||
168 | ASSERT(result == -1 || result >= 16); | ||
169 | |||
170 | return result; | ||
171 | } | ||
172 | |||
173 | int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig) | ||
174 | { | ||
175 | if (!apic_test_and_set_irr(vec, apic)) { | ||
176 | /* a new pending irq is set in IRR */ | ||
177 | if (trig) | ||
178 | apic_set_vector(vec, apic->regs + APIC_TMR); | ||
179 | else | ||
180 | apic_clear_vector(vec, apic->regs + APIC_TMR); | ||
181 | kvm_vcpu_kick(apic->vcpu); | ||
182 | return 1; | ||
183 | } | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static inline int apic_find_highest_isr(struct kvm_lapic *apic) | ||
188 | { | ||
189 | int result; | ||
190 | |||
191 | result = find_highest_vector(apic->regs + APIC_ISR); | ||
192 | ASSERT(result == -1 || result >= 16); | ||
193 | |||
194 | return result; | ||
195 | } | ||
196 | |||
197 | static void apic_update_ppr(struct kvm_lapic *apic) | ||
198 | { | ||
199 | u32 tpr, isrv, ppr; | ||
200 | int isr; | ||
201 | |||
202 | tpr = apic_get_reg(apic, APIC_TASKPRI); | ||
203 | isr = apic_find_highest_isr(apic); | ||
204 | isrv = (isr != -1) ? isr : 0; | ||
205 | |||
206 | if ((tpr & 0xf0) >= (isrv & 0xf0)) | ||
207 | ppr = tpr & 0xff; | ||
208 | else | ||
209 | ppr = isrv & 0xf0; | ||
210 | |||
211 | apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x", | ||
212 | apic, ppr, isr, isrv); | ||
213 | |||
214 | apic_set_reg(apic, APIC_PROCPRI, ppr); | ||
215 | } | ||
216 | |||
217 | static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) | ||
218 | { | ||
219 | apic_set_reg(apic, APIC_TASKPRI, tpr); | ||
220 | apic_update_ppr(apic); | ||
221 | } | ||
222 | |||
223 | int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) | ||
224 | { | ||
225 | return kvm_apic_id(apic) == dest; | ||
226 | } | ||
227 | |||
228 | int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) | ||
229 | { | ||
230 | int result = 0; | ||
231 | u8 logical_id; | ||
232 | |||
233 | logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR)); | ||
234 | |||
235 | switch (apic_get_reg(apic, APIC_DFR)) { | ||
236 | case APIC_DFR_FLAT: | ||
237 | if (logical_id & mda) | ||
238 | result = 1; | ||
239 | break; | ||
240 | case APIC_DFR_CLUSTER: | ||
241 | if (((logical_id >> 4) == (mda >> 0x4)) | ||
242 | && (logical_id & mda & 0xf)) | ||
243 | result = 1; | ||
244 | break; | ||
245 | default: | ||
246 | printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n", | ||
247 | apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR)); | ||
248 | break; | ||
249 | } | ||
250 | |||
251 | return result; | ||
252 | } | ||
253 | |||
254 | static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, | ||
255 | int short_hand, int dest, int dest_mode) | ||
256 | { | ||
257 | int result = 0; | ||
258 | struct kvm_lapic *target = vcpu->apic; | ||
259 | |||
260 | apic_debug("target %p, source %p, dest 0x%x, " | ||
261 | "dest_mode 0x%x, short_hand 0x%x", | ||
262 | target, source, dest, dest_mode, short_hand); | ||
263 | |||
264 | ASSERT(!target); | ||
265 | switch (short_hand) { | ||
266 | case APIC_DEST_NOSHORT: | ||
267 | if (dest_mode == 0) { | ||
268 | /* Physical mode. */ | ||
269 | if ((dest == 0xFF) || (dest == kvm_apic_id(target))) | ||
270 | result = 1; | ||
271 | } else | ||
272 | /* Logical mode. */ | ||
273 | result = kvm_apic_match_logical_addr(target, dest); | ||
274 | break; | ||
275 | case APIC_DEST_SELF: | ||
276 | if (target == source) | ||
277 | result = 1; | ||
278 | break; | ||
279 | case APIC_DEST_ALLINC: | ||
280 | result = 1; | ||
281 | break; | ||
282 | case APIC_DEST_ALLBUT: | ||
283 | if (target != source) | ||
284 | result = 1; | ||
285 | break; | ||
286 | default: | ||
287 | printk(KERN_WARNING "Bad dest shorthand value %x\n", | ||
288 | short_hand); | ||
289 | break; | ||
290 | } | ||
291 | |||
292 | return result; | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Add a pending IRQ into lapic. | ||
297 | * Return 1 if successfully added and 0 if discarded. | ||
298 | */ | ||
299 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | ||
300 | int vector, int level, int trig_mode) | ||
301 | { | ||
302 | int result = 0; | ||
303 | |||
304 | switch (delivery_mode) { | ||
305 | case APIC_DM_FIXED: | ||
306 | case APIC_DM_LOWEST: | ||
307 | /* FIXME add logic for vcpu on reset */ | ||
308 | if (unlikely(!apic_enabled(apic))) | ||
309 | break; | ||
310 | |||
311 | if (apic_test_and_set_irr(vector, apic) && trig_mode) { | ||
312 | apic_debug("level trig mode repeatedly for vector %d", | ||
313 | vector); | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | if (trig_mode) { | ||
318 | apic_debug("level trig mode for vector %d", vector); | ||
319 | apic_set_vector(vector, apic->regs + APIC_TMR); | ||
320 | } else | ||
321 | apic_clear_vector(vector, apic->regs + APIC_TMR); | ||
322 | |||
323 | kvm_vcpu_kick(apic->vcpu); | ||
324 | |||
325 | result = 1; | ||
326 | break; | ||
327 | |||
328 | case APIC_DM_REMRD: | ||
329 | printk(KERN_DEBUG "Ignoring delivery mode 3\n"); | ||
330 | break; | ||
331 | |||
332 | case APIC_DM_SMI: | ||
333 | printk(KERN_DEBUG "Ignoring guest SMI\n"); | ||
334 | break; | ||
335 | case APIC_DM_NMI: | ||
336 | printk(KERN_DEBUG "Ignoring guest NMI\n"); | ||
337 | break; | ||
338 | |||
339 | case APIC_DM_INIT: | ||
340 | printk(KERN_DEBUG "Ignoring guest INIT\n"); | ||
341 | break; | ||
342 | |||
343 | case APIC_DM_STARTUP: | ||
344 | printk(KERN_DEBUG "Ignoring guest STARTUP\n"); | ||
345 | break; | ||
346 | |||
347 | default: | ||
348 | printk(KERN_ERR "TODO: unsupported delivery mode %x\n", | ||
349 | delivery_mode); | ||
350 | break; | ||
351 | } | ||
352 | return result; | ||
353 | } | ||
354 | |||
355 | struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector, | ||
356 | unsigned long bitmap) | ||
357 | { | ||
358 | int vcpu_id; | ||
359 | |||
360 | /* TODO for real round robin */ | ||
361 | vcpu_id = fls(bitmap) - 1; | ||
362 | if (vcpu_id < 0) | ||
363 | printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n"); | ||
364 | return kvm->vcpus[vcpu_id]->apic; | ||
365 | } | ||
366 | |||
367 | static void apic_set_eoi(struct kvm_lapic *apic) | ||
368 | { | ||
369 | int vector = apic_find_highest_isr(apic); | ||
370 | |||
371 | /* | ||
372 | * Not every write EOI will has corresponding ISR, | ||
373 | * one example is when Kernel check timer on setup_IO_APIC | ||
374 | */ | ||
375 | if (vector == -1) | ||
376 | return; | ||
377 | |||
378 | apic_clear_vector(vector, apic->regs + APIC_ISR); | ||
379 | apic_update_ppr(apic); | ||
380 | |||
381 | if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR)) | ||
382 | kvm_ioapic_update_eoi(apic->vcpu->kvm, vector); | ||
383 | } | ||
384 | |||
385 | static void apic_send_ipi(struct kvm_lapic *apic) | ||
386 | { | ||
387 | u32 icr_low = apic_get_reg(apic, APIC_ICR); | ||
388 | u32 icr_high = apic_get_reg(apic, APIC_ICR2); | ||
389 | |||
390 | unsigned int dest = GET_APIC_DEST_FIELD(icr_high); | ||
391 | unsigned int short_hand = icr_low & APIC_SHORT_MASK; | ||
392 | unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG; | ||
393 | unsigned int level = icr_low & APIC_INT_ASSERT; | ||
394 | unsigned int dest_mode = icr_low & APIC_DEST_MASK; | ||
395 | unsigned int delivery_mode = icr_low & APIC_MODE_MASK; | ||
396 | unsigned int vector = icr_low & APIC_VECTOR_MASK; | ||
397 | |||
398 | struct kvm_lapic *target; | ||
399 | struct kvm_vcpu *vcpu; | ||
400 | unsigned long lpr_map = 0; | ||
401 | int i; | ||
402 | |||
403 | apic_debug("icr_high 0x%x, icr_low 0x%x, " | ||
404 | "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " | ||
405 | "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", | ||
406 | icr_high, icr_low, short_hand, dest, | ||
407 | trig_mode, level, dest_mode, delivery_mode, vector); | ||
408 | |||
409 | for (i = 0; i < KVM_MAX_VCPUS; i++) { | ||
410 | vcpu = apic->vcpu->kvm->vcpus[i]; | ||
411 | if (!vcpu) | ||
412 | continue; | ||
413 | |||
414 | if (vcpu->apic && | ||
415 | apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) { | ||
416 | if (delivery_mode == APIC_DM_LOWEST) | ||
417 | set_bit(vcpu->vcpu_id, &lpr_map); | ||
418 | else | ||
419 | __apic_accept_irq(vcpu->apic, delivery_mode, | ||
420 | vector, level, trig_mode); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | if (delivery_mode == APIC_DM_LOWEST) { | ||
425 | target = kvm_apic_round_robin(vcpu->kvm, vector, lpr_map); | ||
426 | if (target != NULL) | ||
427 | __apic_accept_irq(target, delivery_mode, | ||
428 | vector, level, trig_mode); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static u32 apic_get_tmcct(struct kvm_lapic *apic) | ||
433 | { | ||
434 | u32 counter_passed; | ||
435 | ktime_t passed, now = apic->timer.dev.base->get_time(); | ||
436 | u32 tmcct = apic_get_reg(apic, APIC_TMICT); | ||
437 | |||
438 | ASSERT(apic != NULL); | ||
439 | |||
440 | if (unlikely(ktime_to_ns(now) <= | ||
441 | ktime_to_ns(apic->timer.last_update))) { | ||
442 | /* Wrap around */ | ||
443 | passed = ktime_add(( { | ||
444 | (ktime_t) { | ||
445 | .tv64 = KTIME_MAX - | ||
446 | (apic->timer.last_update).tv64}; } | ||
447 | ), now); | ||
448 | apic_debug("time elapsed\n"); | ||
449 | } else | ||
450 | passed = ktime_sub(now, apic->timer.last_update); | ||
451 | |||
452 | counter_passed = div64_64(ktime_to_ns(passed), | ||
453 | (APIC_BUS_CYCLE_NS * apic->timer.divide_count)); | ||
454 | tmcct -= counter_passed; | ||
455 | |||
456 | if (tmcct <= 0) { | ||
457 | if (unlikely(!apic_lvtt_period(apic))) | ||
458 | tmcct = 0; | ||
459 | else | ||
460 | do { | ||
461 | tmcct += apic_get_reg(apic, APIC_TMICT); | ||
462 | } while (tmcct <= 0); | ||
463 | } | ||
464 | |||
465 | return tmcct; | ||
466 | } | ||
467 | |||
468 | static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) | ||
469 | { | ||
470 | u32 val = 0; | ||
471 | |||
472 | if (offset >= LAPIC_MMIO_LENGTH) | ||
473 | return 0; | ||
474 | |||
475 | switch (offset) { | ||
476 | case APIC_ARBPRI: | ||
477 | printk(KERN_WARNING "Access APIC ARBPRI register " | ||
478 | "which is for P6\n"); | ||
479 | break; | ||
480 | |||
481 | case APIC_TMCCT: /* Timer CCR */ | ||
482 | val = apic_get_tmcct(apic); | ||
483 | break; | ||
484 | |||
485 | default: | ||
486 | val = apic_get_reg(apic, offset); | ||
487 | break; | ||
488 | } | ||
489 | |||
490 | return val; | ||
491 | } | ||
492 | |||
493 | static void apic_mmio_read(struct kvm_io_device *this, | ||
494 | gpa_t address, int len, void *data) | ||
495 | { | ||
496 | struct kvm_lapic *apic = (struct kvm_lapic *)this->private; | ||
497 | unsigned int offset = address - apic->base_address; | ||
498 | unsigned char alignment = offset & 0xf; | ||
499 | u32 result; | ||
500 | |||
501 | if ((alignment + len) > 4) { | ||
502 | printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d", | ||
503 | (unsigned long)address, len); | ||
504 | return; | ||
505 | } | ||
506 | result = __apic_read(apic, offset & ~0xf); | ||
507 | |||
508 | switch (len) { | ||
509 | case 1: | ||
510 | case 2: | ||
511 | case 4: | ||
512 | memcpy(data, (char *)&result + alignment, len); | ||
513 | break; | ||
514 | default: | ||
515 | printk(KERN_ERR "Local APIC read with len = %x, " | ||
516 | "should be 1,2, or 4 instead\n", len); | ||
517 | break; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | static void update_divide_count(struct kvm_lapic *apic) | ||
522 | { | ||
523 | u32 tmp1, tmp2, tdcr; | ||
524 | |||
525 | tdcr = apic_get_reg(apic, APIC_TDCR); | ||
526 | tmp1 = tdcr & 0xf; | ||
527 | tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; | ||
528 | apic->timer.divide_count = 0x1 << (tmp2 & 0x7); | ||
529 | |||
530 | apic_debug("timer divide count is 0x%x\n", | ||
531 | apic->timer.divide_count); | ||
532 | } | ||
533 | |||
534 | static void start_apic_timer(struct kvm_lapic *apic) | ||
535 | { | ||
536 | ktime_t now = apic->timer.dev.base->get_time(); | ||
537 | |||
538 | apic->timer.last_update = now; | ||
539 | |||
540 | apic->timer.period = apic_get_reg(apic, APIC_TMICT) * | ||
541 | APIC_BUS_CYCLE_NS * apic->timer.divide_count; | ||
542 | atomic_set(&apic->timer.pending, 0); | ||
543 | hrtimer_start(&apic->timer.dev, | ||
544 | ktime_add_ns(now, apic->timer.period), | ||
545 | HRTIMER_MODE_ABS); | ||
546 | |||
547 | apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" | ||
548 | PRIx64 ", " | ||
549 | "timer initial count 0x%x, period %lldns, " | ||
550 | "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__, | ||
551 | APIC_BUS_CYCLE_NS, ktime_to_ns(now), | ||
552 | apic_get_reg(apic, APIC_TMICT), | ||
553 | apic->timer.period, | ||
554 | ktime_to_ns(ktime_add_ns(now, | ||
555 | apic->timer.period))); | ||
556 | } | ||
557 | |||
558 | static void apic_mmio_write(struct kvm_io_device *this, | ||
559 | gpa_t address, int len, const void *data) | ||
560 | { | ||
561 | struct kvm_lapic *apic = (struct kvm_lapic *)this->private; | ||
562 | unsigned int offset = address - apic->base_address; | ||
563 | unsigned char alignment = offset & 0xf; | ||
564 | u32 val; | ||
565 | |||
566 | /* | ||
567 | * APIC register must be aligned on 128-bits boundary. | ||
568 | * 32/64/128 bits registers must be accessed thru 32 bits. | ||
569 | * Refer SDM 8.4.1 | ||
570 | */ | ||
571 | if (len != 4 || alignment) { | ||
572 | if (printk_ratelimit()) | ||
573 | printk(KERN_ERR "apic write: bad size=%d %lx\n", | ||
574 | len, (long)address); | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | val = *(u32 *) data; | ||
579 | |||
580 | /* too common printing */ | ||
581 | if (offset != APIC_EOI) | ||
582 | apic_debug("%s: offset 0x%x with length 0x%x, and value is " | ||
583 | "0x%x\n", __FUNCTION__, offset, len, val); | ||
584 | |||
585 | offset &= 0xff0; | ||
586 | |||
587 | switch (offset) { | ||
588 | case APIC_ID: /* Local APIC ID */ | ||
589 | apic_set_reg(apic, APIC_ID, val); | ||
590 | break; | ||
591 | |||
592 | case APIC_TASKPRI: | ||
593 | apic_set_tpr(apic, val & 0xff); | ||
594 | break; | ||
595 | |||
596 | case APIC_EOI: | ||
597 | apic_set_eoi(apic); | ||
598 | break; | ||
599 | |||
600 | case APIC_LDR: | ||
601 | apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK); | ||
602 | break; | ||
603 | |||
604 | case APIC_DFR: | ||
605 | apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); | ||
606 | break; | ||
607 | |||
608 | case APIC_SPIV: | ||
609 | apic_set_reg(apic, APIC_SPIV, val & 0x3ff); | ||
610 | if (!(val & APIC_SPIV_APIC_ENABLED)) { | ||
611 | int i; | ||
612 | u32 lvt_val; | ||
613 | |||
614 | for (i = 0; i < APIC_LVT_NUM; i++) { | ||
615 | lvt_val = apic_get_reg(apic, | ||
616 | APIC_LVTT + 0x10 * i); | ||
617 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, | ||
618 | lvt_val | APIC_LVT_MASKED); | ||
619 | } | ||
620 | atomic_set(&apic->timer.pending, 0); | ||
621 | |||
622 | } | ||
623 | break; | ||
624 | |||
625 | case APIC_ICR: | ||
626 | /* No delay here, so we always clear the pending bit */ | ||
627 | apic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); | ||
628 | apic_send_ipi(apic); | ||
629 | break; | ||
630 | |||
631 | case APIC_ICR2: | ||
632 | apic_set_reg(apic, APIC_ICR2, val & 0xff000000); | ||
633 | break; | ||
634 | |||
635 | case APIC_LVTT: | ||
636 | case APIC_LVTTHMR: | ||
637 | case APIC_LVTPC: | ||
638 | case APIC_LVT0: | ||
639 | case APIC_LVT1: | ||
640 | case APIC_LVTERR: | ||
641 | /* TODO: Check vector */ | ||
642 | if (!apic_sw_enabled(apic)) | ||
643 | val |= APIC_LVT_MASKED; | ||
644 | |||
645 | val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4]; | ||
646 | apic_set_reg(apic, offset, val); | ||
647 | |||
648 | break; | ||
649 | |||
650 | case APIC_TMICT: | ||
651 | hrtimer_cancel(&apic->timer.dev); | ||
652 | apic_set_reg(apic, APIC_TMICT, val); | ||
653 | start_apic_timer(apic); | ||
654 | return; | ||
655 | |||
656 | case APIC_TDCR: | ||
657 | if (val & 4) | ||
658 | printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val); | ||
659 | apic_set_reg(apic, APIC_TDCR, val); | ||
660 | update_divide_count(apic); | ||
661 | break; | ||
662 | |||
663 | default: | ||
664 | apic_debug("Local APIC Write to read-only register %x\n", | ||
665 | offset); | ||
666 | break; | ||
667 | } | ||
668 | |||
669 | } | ||
670 | |||
671 | static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr) | ||
672 | { | ||
673 | struct kvm_lapic *apic = (struct kvm_lapic *)this->private; | ||
674 | int ret = 0; | ||
675 | |||
676 | |||
677 | if (apic_hw_enabled(apic) && | ||
678 | (addr >= apic->base_address) && | ||
679 | (addr < (apic->base_address + LAPIC_MMIO_LENGTH))) | ||
680 | ret = 1; | ||
681 | |||
682 | return ret; | ||
683 | } | ||
684 | |||
685 | void kvm_free_apic(struct kvm_lapic *apic) | ||
686 | { | ||
687 | if (!apic) | ||
688 | return; | ||
689 | |||
690 | hrtimer_cancel(&apic->timer.dev); | ||
691 | |||
692 | if (apic->regs_page) { | ||
693 | __free_page(apic->regs_page); | ||
694 | apic->regs_page = 0; | ||
695 | } | ||
696 | |||
697 | kfree(apic); | ||
698 | } | ||
699 | |||
700 | /* | ||
701 | *---------------------------------------------------------------------- | ||
702 | * LAPIC interface | ||
703 | *---------------------------------------------------------------------- | ||
704 | */ | ||
705 | |||
706 | void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) | ||
707 | { | ||
708 | struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; | ||
709 | |||
710 | if (!apic) | ||
711 | return; | ||
712 | apic_set_tpr(apic, ((cr8 & 0x0f) << 4)); | ||
713 | } | ||
714 | |||
715 | u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) | ||
716 | { | ||
717 | struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; | ||
718 | u64 tpr; | ||
719 | |||
720 | if (!apic) | ||
721 | return 0; | ||
722 | tpr = (u64) apic_get_reg(apic, APIC_TASKPRI); | ||
723 | |||
724 | return (tpr & 0xf0) >> 4; | ||
725 | } | ||
726 | |||
727 | void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) | ||
728 | { | ||
729 | struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; | ||
730 | |||
731 | if (!apic) { | ||
732 | value |= MSR_IA32_APICBASE_BSP; | ||
733 | vcpu->apic_base = value; | ||
734 | return; | ||
735 | } | ||
736 | if (apic->vcpu->vcpu_id) | ||
737 | value &= ~MSR_IA32_APICBASE_BSP; | ||
738 | |||
739 | vcpu->apic_base = value; | ||
740 | apic->base_address = apic->vcpu->apic_base & | ||
741 | MSR_IA32_APICBASE_BASE; | ||
742 | |||
743 | /* with FSB delivery interrupt, we can restart APIC functionality */ | ||
744 | apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is " | ||
745 | "0x%lx.\n", apic->apic_base, apic->base_address); | ||
746 | |||
747 | } | ||
748 | |||
749 | u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu) | ||
750 | { | ||
751 | return vcpu->apic_base; | ||
752 | } | ||
753 | EXPORT_SYMBOL_GPL(kvm_lapic_get_base); | ||
754 | |||
755 | static void lapic_reset(struct kvm_vcpu *vcpu) | ||
756 | { | ||
757 | struct kvm_lapic *apic; | ||
758 | int i; | ||
759 | |||
760 | apic_debug("%s\n", __FUNCTION__); | ||
761 | |||
762 | ASSERT(vcpu); | ||
763 | apic = vcpu->apic; | ||
764 | ASSERT(apic != NULL); | ||
765 | |||
766 | /* Stop the timer in case it's a reset to an active apic */ | ||
767 | hrtimer_cancel(&apic->timer.dev); | ||
768 | |||
769 | apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); | ||
770 | apic_set_reg(apic, APIC_LVR, APIC_VERSION); | ||
771 | |||
772 | for (i = 0; i < APIC_LVT_NUM; i++) | ||
773 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); | ||
774 | |||
775 | apic_set_reg(apic, APIC_DFR, 0xffffffffU); | ||
776 | apic_set_reg(apic, APIC_SPIV, 0xff); | ||
777 | apic_set_reg(apic, APIC_TASKPRI, 0); | ||
778 | apic_set_reg(apic, APIC_LDR, 0); | ||
779 | apic_set_reg(apic, APIC_ESR, 0); | ||
780 | apic_set_reg(apic, APIC_ICR, 0); | ||
781 | apic_set_reg(apic, APIC_ICR2, 0); | ||
782 | apic_set_reg(apic, APIC_TDCR, 0); | ||
783 | apic_set_reg(apic, APIC_TMICT, 0); | ||
784 | for (i = 0; i < 8; i++) { | ||
785 | apic_set_reg(apic, APIC_IRR + 0x10 * i, 0); | ||
786 | apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); | ||
787 | apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); | ||
788 | } | ||
789 | apic->timer.divide_count = 0; | ||
790 | atomic_set(&apic->timer.pending, 0); | ||
791 | if (vcpu->vcpu_id == 0) | ||
792 | vcpu->apic_base |= MSR_IA32_APICBASE_BSP; | ||
793 | apic_update_ppr(apic); | ||
794 | |||
795 | apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr=" | ||
796 | "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__, | ||
797 | vcpu, kvm_apic_id(apic), | ||
798 | vcpu->apic_base, apic->base_address); | ||
799 | } | ||
800 | |||
801 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu) | ||
802 | { | ||
803 | struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; | ||
804 | int ret = 0; | ||
805 | |||
806 | if (!apic) | ||
807 | return 0; | ||
808 | ret = apic_enabled(apic); | ||
809 | |||
810 | return ret; | ||
811 | } | ||
812 | |||
813 | /* | ||
814 | *---------------------------------------------------------------------- | ||
815 | * timer interface | ||
816 | *---------------------------------------------------------------------- | ||
817 | */ | ||
818 | static int __apic_timer_fn(struct kvm_lapic *apic) | ||
819 | { | ||
820 | u32 vector; | ||
821 | int result = 0; | ||
822 | |||
823 | if (unlikely(!apic_enabled(apic) || | ||
824 | !apic_lvt_enabled(apic, APIC_LVTT))) { | ||
825 | apic_debug("%s: time interrupt although apic is down\n", | ||
826 | __FUNCTION__); | ||
827 | return 0; | ||
828 | } | ||
829 | |||
830 | vector = apic_lvt_vector(apic, APIC_LVTT); | ||
831 | apic->timer.last_update = apic->timer.dev.expires; | ||
832 | atomic_inc(&apic->timer.pending); | ||
833 | __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); | ||
834 | |||
835 | if (apic_lvtt_period(apic)) { | ||
836 | u32 offset; | ||
837 | u32 tmict = apic_get_reg(apic, APIC_TMICT); | ||
838 | |||
839 | offset = APIC_BUS_CYCLE_NS * apic->timer.divide_count * tmict; | ||
840 | |||
841 | result = 1; | ||
842 | apic->timer.dev.expires = ktime_add_ns( | ||
843 | apic->timer.dev.expires, | ||
844 | apic->timer.period); | ||
845 | } | ||
846 | |||
847 | return result; | ||
848 | } | ||
849 | |||
850 | static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) | ||
851 | { | ||
852 | struct kvm_lapic *apic; | ||
853 | int restart_timer = 0; | ||
854 | |||
855 | apic = container_of(data, struct kvm_lapic, timer.dev); | ||
856 | |||
857 | restart_timer = __apic_timer_fn(apic); | ||
858 | |||
859 | if (restart_timer) | ||
860 | return HRTIMER_RESTART; | ||
861 | else | ||
862 | return HRTIMER_NORESTART; | ||
863 | } | ||
864 | |||
865 | int kvm_create_lapic(struct kvm_vcpu *vcpu) | ||
866 | { | ||
867 | struct kvm_lapic *apic; | ||
868 | |||
869 | ASSERT(vcpu != NULL); | ||
870 | apic_debug("apic_init %d\n", vcpu->vcpu_id); | ||
871 | |||
872 | apic = kzalloc(sizeof(*apic), GFP_KERNEL); | ||
873 | if (!apic) | ||
874 | goto nomem; | ||
875 | |||
876 | vcpu->apic = apic; | ||
877 | |||
878 | apic->regs_page = alloc_page(GFP_KERNEL); | ||
879 | if (apic->regs_page == NULL) { | ||
880 | printk(KERN_ERR "malloc apic regs error for vcpu %x\n", | ||
881 | vcpu->vcpu_id); | ||
882 | goto nomem; | ||
883 | } | ||
884 | apic->regs = page_address(apic->regs_page); | ||
885 | memset(apic->regs, 0, PAGE_SIZE); | ||
886 | apic->vcpu = vcpu; | ||
887 | |||
888 | hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
889 | apic->timer.dev.function = apic_timer_fn; | ||
890 | apic->base_address = APIC_DEFAULT_PHYS_BASE; | ||
891 | vcpu->apic_base = APIC_DEFAULT_PHYS_BASE; | ||
892 | |||
893 | lapic_reset(vcpu); | ||
894 | apic->dev.read = apic_mmio_read; | ||
895 | apic->dev.write = apic_mmio_write; | ||
896 | apic->dev.in_range = apic_mmio_range; | ||
897 | apic->dev.private = apic; | ||
898 | |||
899 | return 0; | ||
900 | nomem: | ||
901 | kvm_free_apic(apic); | ||
902 | return -ENOMEM; | ||
903 | } | ||
904 | EXPORT_SYMBOL_GPL(kvm_create_lapic); | ||
905 | |||
906 | int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) | ||
907 | { | ||
908 | struct kvm_lapic *apic = vcpu->apic; | ||
909 | int highest_irr; | ||
910 | |||
911 | if (!apic || !apic_enabled(apic)) | ||
912 | return -1; | ||
913 | |||
914 | highest_irr = apic_find_highest_irr(apic); | ||
915 | if ((highest_irr == -1) || | ||
916 | ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI))) | ||
917 | return -1; | ||
918 | return highest_irr; | ||
919 | } | ||
920 | |||
921 | int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) | ||
922 | { | ||
923 | int vector = kvm_apic_has_interrupt(vcpu); | ||
924 | struct kvm_lapic *apic = vcpu->apic; | ||
925 | |||
926 | if (vector == -1) | ||
927 | return -1; | ||
928 | |||
929 | apic_set_vector(vector, apic->regs + APIC_ISR); | ||
930 | apic_update_ppr(apic); | ||
931 | apic_clear_irr(vector, apic); | ||
932 | return vector; | ||
933 | } | ||
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 57525e7ed28f..d576451827e7 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c | |||
@@ -573,6 +573,12 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) | |||
573 | if (err) | 573 | if (err) |
574 | goto free_svm; | 574 | goto free_svm; |
575 | 575 | ||
576 | if (irqchip_in_kernel(kvm)) { | ||
577 | err = kvm_create_lapic(&svm->vcpu); | ||
578 | if (err < 0) | ||
579 | goto free_svm; | ||
580 | } | ||
581 | |||
576 | page = alloc_page(GFP_KERNEL); | 582 | page = alloc_page(GFP_KERNEL); |
577 | if (!page) { | 583 | if (!page) { |
578 | err = -ENOMEM; | 584 | err = -ENOMEM; |
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 19676b5a6719..c4cc17cc00f7 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -2390,6 +2390,12 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) | |||
2390 | if (err) | 2390 | if (err) |
2391 | goto free_vcpu; | 2391 | goto free_vcpu; |
2392 | 2392 | ||
2393 | if (irqchip_in_kernel(kvm)) { | ||
2394 | err = kvm_create_lapic(&vmx->vcpu); | ||
2395 | if (err < 0) | ||
2396 | goto free_vcpu; | ||
2397 | } | ||
2398 | |||
2393 | vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); | 2399 | vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); |
2394 | if (!vmx->guest_msrs) { | 2400 | if (!vmx->guest_msrs) { |
2395 | err = -ENOMEM; | 2401 | err = -ENOMEM; |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index bfe742b771f6..997bb3e46f1e 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -34,7 +34,7 @@ struct kvm_memory_alias { | |||
34 | __u64 target_phys_addr; | 34 | __u64 target_phys_addr; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | /* for KVM_SET_IRQ_LEVEL */ | 37 | /* for KVM_IRQ_LINE */ |
38 | struct kvm_irq_level { | 38 | struct kvm_irq_level { |
39 | /* | 39 | /* |
40 | * ACPI gsi notion of irq. | 40 | * ACPI gsi notion of irq. |
@@ -297,7 +297,7 @@ struct kvm_signal_mask { | |||
297 | #define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias) | 297 | #define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias) |
298 | /* Device model IOC */ | 298 | /* Device model IOC */ |
299 | #define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60) | 299 | #define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60) |
300 | #define KVM_IRQ_LINE _IO(KVMIO, 0x61) | 300 | #define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level) |
301 | 301 | ||
302 | /* | 302 | /* |
303 | * ioctls for vcpu fds | 303 | * ioctls for vcpu fds |