ia64/xen-unstable

view xen/arch/x86/audit.c @ 7698:d25bdfb2576e

Fixed a bug in the audit code.
We don't hold a type refcount to the user's ptbase frame in
shadow refcounting mode.
author mafetter@seana.research.intel-research.net
date Tue Nov 08 11:36:55 2005 +0100 (2005-11-08)
parents 9b51e7637676
children c7508abc5b6b
line source
1 /******************************************************************************
2 * arch/x86/audit.c
3 *
4 * Copyright (c) 2002-2005 K A Fraser
5 * Copyright (c) 2004 Christian Limpach
6 * Copyright (c) 2005 Michael A Fetterman
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
23 #include <xen/config.h>
24 #include <xen/init.h>
25 #include <xen/kernel.h>
26 #include <xen/lib.h>
27 #include <xen/mm.h>
28 #include <xen/perfc.h>
29 #include <asm/shadow.h>
30 #include <asm/page.h>
31 #include <asm/flushtlb.h>
33 /* XXX SMP bug -- these should not be statics... */
34 static int ttot=0, ctot=0, io_mappings=0, lowmem_mappings=0;
35 static int l1, l2, oos_count, page_count;
37 #define FILE_AND_LINE 0
39 #if FILE_AND_LINE
40 #define adjust(_p, _a) _adjust((_p), (_a), __FILE__, __LINE__)
41 #define ADJUST_EXTRA_ARGS ,const char *file, int line
42 #define APRINTK(_f, _a...) printk(_f " %s:%d\n", ## _a, file, line)
43 #else
44 #define adjust _adjust
45 #define ADJUST_EXTRA_ARGS
46 #define APRINTK(_f, _a...) printk(_f "\n", ##_a)
47 #endif
49 int audit_adjust_pgtables(struct domain *d, int dir, int noisy)
50 {
51 int errors = 0;
52 int shadow_refcounts = !!shadow_mode_refcounts(d);
53 int shadow_enabled = !!shadow_mode_enabled(d);
54 int l2limit;
56 void _adjust(struct pfn_info *page, int adjtype ADJUST_EXTRA_ARGS)
57 {
58 if ( adjtype )
59 {
60 // adjust the type count
61 //
62 int tcount = page->u.inuse.type_info & PGT_count_mask;
63 tcount += dir;
64 ttot++;
66 if ( page_get_owner(page) == NULL )
67 {
68 APRINTK("adjust(mfn=%lx, dir=%d, adjtype=%d) owner=NULL",
69 page_to_pfn(page), dir, adjtype);
70 errors++;
71 }
73 if ( tcount < 0 )
74 {
75 APRINTK("Audit %d: type count went below zero "
76 "mfn=%lx t=%" PRtype_info " ot=%x",
77 d->domain_id, page_to_pfn(page),
78 page->u.inuse.type_info,
79 page->tlbflush_timestamp);
80 errors++;
81 }
82 else if ( (tcount & ~PGT_count_mask) != 0 )
83 {
84 APRINTK("Audit %d: type count overflowed "
85 "mfn=%lx t=%" PRtype_info " ot=%x",
86 d->domain_id, page_to_pfn(page),
87 page->u.inuse.type_info,
88 page->tlbflush_timestamp);
89 errors++;
90 }
91 else
92 page->u.inuse.type_info += dir;
93 }
95 // adjust the general count
96 //
97 int count = page->count_info & PGC_count_mask;
98 count += dir;
99 ctot++;
101 if ( count < 0 )
102 {
103 APRINTK("Audit %d: general count went below zero "
104 "mfn=%lx t=%" PRtype_info " ot=%x",
105 d->domain_id, page_to_pfn(page),
106 page->u.inuse.type_info,
107 page->tlbflush_timestamp);
108 errors++;
109 }
110 else if ( (count & ~PGT_count_mask) != 0 )
111 {
112 APRINTK("Audit %d: general count overflowed "
113 "mfn=%lx t=%" PRtype_info " ot=%x",
114 d->domain_id, page_to_pfn(page),
115 page->u.inuse.type_info,
116 page->tlbflush_timestamp);
117 errors++;
118 }
119 else
120 page->count_info += dir;
121 }
123 void adjust_l2_page(unsigned long mfn, int shadow)
124 {
125 unsigned long *pt = map_domain_page(mfn);
126 int i;
128 for ( i = 0; i < l2limit; i++ )
129 {
130 if ( pt[i] & _PAGE_PRESENT )
131 {
132 unsigned long l1mfn = pt[i] >> PAGE_SHIFT;
133 struct pfn_info *l1page = pfn_to_page(l1mfn);
135 if ( noisy )
136 {
137 if ( shadow )
138 {
139 if ( page_get_owner(l1page) != NULL )
140 {
141 printk("L2: Bizarre shadow L1 page mfn=%lx "
142 "belonging to a domain %p (id=%d)\n",
143 l1mfn,
144 page_get_owner(l1page),
145 page_get_owner(l1page)->domain_id);
146 errors++;
147 continue;
148 }
150 u32 page_type = l1page->u.inuse.type_info & PGT_type_mask;
152 if ( page_type != PGT_l1_shadow )
153 {
154 printk("Audit %d: [Shadow L2 mfn=%lx i=%x] "
155 "Expected Shadow L1 t=%" PRtype_info
156 " mfn=%lx\n",
157 d->domain_id, mfn, i,
158 l1page->u.inuse.type_info, l1mfn);
159 errors++;
160 }
161 }
162 else
163 {
164 if ( page_get_owner(l1page) != d )
165 {
166 printk("L2: Skip bizarre L1 page mfn=%lx "
167 "belonging to other dom %p (id=%d)\n",
168 l1mfn,
169 page_get_owner(l1page),
170 (page_get_owner(l1page)
171 ? page_get_owner(l1page)->domain_id
172 : -1));
173 errors++;
174 continue;
175 }
177 u32 page_type = l1page->u.inuse.type_info & PGT_type_mask;
179 if ( page_type == PGT_l2_page_table )
180 {
181 printk("Audit %d: [%x] Found %s Linear PT "
182 "t=%" PRtype_info " mfn=%lx\n",
183 d->domain_id, i, (l1mfn==mfn) ? "Self" : "Other",
184 l1page->u.inuse.type_info, l1mfn);
185 }
186 else if ( page_type != PGT_l1_page_table )
187 {
188 printk("Audit %d: [L2 mfn=%lx i=%x] "
189 "Expected L1 t=%" PRtype_info " mfn=%lx\n",
190 d->domain_id, mfn, i,
191 l1page->u.inuse.type_info, l1mfn);
192 errors++;
193 }
194 }
195 }
197 adjust(l1page, !shadow);
198 }
199 }
201 if ( shadow_mode_translate(d) && !shadow_mode_external(d) )
202 {
203 unsigned long hl2mfn =
204 pt[l2_table_offset(LINEAR_PT_VIRT_START)] >> PAGE_SHIFT;
205 struct pfn_info *hl2page = pfn_to_page(hl2mfn);
206 adjust(hl2page, 0);
207 }
209 unmap_domain_page(pt);
210 }
212 void adjust_hl2_page(unsigned long hl2mfn)
213 {
214 unsigned long *pt = map_domain_page(hl2mfn);
215 int i;
217 for ( i = 0; i < l2limit; i++ )
218 {
219 if ( pt[i] & _PAGE_PRESENT )
220 {
221 unsigned long gmfn = pt[i] >> PAGE_SHIFT;
222 struct pfn_info *gpage = pfn_to_page(gmfn);
224 if ( gmfn < 0x100 )
225 {
226 lowmem_mappings++;
227 continue;
228 }
230 if ( gmfn > max_page )
231 {
232 io_mappings++;
233 continue;
234 }
236 if ( noisy )
237 {
238 if ( page_get_owner(gpage) != d )
239 {
240 printk("Audit %d: [hl2mfn=%lx,i=%x] Skip foreign page "
241 "dom=%p (id=%d) mfn=%lx c=%08x t=%"
242 PRtype_info "\n",
243 d->domain_id, hl2mfn, i,
244 page_get_owner(gpage),
245 page_get_owner(gpage)->domain_id,
246 gmfn,
247 gpage->count_info,
248 gpage->u.inuse.type_info);
249 continue;
250 }
251 }
252 adjust(gpage, 0);
253 }
254 }
256 unmap_domain_page(pt);
257 }
259 void adjust_l1_page(unsigned long l1mfn)
260 {
261 unsigned long *pt = map_domain_page(l1mfn);
262 int i;
264 for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
265 {
266 if ( pt[i] & _PAGE_PRESENT )
267 {
268 unsigned long gmfn = pt[i] >> PAGE_SHIFT;
269 struct pfn_info *gpage = pfn_to_page(gmfn);
271 if ( gmfn < 0x100 )
272 {
273 lowmem_mappings++;
274 continue;
275 }
277 if ( gmfn > max_page )
278 {
279 io_mappings++;
280 continue;
281 }
283 if ( noisy )
284 {
285 if ( pt[i] & _PAGE_RW )
286 {
287 // If it's not a writable page, complain.
288 //
289 if ( !((gpage->u.inuse.type_info & PGT_type_mask) ==
290 PGT_writable_page) )
291 {
292 printk("Audit %d: [l1mfn=%lx, i=%x] Illegal RW "
293 "t=%" PRtype_info " mfn=%lx\n",
294 d->domain_id, l1mfn, i,
295 gpage->u.inuse.type_info, gmfn);
296 errors++;
297 }
299 if ( shadow_refcounts &&
300 page_is_page_table(gpage) &&
301 ! page_out_of_sync(gpage) )
302 {
303 printk("Audit %d: [l1mfn=%lx, i=%x] Illegal RW of "
304 "page table gmfn=%lx\n",
305 d->domain_id, l1mfn, i, gmfn);
306 errors++;
307 }
308 }
310 if ( page_get_owner(gpage) != d )
311 {
312 printk("Audit %d: [l1mfn=%lx,i=%x] Skip foreign page "
313 "dom=%p (id=%d) mfn=%lx c=%08x t=%"
314 PRtype_info "\n",
315 d->domain_id, l1mfn, i,
316 page_get_owner(gpage),
317 page_get_owner(gpage)->domain_id,
318 gmfn,
319 gpage->count_info,
320 gpage->u.inuse.type_info);
321 continue;
322 }
323 }
325 adjust(gpage, (pt[i] & _PAGE_RW) ? 1 : 0);
326 }
327 }
329 unmap_domain_page(pt);
330 }
332 void adjust_shadow_tables()
333 {
334 struct shadow_status *a;
335 unsigned long smfn, gmfn;
336 struct pfn_info *page;
337 int i;
339 for ( i = 0; i < shadow_ht_buckets; i++ )
340 {
341 a = &d->arch.shadow_ht[i];
342 while ( a && a->gpfn_and_flags )
343 {
344 gmfn = __gpfn_to_mfn(d, a->gpfn_and_flags & PGT_mfn_mask);
345 smfn = a->smfn;
346 page = &frame_table[smfn];
348 switch ( a->gpfn_and_flags & PGT_type_mask ) {
349 case PGT_writable_pred:
350 break;
351 case PGT_snapshot:
352 adjust(pfn_to_page(gmfn), 0);
353 break;
354 case PGT_l1_shadow:
355 adjust(pfn_to_page(gmfn), 0);
356 if ( shadow_refcounts )
357 adjust_l1_page(smfn);
358 if ( page->u.inuse.type_info & PGT_pinned )
359 adjust(page, 0);
360 break;
361 case PGT_hl2_shadow:
362 adjust(pfn_to_page(gmfn), 0);
363 if ( shadow_refcounts )
364 adjust_hl2_page(smfn);
365 if ( page->u.inuse.type_info & PGT_pinned )
366 adjust(page, 0);
367 break;
368 case PGT_l2_shadow:
369 adjust(pfn_to_page(gmfn), 0);
370 adjust_l2_page(smfn, 1);
371 if ( page->u.inuse.type_info & PGT_pinned )
372 adjust(page, 0);
373 break;
374 default:
375 BUG();
376 break;
377 }
379 a = a->next;
380 }
381 }
382 }
384 void adjust_oos_list()
385 {
386 struct out_of_sync_entry *oos;
388 if ( (oos = d->arch.out_of_sync) )
389 ASSERT(shadow_enabled);
391 while ( oos )
392 {
393 adjust(pfn_to_page(oos->gmfn), 0);
395 // Only use entries that have low bits clear...
396 //
397 if ( !(oos->writable_pl1e & (sizeof(l1_pgentry_t)-1)) )
398 adjust(pfn_to_page(oos->writable_pl1e >> PAGE_SHIFT), 0);
400 if ( oos->snapshot_mfn != SHADOW_SNAPSHOT_ELSEWHERE )
401 adjust(pfn_to_page(oos->snapshot_mfn), 0);
403 oos = oos->next;
404 oos_count++;
405 }
406 }
408 void adjust_for_pgtbase()
409 {
410 struct vcpu *v;
412 for_each_vcpu(d, v)
413 {
414 if ( pagetable_get_paddr(v->arch.guest_table) )
415 adjust(&frame_table[pagetable_get_pfn(v->arch.guest_table)], !shadow_mode_refcounts(d));
416 if ( pagetable_get_paddr(v->arch.shadow_table) )
417 adjust(&frame_table[pagetable_get_pfn(v->arch.shadow_table)], 0);
418 if ( v->arch.monitor_shadow_ref )
419 adjust(&frame_table[v->arch.monitor_shadow_ref], 0);
420 }
421 }
423 void adjust_guest_pages()
424 {
425 struct list_head *list_ent = d->page_list.next;
426 struct pfn_info *page;
427 unsigned long mfn, snapshot_mfn;
429 while ( list_ent != &d->page_list )
430 {
431 u32 page_type;
433 page = list_entry(list_ent, struct pfn_info, list);
434 snapshot_mfn = mfn = page_to_pfn(page);
435 page_type = page->u.inuse.type_info & PGT_type_mask;
437 BUG_ON(page_get_owner(page) != d);
439 page_count++;
441 if ( shadow_enabled && !shadow_refcounts &&
442 page_out_of_sync(page) )
443 {
444 unsigned long gpfn = __mfn_to_gpfn(d, mfn);
445 ASSERT( VALID_M2P(gpfn) );
446 snapshot_mfn = __shadow_status(d, gpfn, PGT_snapshot);
447 ASSERT( snapshot_mfn );
448 }
450 switch ( page_type )
451 {
452 case PGT_l2_page_table:
453 l2++;
455 if ( noisy )
456 {
457 if ( shadow_refcounts )
458 {
459 printk("Audit %d: found an L2 guest page "
460 "mfn=%lx t=%" PRtype_info " c=%08x while in shadow mode\n",
461 d->domain_id, mfn, page->u.inuse.type_info,
462 page->count_info);
463 errors++;
464 }
466 if ( (page->u.inuse.type_info & PGT_count_mask) != 0 )
467 {
468 if ( (page->u.inuse.type_info & PGT_validated) !=
469 PGT_validated )
470 {
471 printk("Audit %d: L2 mfn=%lx not validated %"
472 PRtype_info "\n",
473 d->domain_id, mfn, page->u.inuse.type_info);
474 errors++;
475 }
477 if ( (page->u.inuse.type_info & PGT_pinned) != PGT_pinned )
478 {
479 printk("Audit %d: L2 mfn=%lx not pinned t=%"
480 PRtype_info "\n",
481 d->domain_id, mfn, page->u.inuse.type_info);
482 errors++;
483 }
484 }
485 }
487 if ( page->u.inuse.type_info & PGT_pinned )
488 adjust(page, 1);
490 if ( page->u.inuse.type_info & PGT_validated )
491 adjust_l2_page(snapshot_mfn, 0);
493 break;
495 case PGT_l1_page_table:
496 l1++;
498 if ( noisy )
499 {
500 if ( shadow_refcounts )
501 {
502 printk("found an L1 guest page mfn=%lx t=%"
503 PRtype_info " c=%08x "
504 "while in shadow mode\n",
505 mfn, page->u.inuse.type_info, page->count_info);
506 errors++;
507 }
509 if ( (page->u.inuse.type_info & PGT_count_mask) != 0 )
510 {
511 if ( (page->u.inuse.type_info & PGT_validated) !=
512 PGT_validated )
513 {
514 printk("Audit %d: L1 not validated mfn=%lx t=%"
515 PRtype_info "\n",
516 d->domain_id, mfn, page->u.inuse.type_info);
517 errors++;
518 }
519 }
520 }
522 if ( page->u.inuse.type_info & PGT_pinned )
523 adjust(page, 1);
525 if ( page->u.inuse.type_info & PGT_validated )
526 adjust_l1_page(snapshot_mfn);
528 break;
530 case PGT_gdt_page:
531 ASSERT( !page_out_of_sync(page) );
532 adjust(page, 1);
533 break;
535 case PGT_ldt_page:
536 ASSERT( !page_out_of_sync(page) );
537 adjust(page, 1);
538 break;
540 case PGT_writable_page:
541 if ( shadow_refcounts )
542 {
543 // In shadow mode, writable pages can get pinned by
544 // paravirtualized guests that think they are pinning
545 // their L1s and/or L2s.
546 //
547 if ( page->u.inuse.type_info & PGT_pinned )
548 adjust(page, 1);
549 }
550 }
552 list_ent = page->list.next;
553 }
554 }
556 #ifdef __i386__
557 if ( shadow_mode_external(d) )
558 l2limit = L2_PAGETABLE_ENTRIES;
559 else
560 l2limit = DOMAIN_ENTRIES_PER_L2_PAGETABLE;
561 #else
562 l2limit = 0; /* XXX x86/64 XXX */
563 #endif
565 adjust_for_pgtbase();
567 adjust_guest_pages();
569 if ( shadow_enabled )
570 {
571 adjust_oos_list();
572 adjust_shadow_tables();
573 }
575 adjust(virt_to_page(d->shared_info), 1);
577 return errors;
578 }
581 #ifndef NDEBUG
583 void audit_pagelist(struct domain *d)
584 {
585 struct list_head *list_ent;
586 int xenpages, totpages;
588 list_ent = d->xenpage_list.next;
589 for ( xenpages = 0; (list_ent != &d->xenpage_list); xenpages++ )
590 {
591 list_ent = list_ent->next;
592 }
593 list_ent = d->page_list.next;
594 for ( totpages = 0; (list_ent != &d->page_list); totpages++ )
595 {
596 list_ent = list_ent->next;
597 }
599 if ( xenpages != d->xenheap_pages ||
600 totpages != d->tot_pages )
601 {
602 printk("ARGH! dom %d: xen=%d %d, pages=%d %d\n", d->domain_id,
603 xenpages, d->xenheap_pages,
604 totpages, d->tot_pages );
605 }
606 }
608 void _audit_domain(struct domain *d, int flags)
609 {
610 int shadow_refcounts = !!shadow_mode_refcounts(d);
612 void scan_for_pfn_in_mfn(struct domain *d, unsigned long xmfn,
613 unsigned long mfn)
614 {
615 struct pfn_info *page = &frame_table[mfn];
616 unsigned long *pt = map_domain_page(mfn);
617 int i;
619 for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
620 {
621 if ( (pt[i] & _PAGE_PRESENT) && ((pt[i] >> PAGE_SHIFT) == xmfn) )
622 printk(" found dom=%d mfn=%lx t=%" PRtype_info " c=%08x "
623 "pt[i=%x]=%lx\n",
624 d->domain_id, mfn, page->u.inuse.type_info,
625 page->count_info, i, pt[i]);
626 }
628 unmap_domain_page(pt);
629 }
631 void scan_for_pfn_in_grant_table(struct domain *d, unsigned xmfn)
632 {
633 int i;
634 active_grant_entry_t *act = d->grant_table->active;
636 spin_lock(&d->grant_table->lock);
638 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
639 {
640 if ( act[i].pin && (act[i].frame == xmfn) )
641 {
642 printk(" found active grant table entry i=%d dom=%d pin=%d\n",
643 i, act[i].domid, act[i].pin);
644 }
645 }
647 spin_unlock(&d->grant_table->lock);
648 }
650 void scan_for_pfn(struct domain *d, unsigned long xmfn)
651 {
652 scan_for_pfn_in_grant_table(d, xmfn);
654 if ( !shadow_mode_enabled(d) )
655 {
656 struct list_head *list_ent = d->page_list.next;
657 struct pfn_info *page;
659 while ( list_ent != &d->page_list )
660 {
661 page = list_entry(list_ent, struct pfn_info, list);
663 switch ( page->u.inuse.type_info & PGT_type_mask )
664 {
665 case PGT_l1_page_table:
666 case PGT_l2_page_table:
667 scan_for_pfn_in_mfn(d, xmfn, page_to_pfn(page));
668 break;
669 default:
670 break;
671 }
673 list_ent = page->list.next;
674 }
675 }
676 else
677 {
678 struct shadow_status *a;
679 int i;
681 for ( i = 0; i < shadow_ht_buckets; i++ )
682 {
683 a = &d->arch.shadow_ht[i];
684 while ( a && a->gpfn_and_flags )
685 {
686 switch ( a->gpfn_and_flags & PGT_type_mask )
687 {
688 case PGT_l1_shadow:
689 case PGT_l2_shadow:
690 case PGT_hl2_shadow:
691 scan_for_pfn_in_mfn(d, xmfn, a->smfn);
692 break;
693 case PGT_snapshot:
694 case PGT_writable_pred:
695 break;
696 default:
697 BUG();
698 break;
699 }
700 a = a->next;
701 }
702 }
703 }
704 }
706 void scan_for_pfn_remote(unsigned long xmfn)
707 {
708 struct domain *e;
709 for_each_domain ( e )
710 scan_for_pfn( e, xmfn );
711 }
713 unsigned long mfn;
714 struct list_head *list_ent;
715 struct pfn_info *page;
716 int errors = 0;
718 if ( (d != current->domain) && shadow_mode_translate(d) )
719 {
720 printk("skipping audit domain of translated domain %d "
721 "from other context\n",
722 d->domain_id);
723 return;
724 }
726 if ( d != current->domain )
727 domain_pause(d);
729 // Maybe we should just be using BIGLOCK?
730 //
731 if ( !(flags & AUDIT_SHADOW_ALREADY_LOCKED) )
732 shadow_lock(d);
734 spin_lock(&d->page_alloc_lock);
736 audit_pagelist(d);
738 /* PHASE 0 */
740 list_ent = d->page_list.next;
741 while ( list_ent != &d->page_list )
742 {
743 u32 page_type;
745 page = list_entry(list_ent, struct pfn_info, list);
746 mfn = page_to_pfn(page);
747 page_type = page->u.inuse.type_info & PGT_type_mask;
749 BUG_ON(page_get_owner(page) != d);
751 if ( (page->u.inuse.type_info & PGT_count_mask) >
752 (page->count_info & PGC_count_mask) )
753 {
754 printk("taf(%" PRtype_info ") > caf(%08x) mfn=%lx\n",
755 page->u.inuse.type_info, page->count_info, mfn);
756 errors++;
757 }
759 if ( shadow_mode_refcounts(d) &&
760 (page_type == PGT_writable_page) &&
761 !(page->u.inuse.type_info & PGT_validated) )
762 {
763 printk("shadow mode writable page not validated mfn=%lx "
764 "t=%" PRtype_info " c=%08x\n",
765 mfn, page->u.inuse.type_info, page->count_info);
766 errors++;
767 }
769 #if 0 /* SYSV shared memory pages plus writeable files. */
770 if ( page_type == PGT_writable_page &&
771 (page->u.inuse.type_info & PGT_count_mask) > 1 )
772 {
773 printk("writeable page with type count >1: "
774 "mfn=%lx t=%" PRtype_info " c=%08x\n",
775 mfn,
776 page->u.inuse.type_info,
777 page->count_info );
778 errors++;
779 scan_for_pfn_remote(mfn);
780 }
781 #endif
783 if ( page_type == PGT_none &&
784 (page->u.inuse.type_info & PGT_count_mask) > 0 )
785 {
786 printk("normal page with type count >0: mfn=%lx t=%" PRtype_info " c=%08x\n",
787 mfn,
788 page->u.inuse.type_info,
789 page->count_info );
790 errors++;
791 }
793 if ( page_out_of_sync(page) )
794 {
795 if ( !page_is_page_table(page) )
796 {
797 printk("out of sync page mfn=%lx is not a page table\n", mfn);
798 errors++;
799 }
800 unsigned long pfn = __mfn_to_gpfn(d, mfn);
801 if ( !__shadow_status(d, pfn, PGT_snapshot) )
802 {
803 printk("out of sync page mfn=%lx doesn't have a snapshot\n",
804 mfn);
805 errors++;
806 }
807 if ( shadow_refcounts
808 ? (page_type != PGT_writable_page)
809 : !(page_type && (page_type <= PGT_l4_page_table)) )
810 {
811 printk("out of sync page mfn=%lx has strange type "
812 "t=%" PRtype_info " c=%08x\n",
813 mfn, page->u.inuse.type_info, page->count_info);
814 errors++;
815 }
816 }
818 /* Use tlbflush_timestamp to store original type_info. */
819 page->tlbflush_timestamp = page->u.inuse.type_info;
821 list_ent = page->list.next;
822 }
824 /* PHASE 1 */
825 io_mappings = lowmem_mappings = 0;
827 errors += audit_adjust_pgtables(d, -1, 1);
829 if ( !(flags & AUDIT_QUIET) &&
830 ((io_mappings > 0) || (lowmem_mappings > 0)) )
831 printk("Audit %d: Found %d lowmem mappings and %d io mappings\n",
832 d->domain_id, lowmem_mappings, io_mappings);
834 /* PHASE 2 */
836 list_ent = d->page_list.next;
837 while ( list_ent != &d->page_list )
838 {
839 page = list_entry(list_ent, struct pfn_info, list);
840 mfn = page_to_pfn(page);
842 switch ( page->u.inuse.type_info & PGT_type_mask)
843 {
844 case PGT_l1_page_table:
845 case PGT_l2_page_table:
846 case PGT_l3_page_table:
847 case PGT_l4_page_table:
848 if ( (page->u.inuse.type_info & PGT_count_mask) != 0 )
849 {
850 printk("Audit %d: type count!=0 t=%" PRtype_info " ot=%x c=%x mfn=%lx\n",
851 d->domain_id, page->u.inuse.type_info,
852 page->tlbflush_timestamp,
853 page->count_info, mfn);
854 errors++;
855 scan_for_pfn_remote(mfn);
856 }
857 break;
858 case PGT_none:
859 case PGT_writable_page:
860 case PGT_gdt_page:
861 case PGT_ldt_page:
862 if ( (page->u.inuse.type_info & PGT_count_mask) != 0 )
863 {
864 printk("Audit %d: type count!=0 t=%" PRtype_info " ot=%x c=%x mfn=%lx\n",
865 d->domain_id, page->u.inuse.type_info,
866 page->tlbflush_timestamp,
867 page->count_info, mfn);
868 //errors++;
869 }
870 break;
871 default:
872 BUG(); // XXX fix me...
873 }
875 if ( (page->count_info & PGC_count_mask) != 1 )
876 {
877 printk("Audit %d: gen count!=1 (c=%x) t=%" PRtype_info " ot=%x mfn=%lx\n",
878 d->domain_id,
879 page->count_info,
880 page->u.inuse.type_info,
881 page->tlbflush_timestamp, mfn );
882 //errors++;
883 scan_for_pfn_remote(mfn);
884 }
886 list_ent = page->list.next;
887 }
889 if ( shadow_mode_enabled(d) )
890 {
891 struct shadow_status *a;
892 struct pfn_info *page;
893 u32 page_type;
894 int i;
896 for ( i = 0; i < shadow_ht_buckets; i++ )
897 {
898 a = &d->arch.shadow_ht[i];
899 while ( a && a->gpfn_and_flags )
900 {
901 page = pfn_to_page(a->smfn);
902 page_type = a->gpfn_and_flags & PGT_type_mask;
904 switch ( page_type ) {
905 case PGT_l1_shadow:
906 case PGT_l2_shadow:
907 case PGT_hl2_shadow:
908 case PGT_snapshot:
909 if ( ((page->u.inuse.type_info & PGT_type_mask) != page_type ) ||
910 (page->count_info != 0) )
911 {
912 printk("Audit %d: shadow page counts wrong "
913 "mfn=%lx t=%" PRtype_info " c=%08x\n",
914 d->domain_id, page_to_pfn(page),
915 page->u.inuse.type_info,
916 page->count_info);
917 printk("a->gpfn_and_flags=%p\n",
918 (void *)a->gpfn_and_flags);
919 errors++;
920 }
921 break;
922 case PGT_writable_pred:
923 // XXX - nothing to check?
924 break;
926 default:
927 BUG();
928 break;
929 }
931 a = a->next;
932 }
933 }
934 }
936 /* PHASE 3 */
937 ctot = ttot = page_count = l1 = l2 = oos_count = 0;
939 audit_adjust_pgtables(d, 1, 0);
941 #if 0
942 // This covers our sins of trashing the tlbflush_timestamps...
943 //
944 local_flush_tlb();
945 #endif
947 spin_unlock(&d->page_alloc_lock);
949 if ( !(flags & AUDIT_QUIET) )
950 printk("Audit dom%d Done. "
951 "pages=%d oos=%d l1=%d l2=%d ctot=%d ttot=%d\n",
952 d->domain_id, page_count, oos_count, l1, l2, ctot, ttot);
954 if ( !(flags & AUDIT_SHADOW_ALREADY_LOCKED) )
955 shadow_unlock(d);
957 if ( d != current->domain )
958 domain_unpause(d);
960 if ( errors && !(flags & AUDIT_ERRORS_OK) )
961 BUG();
962 }
964 void audit_domains(void)
965 {
966 struct domain *d;
967 for_each_domain ( d )
968 audit_domain(d);
969 }
971 void audit_domains_key(unsigned char key)
972 {
973 audit_domains();
974 }
975 #endif