diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-18 14:08:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-18 14:08:52 -0400 |
commit | 10bd6b3fc4a4bdeb599495700e97722d18d36609 (patch) | |
tree | 4b0b28756162cc211c941ebd1e846c779399bd82 | |
parent | 98ae6878f151b0b508b09a36367c231b707a88cf (diff) | |
parent | 27aba76615eeb36af84118e8ea6d35ffa51fd1e3 (diff) |
Merge branch 'linus' of git://kvm.qumranet.com/home/avi/kvm
* 'linus' of git://kvm.qumranet.com/home/avi/kvm:
KVM: MMU: Fix host memory corruption on i386 with >= 4GB ram
KVM: MMU: Fix guest writes to nonpae pde
KVM: Fix guest sysenter on vmx
KVM: Unset kvm_arch_ops if arch module loading failed
-rw-r--r-- | drivers/kvm/kvm_main.c | 4 | ||||
-rw-r--r-- | drivers/kvm/mmu.c | 52 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 8 |
3 files changed, 44 insertions, 20 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index a163bca38973..dc7a8c78cbf9 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -2464,7 +2464,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) | |||
2464 | 2464 | ||
2465 | r = kvm_arch_ops->hardware_setup(); | 2465 | r = kvm_arch_ops->hardware_setup(); |
2466 | if (r < 0) | 2466 | if (r < 0) |
2467 | return r; | 2467 | goto out; |
2468 | 2468 | ||
2469 | on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1); | 2469 | on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1); |
2470 | r = register_cpu_notifier(&kvm_cpu_notifier); | 2470 | r = register_cpu_notifier(&kvm_cpu_notifier); |
@@ -2500,6 +2500,8 @@ out_free_2: | |||
2500 | out_free_1: | 2500 | out_free_1: |
2501 | on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); | 2501 | on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); |
2502 | kvm_arch_ops->hardware_unsetup(); | 2502 | kvm_arch_ops->hardware_unsetup(); |
2503 | out: | ||
2504 | kvm_arch_ops = NULL; | ||
2503 | return r; | 2505 | return r; |
2504 | } | 2506 | } |
2505 | 2507 | ||
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index a1a93368f314..e85b4c7c36f7 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c | |||
@@ -131,7 +131,7 @@ static int dbg = 1; | |||
131 | (((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1)) | 131 | (((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1)) |
132 | 132 | ||
133 | 133 | ||
134 | #define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & PAGE_MASK) | 134 | #define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)) |
135 | #define PT64_DIR_BASE_ADDR_MASK \ | 135 | #define PT64_DIR_BASE_ADDR_MASK \ |
136 | (PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + PT64_LEVEL_BITS)) - 1)) | 136 | (PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + PT64_LEVEL_BITS)) - 1)) |
137 | 137 | ||
@@ -406,8 +406,8 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn) | |||
406 | spte = desc->shadow_ptes[0]; | 406 | spte = desc->shadow_ptes[0]; |
407 | } | 407 | } |
408 | BUG_ON(!spte); | 408 | BUG_ON(!spte); |
409 | BUG_ON((*spte & PT64_BASE_ADDR_MASK) != | 409 | BUG_ON((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT |
410 | page_to_pfn(page) << PAGE_SHIFT); | 410 | != page_to_pfn(page)); |
411 | BUG_ON(!(*spte & PT_PRESENT_MASK)); | 411 | BUG_ON(!(*spte & PT_PRESENT_MASK)); |
412 | BUG_ON(!(*spte & PT_WRITABLE_MASK)); | 412 | BUG_ON(!(*spte & PT_WRITABLE_MASK)); |
413 | rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte); | 413 | rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte); |
@@ -1093,22 +1093,40 @@ out: | |||
1093 | return r; | 1093 | return r; |
1094 | } | 1094 | } |
1095 | 1095 | ||
1096 | static void mmu_pre_write_zap_pte(struct kvm_vcpu *vcpu, | ||
1097 | struct kvm_mmu_page *page, | ||
1098 | u64 *spte) | ||
1099 | { | ||
1100 | u64 pte; | ||
1101 | struct kvm_mmu_page *child; | ||
1102 | |||
1103 | pte = *spte; | ||
1104 | if (is_present_pte(pte)) { | ||
1105 | if (page->role.level == PT_PAGE_TABLE_LEVEL) | ||
1106 | rmap_remove(vcpu, spte); | ||
1107 | else { | ||
1108 | child = page_header(pte & PT64_BASE_ADDR_MASK); | ||
1109 | mmu_page_remove_parent_pte(vcpu, child, spte); | ||
1110 | } | ||
1111 | } | ||
1112 | *spte = 0; | ||
1113 | } | ||
1114 | |||
1096 | void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes) | 1115 | void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes) |
1097 | { | 1116 | { |
1098 | gfn_t gfn = gpa >> PAGE_SHIFT; | 1117 | gfn_t gfn = gpa >> PAGE_SHIFT; |
1099 | struct kvm_mmu_page *page; | 1118 | struct kvm_mmu_page *page; |
1100 | struct kvm_mmu_page *child; | ||
1101 | struct hlist_node *node, *n; | 1119 | struct hlist_node *node, *n; |
1102 | struct hlist_head *bucket; | 1120 | struct hlist_head *bucket; |
1103 | unsigned index; | 1121 | unsigned index; |
1104 | u64 *spte; | 1122 | u64 *spte; |
1105 | u64 pte; | ||
1106 | unsigned offset = offset_in_page(gpa); | 1123 | unsigned offset = offset_in_page(gpa); |
1107 | unsigned pte_size; | 1124 | unsigned pte_size; |
1108 | unsigned page_offset; | 1125 | unsigned page_offset; |
1109 | unsigned misaligned; | 1126 | unsigned misaligned; |
1110 | int level; | 1127 | int level; |
1111 | int flooded = 0; | 1128 | int flooded = 0; |
1129 | int npte; | ||
1112 | 1130 | ||
1113 | pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); | 1131 | pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); |
1114 | if (gfn == vcpu->last_pt_write_gfn) { | 1132 | if (gfn == vcpu->last_pt_write_gfn) { |
@@ -1144,22 +1162,26 @@ void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes) | |||
1144 | } | 1162 | } |
1145 | page_offset = offset; | 1163 | page_offset = offset; |
1146 | level = page->role.level; | 1164 | level = page->role.level; |
1165 | npte = 1; | ||
1147 | if (page->role.glevels == PT32_ROOT_LEVEL) { | 1166 | if (page->role.glevels == PT32_ROOT_LEVEL) { |
1148 | page_offset <<= 1; /* 32->64 */ | 1167 | page_offset <<= 1; /* 32->64 */ |
1168 | /* | ||
1169 | * A 32-bit pde maps 4MB while the shadow pdes map | ||
1170 | * only 2MB. So we need to double the offset again | ||
1171 | * and zap two pdes instead of one. | ||
1172 | */ | ||
1173 | if (level == PT32_ROOT_LEVEL) { | ||
1174 | page_offset <<= 1; | ||
1175 | npte = 2; | ||
1176 | } | ||
1149 | page_offset &= ~PAGE_MASK; | 1177 | page_offset &= ~PAGE_MASK; |
1150 | } | 1178 | } |
1151 | spte = __va(page->page_hpa); | 1179 | spte = __va(page->page_hpa); |
1152 | spte += page_offset / sizeof(*spte); | 1180 | spte += page_offset / sizeof(*spte); |
1153 | pte = *spte; | 1181 | while (npte--) { |
1154 | if (is_present_pte(pte)) { | 1182 | mmu_pre_write_zap_pte(vcpu, page, spte); |
1155 | if (level == PT_PAGE_TABLE_LEVEL) | 1183 | ++spte; |
1156 | rmap_remove(vcpu, spte); | ||
1157 | else { | ||
1158 | child = page_header(pte & PT64_BASE_ADDR_MASK); | ||
1159 | mmu_page_remove_parent_pte(vcpu, child, spte); | ||
1160 | } | ||
1161 | } | 1184 | } |
1162 | *spte = 0; | ||
1163 | } | 1185 | } |
1164 | } | 1186 | } |
1165 | 1187 | ||
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index c07178e61122..bfa0ce42ea92 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -371,10 +371,10 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) | |||
371 | data = vmcs_read32(GUEST_SYSENTER_CS); | 371 | data = vmcs_read32(GUEST_SYSENTER_CS); |
372 | break; | 372 | break; |
373 | case MSR_IA32_SYSENTER_EIP: | 373 | case MSR_IA32_SYSENTER_EIP: |
374 | data = vmcs_read32(GUEST_SYSENTER_EIP); | 374 | data = vmcs_readl(GUEST_SYSENTER_EIP); |
375 | break; | 375 | break; |
376 | case MSR_IA32_SYSENTER_ESP: | 376 | case MSR_IA32_SYSENTER_ESP: |
377 | data = vmcs_read32(GUEST_SYSENTER_ESP); | 377 | data = vmcs_readl(GUEST_SYSENTER_ESP); |
378 | break; | 378 | break; |
379 | default: | 379 | default: |
380 | msr = find_msr_entry(vcpu, msr_index); | 380 | msr = find_msr_entry(vcpu, msr_index); |
@@ -412,10 +412,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) | |||
412 | vmcs_write32(GUEST_SYSENTER_CS, data); | 412 | vmcs_write32(GUEST_SYSENTER_CS, data); |
413 | break; | 413 | break; |
414 | case MSR_IA32_SYSENTER_EIP: | 414 | case MSR_IA32_SYSENTER_EIP: |
415 | vmcs_write32(GUEST_SYSENTER_EIP, data); | 415 | vmcs_writel(GUEST_SYSENTER_EIP, data); |
416 | break; | 416 | break; |
417 | case MSR_IA32_SYSENTER_ESP: | 417 | case MSR_IA32_SYSENTER_ESP: |
418 | vmcs_write32(GUEST_SYSENTER_ESP, data); | 418 | vmcs_writel(GUEST_SYSENTER_ESP, data); |
419 | break; | 419 | break; |
420 | case MSR_IA32_TIME_STAMP_COUNTER: | 420 | case MSR_IA32_TIME_STAMP_COUNTER: |
421 | guest_write_tsc(data); | 421 | guest_write_tsc(data); |