diff options
author | Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> | 2016-05-04 15:09:46 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-05-18 12:04:28 -0400 |
commit | 44a95dae1d229a4967bbfcc56fb2116a9b4fe942 (patch) | |
tree | a4d63ca6d968ca8878b9e6d833c6c0b16f59be39 | |
parent | 3d5615e5342781453633af7107d72afd601b36a7 (diff) |
KVM: x86: Detect and Initialize AVIC support
This patch introduces AVIC-related data structure, and AVIC
initialization code.
There are three main data structures for AVIC:
* Virtual APIC (vAPIC) backing page (per-VCPU)
* Physical APIC ID table (per-VM)
* Logical APIC ID table (per-VM)
Currently, AVIC is disabled by default. Users can manually
enable AVIC via kernel boot option kvm-amd.avic=1 or during
kvm-amd module loading with parameter avic=1.
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
[Avoid extra indentation (Boris). - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/svm.h | 3 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 225 |
3 files changed, 231 insertions, 1 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 2df5db6fb58b..337e13b0d01d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -773,6 +773,10 @@ struct kvm_arch { | |||
773 | u8 nr_reserved_ioapic_pins; | 773 | u8 nr_reserved_ioapic_pins; |
774 | 774 | ||
775 | bool disabled_lapic_found; | 775 | bool disabled_lapic_found; |
776 | |||
777 | /* Struct members for AVIC */ | ||
778 | struct page *avic_logical_id_table_page; | ||
779 | struct page *avic_physical_id_table_page; | ||
776 | }; | 780 | }; |
777 | 781 | ||
778 | struct kvm_vm_stat { | 782 | struct kvm_vm_stat { |
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 4711fa4457f3..d0fe23ec7e98 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h | |||
@@ -116,6 +116,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area { | |||
116 | #define V_INTR_MASKING_SHIFT 24 | 116 | #define V_INTR_MASKING_SHIFT 24 |
117 | #define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) | 117 | #define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) |
118 | 118 | ||
119 | #define AVIC_ENABLE_SHIFT 31 | ||
120 | #define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT) | ||
121 | |||
119 | #define SVM_INTERRUPT_SHADOW_MASK 1 | 122 | #define SVM_INTERRUPT_SHADOW_MASK 1 |
120 | 123 | ||
121 | #define SVM_IOIO_STR_SHIFT 2 | 124 | #define SVM_IOIO_STR_SHIFT 2 |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 31346a3f20a5..192cad25d321 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -14,6 +14,9 @@ | |||
14 | * the COPYING file in the top-level directory. | 14 | * the COPYING file in the top-level directory. |
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | |||
18 | #define pr_fmt(fmt) "SVM: " fmt | ||
19 | |||
17 | #include <linux/kvm_host.h> | 20 | #include <linux/kvm_host.h> |
18 | 21 | ||
19 | #include "irq.h" | 22 | #include "irq.h" |
@@ -78,6 +81,14 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id); | |||
78 | #define TSC_RATIO_MIN 0x0000000000000001ULL | 81 | #define TSC_RATIO_MIN 0x0000000000000001ULL |
79 | #define TSC_RATIO_MAX 0x000000ffffffffffULL | 82 | #define TSC_RATIO_MAX 0x000000ffffffffffULL |
80 | 83 | ||
84 | #define AVIC_HPA_MASK ~((0xFFFULL << 52) || 0xFFF) | ||
85 | |||
86 | /* | ||
87 | * 0xff is broadcast, so the max index allowed for physical APIC ID | ||
88 | * table is 0xfe. APIC IDs above 0xff are reserved. | ||
89 | */ | ||
90 | #define AVIC_MAX_PHYSICAL_ID_COUNT 255 | ||
91 | |||
81 | static bool erratum_383_found __read_mostly; | 92 | static bool erratum_383_found __read_mostly; |
82 | 93 | ||
83 | static const u32 host_save_user_msrs[] = { | 94 | static const u32 host_save_user_msrs[] = { |
@@ -162,8 +173,19 @@ struct vcpu_svm { | |||
162 | 173 | ||
163 | /* cached guest cpuid flags for faster access */ | 174 | /* cached guest cpuid flags for faster access */ |
164 | bool nrips_enabled : 1; | 175 | bool nrips_enabled : 1; |
176 | |||
177 | struct page *avic_backing_page; | ||
178 | u64 *avic_physical_id_cache; | ||
165 | }; | 179 | }; |
166 | 180 | ||
181 | #define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFF) | ||
182 | #define AVIC_LOGICAL_ID_ENTRY_VALID_MASK (1 << 31) | ||
183 | |||
184 | #define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK (0xFFULL) | ||
185 | #define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK (0xFFFFFFFFFFULL << 12) | ||
186 | #define AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK (1ULL << 62) | ||
187 | #define AVIC_PHYSICAL_ID_ENTRY_VALID_MASK (1ULL << 63) | ||
188 | |||
167 | static DEFINE_PER_CPU(u64, current_tsc_ratio); | 189 | static DEFINE_PER_CPU(u64, current_tsc_ratio); |
168 | #define TSC_RATIO_DEFAULT 0x0100000000ULL | 190 | #define TSC_RATIO_DEFAULT 0x0100000000ULL |
169 | 191 | ||
@@ -205,6 +227,10 @@ module_param(npt, int, S_IRUGO); | |||
205 | static int nested = true; | 227 | static int nested = true; |
206 | module_param(nested, int, S_IRUGO); | 228 | module_param(nested, int, S_IRUGO); |
207 | 229 | ||
230 | /* enable / disable AVIC */ | ||
231 | static int avic; | ||
232 | module_param(avic, int, S_IRUGO); | ||
233 | |||
208 | static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); | 234 | static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); |
209 | static void svm_flush_tlb(struct kvm_vcpu *vcpu); | 235 | static void svm_flush_tlb(struct kvm_vcpu *vcpu); |
210 | static void svm_complete_interrupts(struct vcpu_svm *svm); | 236 | static void svm_complete_interrupts(struct vcpu_svm *svm); |
@@ -228,12 +254,18 @@ enum { | |||
228 | VMCB_SEG, /* CS, DS, SS, ES, CPL */ | 254 | VMCB_SEG, /* CS, DS, SS, ES, CPL */ |
229 | VMCB_CR2, /* CR2 only */ | 255 | VMCB_CR2, /* CR2 only */ |
230 | VMCB_LBR, /* DBGCTL, BR_FROM, BR_TO, LAST_EX_FROM, LAST_EX_TO */ | 256 | VMCB_LBR, /* DBGCTL, BR_FROM, BR_TO, LAST_EX_FROM, LAST_EX_TO */ |
257 | VMCB_AVIC, /* AVIC APIC_BAR, AVIC APIC_BACKING_PAGE, | ||
258 | * AVIC PHYSICAL_TABLE pointer, | ||
259 | * AVIC LOGICAL_TABLE pointer | ||
260 | */ | ||
231 | VMCB_DIRTY_MAX, | 261 | VMCB_DIRTY_MAX, |
232 | }; | 262 | }; |
233 | 263 | ||
234 | /* TPR and CR2 are always written before VMRUN */ | 264 | /* TPR and CR2 are always written before VMRUN */ |
235 | #define VMCB_ALWAYS_DIRTY_MASK ((1U << VMCB_INTR) | (1U << VMCB_CR2)) | 265 | #define VMCB_ALWAYS_DIRTY_MASK ((1U << VMCB_INTR) | (1U << VMCB_CR2)) |
236 | 266 | ||
267 | #define VMCB_AVIC_APIC_BAR_MASK 0xFFFFFFFFFF000ULL | ||
268 | |||
237 | static inline void mark_all_dirty(struct vmcb *vmcb) | 269 | static inline void mark_all_dirty(struct vmcb *vmcb) |
238 | { | 270 | { |
239 | vmcb->control.clean = 0; | 271 | vmcb->control.clean = 0; |
@@ -255,6 +287,12 @@ static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) | |||
255 | return container_of(vcpu, struct vcpu_svm, vcpu); | 287 | return container_of(vcpu, struct vcpu_svm, vcpu); |
256 | } | 288 | } |
257 | 289 | ||
290 | static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data) | ||
291 | { | ||
292 | svm->vmcb->control.avic_vapic_bar = data & VMCB_AVIC_APIC_BAR_MASK; | ||
293 | mark_dirty(svm->vmcb, VMCB_AVIC); | ||
294 | } | ||
295 | |||
258 | static void recalc_intercepts(struct vcpu_svm *svm) | 296 | static void recalc_intercepts(struct vcpu_svm *svm) |
259 | { | 297 | { |
260 | struct vmcb_control_area *c, *h; | 298 | struct vmcb_control_area *c, *h; |
@@ -923,6 +961,12 @@ static __init int svm_hardware_setup(void) | |||
923 | } else | 961 | } else |
924 | kvm_disable_tdp(); | 962 | kvm_disable_tdp(); |
925 | 963 | ||
964 | if (avic && (!npt_enabled || !boot_cpu_has(X86_FEATURE_AVIC))) | ||
965 | avic = false; | ||
966 | |||
967 | if (avic) | ||
968 | pr_info("AVIC enabled\n"); | ||
969 | |||
926 | return 0; | 970 | return 0; |
927 | 971 | ||
928 | err: | 972 | err: |
@@ -1000,6 +1044,22 @@ static void svm_adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, s64 adjustment) | |||
1000 | mark_dirty(svm->vmcb, VMCB_INTERCEPTS); | 1044 | mark_dirty(svm->vmcb, VMCB_INTERCEPTS); |
1001 | } | 1045 | } |
1002 | 1046 | ||
1047 | static void avic_init_vmcb(struct vcpu_svm *svm) | ||
1048 | { | ||
1049 | struct vmcb *vmcb = svm->vmcb; | ||
1050 | struct kvm_arch *vm_data = &svm->vcpu.kvm->arch; | ||
1051 | phys_addr_t bpa = page_to_phys(svm->avic_backing_page); | ||
1052 | phys_addr_t lpa = page_to_phys(vm_data->avic_logical_id_table_page); | ||
1053 | phys_addr_t ppa = page_to_phys(vm_data->avic_physical_id_table_page); | ||
1054 | |||
1055 | vmcb->control.avic_backing_page = bpa & AVIC_HPA_MASK; | ||
1056 | vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK; | ||
1057 | vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK; | ||
1058 | vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID_COUNT; | ||
1059 | vmcb->control.int_ctl |= AVIC_ENABLE_MASK; | ||
1060 | svm->vcpu.arch.apicv_active = true; | ||
1061 | } | ||
1062 | |||
1003 | static void init_vmcb(struct vcpu_svm *svm) | 1063 | static void init_vmcb(struct vcpu_svm *svm) |
1004 | { | 1064 | { |
1005 | struct vmcb_control_area *control = &svm->vmcb->control; | 1065 | struct vmcb_control_area *control = &svm->vmcb->control; |
@@ -1110,9 +1170,131 @@ static void init_vmcb(struct vcpu_svm *svm) | |||
1110 | set_intercept(svm, INTERCEPT_PAUSE); | 1170 | set_intercept(svm, INTERCEPT_PAUSE); |
1111 | } | 1171 | } |
1112 | 1172 | ||
1173 | if (avic) | ||
1174 | avic_init_vmcb(svm); | ||
1175 | |||
1113 | mark_all_dirty(svm->vmcb); | 1176 | mark_all_dirty(svm->vmcb); |
1114 | 1177 | ||
1115 | enable_gif(svm); | 1178 | enable_gif(svm); |
1179 | |||
1180 | } | ||
1181 | |||
1182 | static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu, int index) | ||
1183 | { | ||
1184 | u64 *avic_physical_id_table; | ||
1185 | struct kvm_arch *vm_data = &vcpu->kvm->arch; | ||
1186 | |||
1187 | if (index >= AVIC_MAX_PHYSICAL_ID_COUNT) | ||
1188 | return NULL; | ||
1189 | |||
1190 | avic_physical_id_table = page_address(vm_data->avic_physical_id_table_page); | ||
1191 | |||
1192 | return &avic_physical_id_table[index]; | ||
1193 | } | ||
1194 | |||
1195 | /** | ||
1196 | * Note: | ||
1197 | * AVIC hardware walks the nested page table to check permissions, | ||
1198 | * but does not use the SPA address specified in the leaf page | ||
1199 | * table entry since it uses address in the AVIC_BACKING_PAGE pointer | ||
1200 | * field of the VMCB. Therefore, we set up the | ||
1201 | * APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (4KB) here. | ||
1202 | */ | ||
1203 | static int avic_init_access_page(struct kvm_vcpu *vcpu) | ||
1204 | { | ||
1205 | struct kvm *kvm = vcpu->kvm; | ||
1206 | int ret; | ||
1207 | |||
1208 | if (kvm->arch.apic_access_page_done) | ||
1209 | return 0; | ||
1210 | |||
1211 | ret = x86_set_memory_region(kvm, | ||
1212 | APIC_ACCESS_PAGE_PRIVATE_MEMSLOT, | ||
1213 | APIC_DEFAULT_PHYS_BASE, | ||
1214 | PAGE_SIZE); | ||
1215 | if (ret) | ||
1216 | return ret; | ||
1217 | |||
1218 | kvm->arch.apic_access_page_done = true; | ||
1219 | return 0; | ||
1220 | } | ||
1221 | |||
1222 | static int avic_init_backing_page(struct kvm_vcpu *vcpu) | ||
1223 | { | ||
1224 | int ret; | ||
1225 | u64 *entry, new_entry; | ||
1226 | int id = vcpu->vcpu_id; | ||
1227 | struct vcpu_svm *svm = to_svm(vcpu); | ||
1228 | |||
1229 | ret = avic_init_access_page(vcpu); | ||
1230 | if (ret) | ||
1231 | return ret; | ||
1232 | |||
1233 | if (id >= AVIC_MAX_PHYSICAL_ID_COUNT) | ||
1234 | return -EINVAL; | ||
1235 | |||
1236 | if (!svm->vcpu.arch.apic->regs) | ||
1237 | return -EINVAL; | ||
1238 | |||
1239 | svm->avic_backing_page = virt_to_page(svm->vcpu.arch.apic->regs); | ||
1240 | |||
1241 | /* Setting AVIC backing page address in the phy APIC ID table */ | ||
1242 | entry = avic_get_physical_id_entry(vcpu, id); | ||
1243 | if (!entry) | ||
1244 | return -EINVAL; | ||
1245 | |||
1246 | new_entry = READ_ONCE(*entry); | ||
1247 | new_entry = (page_to_phys(svm->avic_backing_page) & | ||
1248 | AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK) | | ||
1249 | AVIC_PHYSICAL_ID_ENTRY_VALID_MASK; | ||
1250 | WRITE_ONCE(*entry, new_entry); | ||
1251 | |||
1252 | svm->avic_physical_id_cache = entry; | ||
1253 | |||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1257 | static void avic_vm_destroy(struct kvm *kvm) | ||
1258 | { | ||
1259 | struct kvm_arch *vm_data = &kvm->arch; | ||
1260 | |||
1261 | if (vm_data->avic_logical_id_table_page) | ||
1262 | __free_page(vm_data->avic_logical_id_table_page); | ||
1263 | if (vm_data->avic_physical_id_table_page) | ||
1264 | __free_page(vm_data->avic_physical_id_table_page); | ||
1265 | } | ||
1266 | |||
1267 | static int avic_vm_init(struct kvm *kvm) | ||
1268 | { | ||
1269 | int err = -ENOMEM; | ||
1270 | struct kvm_arch *vm_data = &kvm->arch; | ||
1271 | struct page *p_page; | ||
1272 | struct page *l_page; | ||
1273 | |||
1274 | if (!avic) | ||
1275 | return 0; | ||
1276 | |||
1277 | /* Allocating physical APIC ID table (4KB) */ | ||
1278 | p_page = alloc_page(GFP_KERNEL); | ||
1279 | if (!p_page) | ||
1280 | goto free_avic; | ||
1281 | |||
1282 | vm_data->avic_physical_id_table_page = p_page; | ||
1283 | clear_page(page_address(p_page)); | ||
1284 | |||
1285 | /* Allocating logical APIC ID table (4KB) */ | ||
1286 | l_page = alloc_page(GFP_KERNEL); | ||
1287 | if (!l_page) | ||
1288 | goto free_avic; | ||
1289 | |||
1290 | vm_data->avic_logical_id_table_page = l_page; | ||
1291 | clear_page(page_address(l_page)); | ||
1292 | |||
1293 | return 0; | ||
1294 | |||
1295 | free_avic: | ||
1296 | avic_vm_destroy(kvm); | ||
1297 | return err; | ||
1116 | } | 1298 | } |
1117 | 1299 | ||
1118 | static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) | 1300 | static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) |
@@ -1131,6 +1313,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) | |||
1131 | 1313 | ||
1132 | kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy); | 1314 | kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy); |
1133 | kvm_register_write(vcpu, VCPU_REGS_RDX, eax); | 1315 | kvm_register_write(vcpu, VCPU_REGS_RDX, eax); |
1316 | |||
1317 | if (kvm_vcpu_apicv_active(vcpu) && !init_event) | ||
1318 | avic_update_vapic_bar(svm, APIC_DEFAULT_PHYS_BASE); | ||
1134 | } | 1319 | } |
1135 | 1320 | ||
1136 | static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) | 1321 | static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) |
@@ -1169,6 +1354,12 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) | |||
1169 | if (!hsave_page) | 1354 | if (!hsave_page) |
1170 | goto free_page3; | 1355 | goto free_page3; |
1171 | 1356 | ||
1357 | if (avic) { | ||
1358 | err = avic_init_backing_page(&svm->vcpu); | ||
1359 | if (err) | ||
1360 | goto free_page4; | ||
1361 | } | ||
1362 | |||
1172 | svm->nested.hsave = page_address(hsave_page); | 1363 | svm->nested.hsave = page_address(hsave_page); |
1173 | 1364 | ||
1174 | svm->msrpm = page_address(msrpm_pages); | 1365 | svm->msrpm = page_address(msrpm_pages); |
@@ -1187,6 +1378,8 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) | |||
1187 | 1378 | ||
1188 | return &svm->vcpu; | 1379 | return &svm->vcpu; |
1189 | 1380 | ||
1381 | free_page4: | ||
1382 | __free_page(hsave_page); | ||
1190 | free_page3: | 1383 | free_page3: |
1191 | __free_pages(nested_msrpm_pages, MSRPM_ALLOC_ORDER); | 1384 | __free_pages(nested_msrpm_pages, MSRPM_ALLOC_ORDER); |
1192 | free_page2: | 1385 | free_page2: |
@@ -3212,6 +3405,10 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) | |||
3212 | case MSR_VM_IGNNE: | 3405 | case MSR_VM_IGNNE: |
3213 | vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data); | 3406 | vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data); |
3214 | break; | 3407 | break; |
3408 | case MSR_IA32_APICBASE: | ||
3409 | if (kvm_vcpu_apicv_active(vcpu)) | ||
3410 | avic_update_vapic_bar(to_svm(vcpu), data); | ||
3411 | /* Follow through */ | ||
3215 | default: | 3412 | default: |
3216 | return kvm_set_msr_common(vcpu, msr); | 3413 | return kvm_set_msr_common(vcpu, msr); |
3217 | } | 3414 | } |
@@ -3375,10 +3572,14 @@ static void dump_vmcb(struct kvm_vcpu *vcpu) | |||
3375 | pr_err("%-20s%08x\n", "exit_int_info_err:", control->exit_int_info_err); | 3572 | pr_err("%-20s%08x\n", "exit_int_info_err:", control->exit_int_info_err); |
3376 | pr_err("%-20s%lld\n", "nested_ctl:", control->nested_ctl); | 3573 | pr_err("%-20s%lld\n", "nested_ctl:", control->nested_ctl); |
3377 | pr_err("%-20s%016llx\n", "nested_cr3:", control->nested_cr3); | 3574 | pr_err("%-20s%016llx\n", "nested_cr3:", control->nested_cr3); |
3575 | pr_err("%-20s%016llx\n", "avic_vapic_bar:", control->avic_vapic_bar); | ||
3378 | pr_err("%-20s%08x\n", "event_inj:", control->event_inj); | 3576 | pr_err("%-20s%08x\n", "event_inj:", control->event_inj); |
3379 | pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err); | 3577 | pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err); |
3380 | pr_err("%-20s%lld\n", "lbr_ctl:", control->lbr_ctl); | 3578 | pr_err("%-20s%lld\n", "lbr_ctl:", control->lbr_ctl); |
3381 | pr_err("%-20s%016llx\n", "next_rip:", control->next_rip); | 3579 | pr_err("%-20s%016llx\n", "next_rip:", control->next_rip); |
3580 | pr_err("%-20s%016llx\n", "avic_backing_page:", control->avic_backing_page); | ||
3581 | pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id); | ||
3582 | pr_err("%-20s%016llx\n", "avic_physical_id:", control->avic_physical_id); | ||
3382 | pr_err("VMCB State Save Area:\n"); | 3583 | pr_err("VMCB State Save Area:\n"); |
3383 | pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", | 3584 | pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n", |
3384 | "es:", | 3585 | "es:", |
@@ -3606,11 +3807,28 @@ static void svm_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set) | |||
3606 | 3807 | ||
3607 | static bool svm_get_enable_apicv(void) | 3808 | static bool svm_get_enable_apicv(void) |
3608 | { | 3809 | { |
3609 | return false; | 3810 | return avic; |
3811 | } | ||
3812 | |||
3813 | static void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr) | ||
3814 | { | ||
3815 | } | ||
3816 | |||
3817 | static void svm_hwapic_isr_update(struct kvm *kvm, int isr) | ||
3818 | { | ||
3610 | } | 3819 | } |
3611 | 3820 | ||
3821 | /* Note: Currently only used by Hyper-V. */ | ||
3612 | static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) | 3822 | static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) |
3613 | { | 3823 | { |
3824 | struct vcpu_svm *svm = to_svm(vcpu); | ||
3825 | struct vmcb *vmcb = svm->vmcb; | ||
3826 | |||
3827 | if (!avic) | ||
3828 | return; | ||
3829 | |||
3830 | vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK; | ||
3831 | mark_dirty(vmcb, VMCB_INTR); | ||
3614 | } | 3832 | } |
3615 | 3833 | ||
3616 | static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) | 3834 | static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) |
@@ -4322,6 +4540,9 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
4322 | .vcpu_free = svm_free_vcpu, | 4540 | .vcpu_free = svm_free_vcpu, |
4323 | .vcpu_reset = svm_vcpu_reset, | 4541 | .vcpu_reset = svm_vcpu_reset, |
4324 | 4542 | ||
4543 | .vm_init = avic_vm_init, | ||
4544 | .vm_destroy = avic_vm_destroy, | ||
4545 | |||
4325 | .prepare_guest_switch = svm_prepare_guest_switch, | 4546 | .prepare_guest_switch = svm_prepare_guest_switch, |
4326 | .vcpu_load = svm_vcpu_load, | 4547 | .vcpu_load = svm_vcpu_load, |
4327 | .vcpu_put = svm_vcpu_put, | 4548 | .vcpu_put = svm_vcpu_put, |
@@ -4382,6 +4603,8 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
4382 | .refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl, | 4603 | .refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl, |
4383 | .load_eoi_exitmap = svm_load_eoi_exitmap, | 4604 | .load_eoi_exitmap = svm_load_eoi_exitmap, |
4384 | .sync_pir_to_irr = svm_sync_pir_to_irr, | 4605 | .sync_pir_to_irr = svm_sync_pir_to_irr, |
4606 | .hwapic_irr_update = svm_hwapic_irr_update, | ||
4607 | .hwapic_isr_update = svm_hwapic_isr_update, | ||
4385 | 4608 | ||
4386 | .set_tss_addr = svm_set_tss_addr, | 4609 | .set_tss_addr = svm_set_tss_addr, |
4387 | .get_tdp_level = get_npt_level, | 4610 | .get_tdp_level = get_npt_level, |