aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/mmu.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2008-08-22 12:28:04 -0400
committerAvi Kivity <avi@qumranet.com>2008-10-15 04:15:23 -0400
commit140754bc80e1cdbf2d14cdb10d900da1f7718e7b (patch)
tree0b23b396c28da5b01b6693546dca9416a88ded54 /arch/x86/kvm/mmu.c
parent3d000db5688c8beff6319fb9ff4b98dcac32f798 (diff)
KVM: MMU: Convert direct maps to use the generic shadow walker
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/x86/kvm/mmu.c')
-rw-r--r--arch/x86/kvm/mmu.c93
1 files changed, 55 insertions, 38 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 8b95cf748b53..a1ca4ff9c116 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -1260,49 +1260,66 @@ static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
1260{ 1260{
1261} 1261}
1262 1262
1263static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, 1263struct direct_shadow_walk {
1264 int largepage, gfn_t gfn, pfn_t pfn) 1264 struct kvm_shadow_walk walker;
1265{ 1265 pfn_t pfn;
1266 hpa_t table_addr = vcpu->arch.mmu.root_hpa; 1266 int write;
1267 int pt_write = 0; 1267 int largepage;
1268 int level = vcpu->arch.mmu.shadow_root_level; 1268 int pt_write;
1269 1269};
1270 for (; ; level--) {
1271 u32 index = PT64_INDEX(v, level);
1272 u64 *table;
1273 1270
1274 ASSERT(VALID_PAGE(table_addr)); 1271static int direct_map_entry(struct kvm_shadow_walk *_walk,
1275 table = __va(table_addr); 1272 struct kvm_vcpu *vcpu,
1273 gva_t addr, u64 *sptep, int level)
1274{
1275 struct direct_shadow_walk *walk =
1276 container_of(_walk, struct direct_shadow_walk, walker);
1277 struct kvm_mmu_page *sp;
1278 gfn_t pseudo_gfn;
1279 gfn_t gfn = addr >> PAGE_SHIFT;
1280
1281 if (level == PT_PAGE_TABLE_LEVEL
1282 || (walk->largepage && level == PT_DIRECTORY_LEVEL)) {
1283 mmu_set_spte(vcpu, sptep, ACC_ALL, ACC_ALL,
1284 0, walk->write, 1, &walk->pt_write,
1285 walk->largepage, gfn, walk->pfn, false);
1286 return 1;
1287 }
1276 1288
1277 if (level == 1 || (largepage && level == 2)) { 1289 if (*sptep == shadow_trap_nonpresent_pte) {
1278 mmu_set_spte(vcpu, &table[index], ACC_ALL, ACC_ALL, 1290 pseudo_gfn = (addr & PT64_DIR_BASE_ADDR_MASK) >> PAGE_SHIFT;
1279 0, write, 1, &pt_write, largepage, 1291 sp = kvm_mmu_get_page(vcpu, pseudo_gfn, addr, level - 1,
1280 gfn, pfn, false); 1292 1, ACC_ALL, sptep);
1281 return pt_write; 1293 if (!sp) {
1294 pgprintk("nonpaging_map: ENOMEM\n");
1295 kvm_release_pfn_clean(walk->pfn);
1296 return -ENOMEM;
1282 } 1297 }
1283 1298
1284 if (table[index] == shadow_trap_nonpresent_pte) { 1299 set_shadow_pte(sptep,
1285 struct kvm_mmu_page *new_table; 1300 __pa(sp->spt)
1286 gfn_t pseudo_gfn; 1301 | PT_PRESENT_MASK | PT_WRITABLE_MASK
1287 1302 | shadow_user_mask | shadow_x_mask);
1288 pseudo_gfn = (v & PT64_DIR_BASE_ADDR_MASK)
1289 >> PAGE_SHIFT;
1290 new_table = kvm_mmu_get_page(vcpu, pseudo_gfn,
1291 v, level - 1,
1292 1, ACC_ALL, &table[index]);
1293 if (!new_table) {
1294 pgprintk("nonpaging_map: ENOMEM\n");
1295 kvm_release_pfn_clean(pfn);
1296 return -ENOMEM;
1297 }
1298
1299 set_shadow_pte(&table[index],
1300 __pa(new_table->spt)
1301 | PT_PRESENT_MASK | PT_WRITABLE_MASK
1302 | shadow_user_mask | shadow_x_mask);
1303 }
1304 table_addr = table[index] & PT64_BASE_ADDR_MASK;
1305 } 1303 }
1304 return 0;
1305}
1306
1307static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
1308 int largepage, gfn_t gfn, pfn_t pfn)
1309{
1310 int r;
1311 struct direct_shadow_walk walker = {
1312 .walker = { .entry = direct_map_entry, },
1313 .pfn = pfn,
1314 .largepage = largepage,
1315 .write = write,
1316 .pt_write = 0,
1317 };
1318
1319 r = walk_shadow(&walker.walker, vcpu, (gva_t)gfn << PAGE_SHIFT);
1320 if (r < 0)
1321 return r;
1322 return walker.pt_write;
1306} 1323}
1307 1324
1308static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) 1325static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn)