aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-18 14:08:52 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-18 14:08:52 -0400
commit10bd6b3fc4a4bdeb599495700e97722d18d36609 (patch)
tree4b0b28756162cc211c941ebd1e846c779399bd82
parent98ae6878f151b0b508b09a36367c231b707a88cf (diff)
parent27aba76615eeb36af84118e8ea6d35ffa51fd1e3 (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.c4
-rw-r--r--drivers/kvm/mmu.c52
-rw-r--r--drivers/kvm/vmx.c8
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:
2500out_free_1: 2500out_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();
2503out:
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
1096static 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
1096void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes) 1115void 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);