aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-01-05 19:36:56 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2007-01-06 02:55:27 -0500
commit37a7d8b046da6254718be1409140cd7bf3126f8f (patch)
treea52e3a60234920301c881b8b534e85ae1bed5cf8 /drivers/kvm
parent9ede74e0af549d75d4ea870bed8b178983816745 (diff)
[PATCH] KVM: MMU: add audit code to check mappings, etc are correct
Signed-off-by: Avi Kivity <avi@qumranet.com> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/kvm')
-rw-r--r--drivers/kvm/mmu.c187
-rw-r--r--drivers/kvm/paging_tmpl.h4
2 files changed, 189 insertions, 2 deletions
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 2fc252813927..6e7381bc2218 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -26,8 +26,31 @@
26#include "vmx.h" 26#include "vmx.h"
27#include "kvm.h" 27#include "kvm.h"
28 28
29#define pgprintk(x...) do { printk(x); } while (0) 29#undef MMU_DEBUG
30#define rmap_printk(x...) do { printk(x); } while (0) 30
31#undef AUDIT
32
33#ifdef AUDIT
34static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg);
35#else
36static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {}
37#endif
38
39#ifdef MMU_DEBUG
40
41#define pgprintk(x...) do { if (dbg) printk(x); } while (0)
42#define rmap_printk(x...) do { if (dbg) printk(x); } while (0)
43
44#else
45
46#define pgprintk(x...) do { } while (0)
47#define rmap_printk(x...) do { } while (0)
48
49#endif
50
51#if defined(MMU_DEBUG) || defined(AUDIT)
52static int dbg = 1;
53#endif
31 54
32#define ASSERT(x) \ 55#define ASSERT(x) \
33 if (!(x)) { \ 56 if (!(x)) { \
@@ -1271,3 +1294,163 @@ void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
1271 } 1294 }
1272 } 1295 }
1273} 1296}
1297
1298#ifdef AUDIT
1299
1300static const char *audit_msg;
1301
1302static gva_t canonicalize(gva_t gva)
1303{
1304#ifdef CONFIG_X86_64
1305 gva = (long long)(gva << 16) >> 16;
1306#endif
1307 return gva;
1308}
1309
1310static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
1311 gva_t va, int level)
1312{
1313 u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK);
1314 int i;
1315 gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1));
1316
1317 for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
1318 u64 ent = pt[i];
1319
1320 if (!ent & PT_PRESENT_MASK)
1321 continue;
1322
1323 va = canonicalize(va);
1324 if (level > 1)
1325 audit_mappings_page(vcpu, ent, va, level - 1);
1326 else {
1327 gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, va);
1328 hpa_t hpa = gpa_to_hpa(vcpu, gpa);
1329
1330 if ((ent & PT_PRESENT_MASK)
1331 && (ent & PT64_BASE_ADDR_MASK) != hpa)
1332 printk(KERN_ERR "audit error: (%s) levels %d"
1333 " gva %lx gpa %llx hpa %llx ent %llx\n",
1334 audit_msg, vcpu->mmu.root_level,
1335 va, gpa, hpa, ent);
1336 }
1337 }
1338}
1339
1340static void audit_mappings(struct kvm_vcpu *vcpu)
1341{
1342 int i;
1343
1344 if (vcpu->mmu.root_level == 4)
1345 audit_mappings_page(vcpu, vcpu->mmu.root_hpa, 0, 4);
1346 else
1347 for (i = 0; i < 4; ++i)
1348 if (vcpu->mmu.pae_root[i] & PT_PRESENT_MASK)
1349 audit_mappings_page(vcpu,
1350 vcpu->mmu.pae_root[i],
1351 i << 30,
1352 2);
1353}
1354
1355static int count_rmaps(struct kvm_vcpu *vcpu)
1356{
1357 int nmaps = 0;
1358 int i, j, k;
1359
1360 for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
1361 struct kvm_memory_slot *m = &vcpu->kvm->memslots[i];
1362 struct kvm_rmap_desc *d;
1363
1364 for (j = 0; j < m->npages; ++j) {
1365 struct page *page = m->phys_mem[j];
1366
1367 if (!page->private)
1368 continue;
1369 if (!(page->private & 1)) {
1370 ++nmaps;
1371 continue;
1372 }
1373 d = (struct kvm_rmap_desc *)(page->private & ~1ul);
1374 while (d) {
1375 for (k = 0; k < RMAP_EXT; ++k)
1376 if (d->shadow_ptes[k])
1377 ++nmaps;
1378 else
1379 break;
1380 d = d->more;
1381 }
1382 }
1383 }
1384 return nmaps;
1385}
1386
1387static int count_writable_mappings(struct kvm_vcpu *vcpu)
1388{
1389 int nmaps = 0;
1390 struct kvm_mmu_page *page;
1391 int i;
1392
1393 list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) {
1394 u64 *pt = __va(page->page_hpa);
1395
1396 if (page->role.level != PT_PAGE_TABLE_LEVEL)
1397 continue;
1398
1399 for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
1400 u64 ent = pt[i];
1401
1402 if (!(ent & PT_PRESENT_MASK))
1403 continue;
1404 if (!(ent & PT_WRITABLE_MASK))
1405 continue;
1406 ++nmaps;
1407 }
1408 }
1409 return nmaps;
1410}
1411
1412static void audit_rmap(struct kvm_vcpu *vcpu)
1413{
1414 int n_rmap = count_rmaps(vcpu);
1415 int n_actual = count_writable_mappings(vcpu);
1416
1417 if (n_rmap != n_actual)
1418 printk(KERN_ERR "%s: (%s) rmap %d actual %d\n",
1419 __FUNCTION__, audit_msg, n_rmap, n_actual);
1420}
1421
1422static void audit_write_protection(struct kvm_vcpu *vcpu)
1423{
1424 struct kvm_mmu_page *page;
1425
1426 list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) {
1427 hfn_t hfn;
1428 struct page *pg;
1429
1430 if (page->role.metaphysical)
1431 continue;
1432
1433 hfn = gpa_to_hpa(vcpu, (gpa_t)page->gfn << PAGE_SHIFT)
1434 >> PAGE_SHIFT;
1435 pg = pfn_to_page(hfn);
1436 if (pg->private)
1437 printk(KERN_ERR "%s: (%s) shadow page has writable"
1438 " mappings: gfn %lx role %x\n",
1439 __FUNCTION__, audit_msg, page->gfn,
1440 page->role.word);
1441 }
1442}
1443
1444static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg)
1445{
1446 int olddbg = dbg;
1447
1448 dbg = 0;
1449 audit_msg = msg;
1450 audit_rmap(vcpu);
1451 audit_write_protection(vcpu);
1452 audit_mappings(vcpu);
1453 dbg = olddbg;
1454}
1455
1456#endif
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 32b385188454..c894b51ba3f8 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -355,6 +355,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
355 int r; 355 int r;
356 356
357 pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code); 357 pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code);
358 kvm_mmu_audit(vcpu, "pre page fault");
358 359
359 r = mmu_topup_memory_caches(vcpu); 360 r = mmu_topup_memory_caches(vcpu);
360 if (r) 361 if (r)
@@ -402,6 +403,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
402 pgprintk("%s: io work, no access\n", __FUNCTION__); 403 pgprintk("%s: io work, no access\n", __FUNCTION__);
403 inject_page_fault(vcpu, addr, 404 inject_page_fault(vcpu, addr,
404 error_code | PFERR_PRESENT_MASK); 405 error_code | PFERR_PRESENT_MASK);
406 kvm_mmu_audit(vcpu, "post page fault (io)");
405 return 0; 407 return 0;
406 } 408 }
407 409
@@ -410,10 +412,12 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
410 */ 412 */
411 if (pte_present && !fixed && !write_pt) { 413 if (pte_present && !fixed && !write_pt) {
412 inject_page_fault(vcpu, addr, error_code); 414 inject_page_fault(vcpu, addr, error_code);
415 kvm_mmu_audit(vcpu, "post page fault (guest)");
413 return 0; 416 return 0;
414 } 417 }
415 418
416 ++kvm_stat.pf_fixed; 419 ++kvm_stat.pf_fixed;
420 kvm_mmu_audit(vcpu, "post page fault (fixed)");
417 421
418 return write_pt; 422 return write_pt;
419} 423}