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); |
