diff options
Diffstat (limited to 'arch/x86/kvm/svm.c')
-rw-r--r-- | arch/x86/kvm/svm.c | 131 |
1 files changed, 90 insertions, 41 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 6b0d5fa5bab3..b756e876dce3 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -27,6 +27,8 @@ | |||
27 | 27 | ||
28 | #include <asm/desc.h> | 28 | #include <asm/desc.h> |
29 | 29 | ||
30 | #define __ex(x) __kvm_handle_fault_on_reboot(x) | ||
31 | |||
30 | MODULE_AUTHOR("Qumranet"); | 32 | MODULE_AUTHOR("Qumranet"); |
31 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
32 | 34 | ||
@@ -129,17 +131,17 @@ static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq) | |||
129 | 131 | ||
130 | static inline void clgi(void) | 132 | static inline void clgi(void) |
131 | { | 133 | { |
132 | asm volatile (SVM_CLGI); | 134 | asm volatile (__ex(SVM_CLGI)); |
133 | } | 135 | } |
134 | 136 | ||
135 | static inline void stgi(void) | 137 | static inline void stgi(void) |
136 | { | 138 | { |
137 | asm volatile (SVM_STGI); | 139 | asm volatile (__ex(SVM_STGI)); |
138 | } | 140 | } |
139 | 141 | ||
140 | static inline void invlpga(unsigned long addr, u32 asid) | 142 | static inline void invlpga(unsigned long addr, u32 asid) |
141 | { | 143 | { |
142 | asm volatile (SVM_INVLPGA :: "a"(addr), "c"(asid)); | 144 | asm volatile (__ex(SVM_INVLPGA) :: "a"(addr), "c"(asid)); |
143 | } | 145 | } |
144 | 146 | ||
145 | static inline unsigned long kvm_read_cr2(void) | 147 | static inline unsigned long kvm_read_cr2(void) |
@@ -270,19 +272,11 @@ static int has_svm(void) | |||
270 | 272 | ||
271 | static void svm_hardware_disable(void *garbage) | 273 | static void svm_hardware_disable(void *garbage) |
272 | { | 274 | { |
273 | struct svm_cpu_data *svm_data | 275 | uint64_t efer; |
274 | = per_cpu(svm_data, raw_smp_processor_id()); | ||
275 | |||
276 | if (svm_data) { | ||
277 | uint64_t efer; | ||
278 | 276 | ||
279 | wrmsrl(MSR_VM_HSAVE_PA, 0); | 277 | wrmsrl(MSR_VM_HSAVE_PA, 0); |
280 | rdmsrl(MSR_EFER, efer); | 278 | rdmsrl(MSR_EFER, efer); |
281 | wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); | 279 | wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); |
282 | per_cpu(svm_data, raw_smp_processor_id()) = NULL; | ||
283 | __free_page(svm_data->save_area); | ||
284 | kfree(svm_data); | ||
285 | } | ||
286 | } | 280 | } |
287 | 281 | ||
288 | static void svm_hardware_enable(void *garbage) | 282 | static void svm_hardware_enable(void *garbage) |
@@ -321,6 +315,19 @@ static void svm_hardware_enable(void *garbage) | |||
321 | page_to_pfn(svm_data->save_area) << PAGE_SHIFT); | 315 | page_to_pfn(svm_data->save_area) << PAGE_SHIFT); |
322 | } | 316 | } |
323 | 317 | ||
318 | static void svm_cpu_uninit(int cpu) | ||
319 | { | ||
320 | struct svm_cpu_data *svm_data | ||
321 | = per_cpu(svm_data, raw_smp_processor_id()); | ||
322 | |||
323 | if (!svm_data) | ||
324 | return; | ||
325 | |||
326 | per_cpu(svm_data, raw_smp_processor_id()) = NULL; | ||
327 | __free_page(svm_data->save_area); | ||
328 | kfree(svm_data); | ||
329 | } | ||
330 | |||
324 | static int svm_cpu_init(int cpu) | 331 | static int svm_cpu_init(int cpu) |
325 | { | 332 | { |
326 | struct svm_cpu_data *svm_data; | 333 | struct svm_cpu_data *svm_data; |
@@ -458,6 +465,11 @@ err: | |||
458 | 465 | ||
459 | static __exit void svm_hardware_unsetup(void) | 466 | static __exit void svm_hardware_unsetup(void) |
460 | { | 467 | { |
468 | int cpu; | ||
469 | |||
470 | for_each_online_cpu(cpu) | ||
471 | svm_cpu_uninit(cpu); | ||
472 | |||
461 | __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER); | 473 | __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER); |
462 | iopm_base = 0; | 474 | iopm_base = 0; |
463 | } | 475 | } |
@@ -707,10 +719,6 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu) | |||
707 | rdtscll(vcpu->arch.host_tsc); | 719 | rdtscll(vcpu->arch.host_tsc); |
708 | } | 720 | } |
709 | 721 | ||
710 | static void svm_vcpu_decache(struct kvm_vcpu *vcpu) | ||
711 | { | ||
712 | } | ||
713 | |||
714 | static void svm_cache_regs(struct kvm_vcpu *vcpu) | 722 | static void svm_cache_regs(struct kvm_vcpu *vcpu) |
715 | { | 723 | { |
716 | struct vcpu_svm *svm = to_svm(vcpu); | 724 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -949,7 +957,9 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data) | |||
949 | 957 | ||
950 | static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) | 958 | static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) |
951 | { | 959 | { |
952 | return to_svm(vcpu)->db_regs[dr]; | 960 | unsigned long val = to_svm(vcpu)->db_regs[dr]; |
961 | KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler); | ||
962 | return val; | ||
953 | } | 963 | } |
954 | 964 | ||
955 | static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, | 965 | static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, |
@@ -1004,6 +1014,16 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
1004 | 1014 | ||
1005 | fault_address = svm->vmcb->control.exit_info_2; | 1015 | fault_address = svm->vmcb->control.exit_info_2; |
1006 | error_code = svm->vmcb->control.exit_info_1; | 1016 | error_code = svm->vmcb->control.exit_info_1; |
1017 | |||
1018 | if (!npt_enabled) | ||
1019 | KVMTRACE_3D(PAGE_FAULT, &svm->vcpu, error_code, | ||
1020 | (u32)fault_address, (u32)(fault_address >> 32), | ||
1021 | handler); | ||
1022 | else | ||
1023 | KVMTRACE_3D(TDP_FAULT, &svm->vcpu, error_code, | ||
1024 | (u32)fault_address, (u32)(fault_address >> 32), | ||
1025 | handler); | ||
1026 | |||
1007 | return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); | 1027 | return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); |
1008 | } | 1028 | } |
1009 | 1029 | ||
@@ -1081,6 +1101,19 @@ static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
1081 | return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port); | 1101 | return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port); |
1082 | } | 1102 | } |
1083 | 1103 | ||
1104 | static int nmi_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | ||
1105 | { | ||
1106 | KVMTRACE_0D(NMI, &svm->vcpu, handler); | ||
1107 | return 1; | ||
1108 | } | ||
1109 | |||
1110 | static int intr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | ||
1111 | { | ||
1112 | ++svm->vcpu.stat.irq_exits; | ||
1113 | KVMTRACE_0D(INTR, &svm->vcpu, handler); | ||
1114 | return 1; | ||
1115 | } | ||
1116 | |||
1084 | static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | 1117 | static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) |
1085 | { | 1118 | { |
1086 | return 1; | 1119 | return 1; |
@@ -1219,6 +1252,9 @@ static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
1219 | if (svm_get_msr(&svm->vcpu, ecx, &data)) | 1252 | if (svm_get_msr(&svm->vcpu, ecx, &data)) |
1220 | kvm_inject_gp(&svm->vcpu, 0); | 1253 | kvm_inject_gp(&svm->vcpu, 0); |
1221 | else { | 1254 | else { |
1255 | KVMTRACE_3D(MSR_READ, &svm->vcpu, ecx, (u32)data, | ||
1256 | (u32)(data >> 32), handler); | ||
1257 | |||
1222 | svm->vmcb->save.rax = data & 0xffffffff; | 1258 | svm->vmcb->save.rax = data & 0xffffffff; |
1223 | svm->vcpu.arch.regs[VCPU_REGS_RDX] = data >> 32; | 1259 | svm->vcpu.arch.regs[VCPU_REGS_RDX] = data >> 32; |
1224 | svm->next_rip = svm->vmcb->save.rip + 2; | 1260 | svm->next_rip = svm->vmcb->save.rip + 2; |
@@ -1284,16 +1320,19 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) | |||
1284 | case MSR_K7_EVNTSEL1: | 1320 | case MSR_K7_EVNTSEL1: |
1285 | case MSR_K7_EVNTSEL2: | 1321 | case MSR_K7_EVNTSEL2: |
1286 | case MSR_K7_EVNTSEL3: | 1322 | case MSR_K7_EVNTSEL3: |
1323 | case MSR_K7_PERFCTR0: | ||
1324 | case MSR_K7_PERFCTR1: | ||
1325 | case MSR_K7_PERFCTR2: | ||
1326 | case MSR_K7_PERFCTR3: | ||
1287 | /* | 1327 | /* |
1288 | * only support writing 0 to the performance counters for now | 1328 | * Just discard all writes to the performance counters; this |
1289 | * to make Windows happy. Should be replaced by a real | 1329 | * should keep both older linux and windows 64-bit guests |
1290 | * performance counter emulation later. | 1330 | * happy |
1291 | */ | 1331 | */ |
1292 | if (data != 0) | 1332 | pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", ecx, data); |
1293 | goto unhandled; | 1333 | |
1294 | break; | 1334 | break; |
1295 | default: | 1335 | default: |
1296 | unhandled: | ||
1297 | return kvm_set_msr_common(vcpu, ecx, data); | 1336 | return kvm_set_msr_common(vcpu, ecx, data); |
1298 | } | 1337 | } |
1299 | return 0; | 1338 | return 0; |
@@ -1304,6 +1343,10 @@ static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
1304 | u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX]; | 1343 | u32 ecx = svm->vcpu.arch.regs[VCPU_REGS_RCX]; |
1305 | u64 data = (svm->vmcb->save.rax & -1u) | 1344 | u64 data = (svm->vmcb->save.rax & -1u) |
1306 | | ((u64)(svm->vcpu.arch.regs[VCPU_REGS_RDX] & -1u) << 32); | 1345 | | ((u64)(svm->vcpu.arch.regs[VCPU_REGS_RDX] & -1u) << 32); |
1346 | |||
1347 | KVMTRACE_3D(MSR_WRITE, &svm->vcpu, ecx, (u32)data, (u32)(data >> 32), | ||
1348 | handler); | ||
1349 | |||
1307 | svm->next_rip = svm->vmcb->save.rip + 2; | 1350 | svm->next_rip = svm->vmcb->save.rip + 2; |
1308 | if (svm_set_msr(&svm->vcpu, ecx, data)) | 1351 | if (svm_set_msr(&svm->vcpu, ecx, data)) |
1309 | kvm_inject_gp(&svm->vcpu, 0); | 1352 | kvm_inject_gp(&svm->vcpu, 0); |
@@ -1323,6 +1366,8 @@ static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
1323 | static int interrupt_window_interception(struct vcpu_svm *svm, | 1366 | static int interrupt_window_interception(struct vcpu_svm *svm, |
1324 | struct kvm_run *kvm_run) | 1367 | struct kvm_run *kvm_run) |
1325 | { | 1368 | { |
1369 | KVMTRACE_0D(PEND_INTR, &svm->vcpu, handler); | ||
1370 | |||
1326 | svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR); | 1371 | svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR); |
1327 | svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; | 1372 | svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; |
1328 | /* | 1373 | /* |
@@ -1364,8 +1409,8 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, | |||
1364 | [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, | 1409 | [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, |
1365 | [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, | 1410 | [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, |
1366 | [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, | 1411 | [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, |
1367 | [SVM_EXIT_INTR] = nop_on_interception, | 1412 | [SVM_EXIT_INTR] = intr_interception, |
1368 | [SVM_EXIT_NMI] = nop_on_interception, | 1413 | [SVM_EXIT_NMI] = nmi_interception, |
1369 | [SVM_EXIT_SMI] = nop_on_interception, | 1414 | [SVM_EXIT_SMI] = nop_on_interception, |
1370 | [SVM_EXIT_INIT] = nop_on_interception, | 1415 | [SVM_EXIT_INIT] = nop_on_interception, |
1371 | [SVM_EXIT_VINTR] = interrupt_window_interception, | 1416 | [SVM_EXIT_VINTR] = interrupt_window_interception, |
@@ -1397,6 +1442,9 @@ static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | |||
1397 | struct vcpu_svm *svm = to_svm(vcpu); | 1442 | struct vcpu_svm *svm = to_svm(vcpu); |
1398 | u32 exit_code = svm->vmcb->control.exit_code; | 1443 | u32 exit_code = svm->vmcb->control.exit_code; |
1399 | 1444 | ||
1445 | KVMTRACE_3D(VMEXIT, vcpu, exit_code, (u32)svm->vmcb->save.rip, | ||
1446 | (u32)((u64)svm->vmcb->save.rip >> 32), entryexit); | ||
1447 | |||
1400 | if (npt_enabled) { | 1448 | if (npt_enabled) { |
1401 | int mmu_reload = 0; | 1449 | int mmu_reload = 0; |
1402 | if ((vcpu->arch.cr0 ^ svm->vmcb->save.cr0) & X86_CR0_PG) { | 1450 | if ((vcpu->arch.cr0 ^ svm->vmcb->save.cr0) & X86_CR0_PG) { |
@@ -1470,6 +1518,8 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) | |||
1470 | { | 1518 | { |
1471 | struct vmcb_control_area *control; | 1519 | struct vmcb_control_area *control; |
1472 | 1520 | ||
1521 | KVMTRACE_1D(INJ_VIRQ, &svm->vcpu, (u32)irq, handler); | ||
1522 | |||
1473 | control = &svm->vmcb->control; | 1523 | control = &svm->vmcb->control; |
1474 | control->int_vector = irq; | 1524 | control->int_vector = irq; |
1475 | control->int_ctl &= ~V_INTR_PRIO_MASK; | 1525 | control->int_ctl &= ~V_INTR_PRIO_MASK; |
@@ -1660,9 +1710,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1660 | sync_lapic_to_cr8(vcpu); | 1710 | sync_lapic_to_cr8(vcpu); |
1661 | 1711 | ||
1662 | save_host_msrs(vcpu); | 1712 | save_host_msrs(vcpu); |
1663 | fs_selector = read_fs(); | 1713 | fs_selector = kvm_read_fs(); |
1664 | gs_selector = read_gs(); | 1714 | gs_selector = kvm_read_gs(); |
1665 | ldt_selector = read_ldt(); | 1715 | ldt_selector = kvm_read_ldt(); |
1666 | svm->host_cr2 = kvm_read_cr2(); | 1716 | svm->host_cr2 = kvm_read_cr2(); |
1667 | svm->host_dr6 = read_dr6(); | 1717 | svm->host_dr6 = read_dr6(); |
1668 | svm->host_dr7 = read_dr7(); | 1718 | svm->host_dr7 = read_dr7(); |
@@ -1716,17 +1766,17 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1716 | /* Enter guest mode */ | 1766 | /* Enter guest mode */ |
1717 | "push %%rax \n\t" | 1767 | "push %%rax \n\t" |
1718 | "mov %c[vmcb](%[svm]), %%rax \n\t" | 1768 | "mov %c[vmcb](%[svm]), %%rax \n\t" |
1719 | SVM_VMLOAD "\n\t" | 1769 | __ex(SVM_VMLOAD) "\n\t" |
1720 | SVM_VMRUN "\n\t" | 1770 | __ex(SVM_VMRUN) "\n\t" |
1721 | SVM_VMSAVE "\n\t" | 1771 | __ex(SVM_VMSAVE) "\n\t" |
1722 | "pop %%rax \n\t" | 1772 | "pop %%rax \n\t" |
1723 | #else | 1773 | #else |
1724 | /* Enter guest mode */ | 1774 | /* Enter guest mode */ |
1725 | "push %%eax \n\t" | 1775 | "push %%eax \n\t" |
1726 | "mov %c[vmcb](%[svm]), %%eax \n\t" | 1776 | "mov %c[vmcb](%[svm]), %%eax \n\t" |
1727 | SVM_VMLOAD "\n\t" | 1777 | __ex(SVM_VMLOAD) "\n\t" |
1728 | SVM_VMRUN "\n\t" | 1778 | __ex(SVM_VMRUN) "\n\t" |
1729 | SVM_VMSAVE "\n\t" | 1779 | __ex(SVM_VMSAVE) "\n\t" |
1730 | "pop %%eax \n\t" | 1780 | "pop %%eax \n\t" |
1731 | #endif | 1781 | #endif |
1732 | 1782 | ||
@@ -1795,9 +1845,9 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
1795 | write_dr7(svm->host_dr7); | 1845 | write_dr7(svm->host_dr7); |
1796 | kvm_write_cr2(svm->host_cr2); | 1846 | kvm_write_cr2(svm->host_cr2); |
1797 | 1847 | ||
1798 | load_fs(fs_selector); | 1848 | kvm_load_fs(fs_selector); |
1799 | load_gs(gs_selector); | 1849 | kvm_load_gs(gs_selector); |
1800 | load_ldt(ldt_selector); | 1850 | kvm_load_ldt(ldt_selector); |
1801 | load_host_msrs(vcpu); | 1851 | load_host_msrs(vcpu); |
1802 | 1852 | ||
1803 | reload_tss(vcpu); | 1853 | reload_tss(vcpu); |
@@ -1889,7 +1939,6 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
1889 | .prepare_guest_switch = svm_prepare_guest_switch, | 1939 | .prepare_guest_switch = svm_prepare_guest_switch, |
1890 | .vcpu_load = svm_vcpu_load, | 1940 | .vcpu_load = svm_vcpu_load, |
1891 | .vcpu_put = svm_vcpu_put, | 1941 | .vcpu_put = svm_vcpu_put, |
1892 | .vcpu_decache = svm_vcpu_decache, | ||
1893 | 1942 | ||
1894 | .set_guest_debug = svm_guest_debug, | 1943 | .set_guest_debug = svm_guest_debug, |
1895 | .get_msr = svm_get_msr, | 1944 | .get_msr = svm_get_msr, |