diff options
author | Avi Kivity <avi@qumranet.com> | 2008-08-22 12:28:04 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-10-15 04:15:23 -0400 |
commit | 140754bc80e1cdbf2d14cdb10d900da1f7718e7b (patch) | |
tree | 0b23b396c28da5b01b6693546dca9416a88ded54 /arch/x86/kvm/mmu.c | |
parent | 3d000db5688c8beff6319fb9ff4b98dcac32f798 (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.c | 93 |
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 | ||
1263 | static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, | 1263 | struct 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)); | 1271 | static 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 | |||
1307 | static 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 | ||
1308 | static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) | 1325 | static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, int write, gfn_t gfn) |