From 53fcd3bb76db7cd90ef64d60359532e30da10f7b Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 27 Feb 2006 17:18:58 +0100 Subject: [PATCH] Allow a guest to switch pagetables 'atomically'. That is, the new pagetables do not need to be read-only in the old pagetables, and the old pagetables do not need to be read-only in the new pagetables. Signed-off-by: Keir Fraser --- xen/arch/x86/mm.c | 84 +++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index f2a5f2b257..371cc78279 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -1570,42 +1570,68 @@ int new_guest_cr3(unsigned long mfn) unsigned long old_base_mfn; if ( shadow_mode_refcounts(d) ) - okay = get_page_from_pagenr(mfn, d); - else - okay = get_page_and_type_from_pagenr(mfn, PGT_root_page_table, d); - - if ( likely(okay) ) { - invalidate_shadow_ldt(v); - - old_base_mfn = pagetable_get_pfn(v->arch.guest_table); - v->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT); - update_pagetables(v); /* update shadow_table and monitor_table */ - - write_ptbase(v); - - if ( shadow_mode_refcounts(d) ) - put_page(mfn_to_page(old_base_mfn)); - else - put_page_and_type(mfn_to_page(old_base_mfn)); - - /* CR3 also holds a ref to its shadow... */ - if ( shadow_mode_enabled(d) ) + okay = get_page_from_pagenr(mfn, d); + if ( unlikely(!okay) ) { - if ( v->arch.monitor_shadow_ref ) - put_shadow_ref(v->arch.monitor_shadow_ref); - v->arch.monitor_shadow_ref = - pagetable_get_pfn(v->arch.monitor_table); - ASSERT(!page_get_owner(mfn_to_page(v->arch.monitor_shadow_ref))); - get_shadow_ref(v->arch.monitor_shadow_ref); + MEM_LOG("Error while installing new baseptr %lx", mfn); + return 0; } } else { - MEM_LOG("Error while installing new baseptr %lx", mfn); + okay = get_page_and_type_from_pagenr(mfn, PGT_root_page_table, d); + if ( unlikely(!okay) ) + { + /* Switch to idle pagetable: this VCPU has no active p.t. now. */ + old_base_mfn = pagetable_get_pfn(v->arch.guest_table); + v->arch.guest_table = mk_pagetable(0); + update_pagetables(v); + write_cr3(__pa(idle_pg_table)); + if ( old_base_mfn != 0 ) + put_page_and_type(mfn_to_page(old_base_mfn)); + + /* Retry the validation with no active p.t. for this VCPU. */ + okay = get_page_and_type_from_pagenr(mfn, PGT_root_page_table, d); + if ( !okay ) + { + /* Failure here is unrecoverable: the VCPU has no pagetable! */ + MEM_LOG("Fatal error while installing new baseptr %lx", mfn); + domain_crash(d); + percpu_info[v->processor].deferred_ops = 0; + return 0; + } + } } - return okay; + invalidate_shadow_ldt(v); + + old_base_mfn = pagetable_get_pfn(v->arch.guest_table); + v->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT); + update_pagetables(v); /* update shadow_table and monitor_table */ + + write_ptbase(v); + + if ( likely(old_base_mfn != 0) ) + { + if ( shadow_mode_refcounts(d) ) + put_page(mfn_to_page(old_base_mfn)); + else + put_page_and_type(mfn_to_page(old_base_mfn)); + } + + /* CR3 also holds a ref to its shadow... */ + if ( shadow_mode_enabled(d) ) + { + if ( v->arch.monitor_shadow_ref ) + put_shadow_ref(v->arch.monitor_shadow_ref); + v->arch.monitor_shadow_ref = + pagetable_get_pfn(v->arch.monitor_table); + ASSERT(!page_get_owner(mfn_to_page(v->arch.monitor_shadow_ref))); + get_shadow_ref(v->arch.monitor_shadow_ref); + } + + return 1; } static void process_deferred_ops(unsigned int cpu) @@ -1625,7 +1651,7 @@ static void process_deferred_ops(unsigned int cpu) else local_flush_tlb(); } - + if ( deferred_ops & DOP_RELOAD_LDT ) (void)map_ldt_shadow_page(0);