[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2] x86/mm: Suppresses vm_events caused by page-walks
The original version of the patch emulated the current instruction (which, as a side-effect, emulated the page-walk as well), however we need finer-grained control. We want to emulate the page-walk, but still get an EPT violation event if the current instruction would trigger one. This patch performs just the page-walk emulation. Signed-off-by: Alexandru Isaila <aisaila@xxxxxxxxxxxxxxx> --- Changes since V1: - Changed guest_walk_tables() to set A bit on each level and check if there was any A set. If not the it will set the D bit according to the write flags and cr0.wp --- xen/arch/x86/mm/guest_walk.c | 23 ++++++++++++++++++++++- xen/arch/x86/mm/hap/guest_walk.c | 32 +++++++++++++++++++++++++++++++- xen/arch/x86/mm/hap/hap.c | 12 ++++++++---- xen/arch/x86/mm/hap/private.h | 10 ++++++++++ xen/arch/x86/mm/mem_access.c | 5 ++++- xen/arch/x86/mm/shadow/multi.c | 6 +++--- xen/include/asm-x86/guest_pt.h | 3 ++- xen/include/asm-x86/paging.h | 5 ++++- 8 files changed, 84 insertions(+), 12 deletions(-) diff --git a/xen/arch/x86/mm/guest_walk.c b/xen/arch/x86/mm/guest_walk.c index f67aeda3d0..c99c48fa8a 100644 --- a/xen/arch/x86/mm/guest_walk.c +++ b/xen/arch/x86/mm/guest_walk.c @@ -82,7 +82,8 @@ static bool set_ad_bits(guest_intpte_t *guest_p, guest_intpte_t *walk_p, bool guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, unsigned long va, walk_t *gw, - uint32_t walk, mfn_t top_mfn, void *top_map) + uint32_t walk, mfn_t top_mfn, void *top_map, + bool set_ad) { struct domain *d = v->domain; p2m_type_t p2mt; @@ -95,6 +96,7 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, uint32_t gflags, rc; unsigned int leaf_level; p2m_query_t qt = P2M_ALLOC | P2M_UNSHARE; + bool accessed = false; #define AR_ACCUM_AND (_PAGE_USER | _PAGE_RW) #define AR_ACCUM_OR (_PAGE_NX_BIT) @@ -149,6 +151,10 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, ar_and &= gflags; ar_or |= gflags; + if ( set_ad && set_ad_bits(&l4p[guest_l4_table_offset(va)].l4, + &gw->l4e.l4, false) ) + accessed = true; + /* Map the l3 table */ l3p = map_domain_gfn(p2m, guest_l4e_get_gfn(gw->l4e), @@ -179,6 +185,10 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, ar_and &= gflags; ar_or |= gflags; + if ( set_ad && set_ad_bits(&l3p[guest_l3_table_offset(va)].l3, + &gw->l3e.l3, false) ) + accessed = true; + if ( gflags & _PAGE_PSE ) { /* @@ -278,6 +288,10 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, ar_and &= gflags; ar_or |= gflags; + if ( set_ad && set_ad_bits(&l2p[guest_l2_table_offset(va)].l2, + &gw->l2e.l2, false) ) + accessed = true; + if ( gflags & _PAGE_PSE ) { /* @@ -362,6 +376,13 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, */ ar = (ar_and & AR_ACCUM_AND) | (ar_or & AR_ACCUM_OR); + if ( set_ad ) + { + set_ad_bits(&l1p[guest_l1_table_offset(va)].l1, &gw->l1e.l1, + (ar & _PAGE_RW) && !accessed && !guest_wp_enabled(v)); + goto out; + } + /* * Sanity check. If EFER.NX is disabled, _PAGE_NX_BIT is reserved and * should have caused a translation failure before we get here. diff --git a/xen/arch/x86/mm/hap/guest_walk.c b/xen/arch/x86/mm/hap/guest_walk.c index 3b8ee2efce..4cbbf69095 100644 --- a/xen/arch/x86/mm/hap/guest_walk.c +++ b/xen/arch/x86/mm/hap/guest_walk.c @@ -29,6 +29,10 @@ asm(".file \"" __OBJECT_FILE__ "\""); #define _hap_gva_to_gfn(levels) hap_gva_to_gfn_##levels##_levels #define hap_gva_to_gfn(levels) _hap_gva_to_gfn(levels) +#define _hap_page_walk_set_ad_bits(levels) \ + hap_page_walk_set_ad_bits_##levels##_levels +#define hap_page_walk_set_ad_bits(levels) _hap_page_walk_set_ad_bits(levels) + #define _hap_p2m_ga_to_gfn(levels) hap_p2m_ga_to_gfn_##levels##_levels #define hap_p2m_ga_to_gfn(levels) _hap_p2m_ga_to_gfn(levels) @@ -39,6 +43,32 @@ asm(".file \"" __OBJECT_FILE__ "\""); #include <asm/guest_pt.h> #include <asm/p2m.h> +void hap_page_walk_set_ad_bits(GUEST_PAGING_LEVELS)( + struct vcpu *v, struct p2m_domain *p2m, + unsigned long va, uint32_t walk, unsigned long cr3) +{ + walk_t gw; + mfn_t top_mfn; + void *top_map; + gfn_t top_gfn; + struct page_info *top_page; + p2m_type_t p2mt; + + top_gfn = _gfn(cr3 >> PAGE_SHIFT); + top_page = p2m_get_page_from_gfn(p2m, top_gfn, &p2mt, NULL, + P2M_ALLOC | P2M_UNSHARE); + top_mfn = page_to_mfn(top_page); + + /* Map the top-level table and call the tree-walker */ + ASSERT(mfn_valid(top_mfn)); + top_map = map_domain_page(top_mfn); +#if GUEST_PAGING_LEVELS == 3 + top_map += (cr3 & ~(PAGE_MASK | 31)); +#endif + + guest_walk_tables(v, p2m, va, &gw, walk, top_mfn, top_map, true); +} + unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)( struct vcpu *v, struct p2m_domain *p2m, unsigned long gva, uint32_t *pfec) { @@ -91,7 +121,7 @@ unsigned long hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)( #if GUEST_PAGING_LEVELS == 3 top_map += (cr3 & ~(PAGE_MASK | 31)); #endif - walk_ok = guest_walk_tables(v, p2m, ga, &gw, *pfec, top_mfn, top_map); + walk_ok = guest_walk_tables(v, p2m, ga, &gw, *pfec, top_mfn, top_map, false); unmap_domain_page(top_map); put_page(top_page); diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c index 3d651b94c3..ca046b78df 100644 --- a/xen/arch/x86/mm/hap/hap.c +++ b/xen/arch/x86/mm/hap/hap.c @@ -768,7 +768,8 @@ static const struct paging_mode hap_paging_real_mode = { .update_cr3 = hap_update_cr3, .update_paging_modes = hap_update_paging_modes, .write_p2m_entry = hap_write_p2m_entry, - .guest_levels = 1 + .guest_levels = 1, + .page_walk_set_ad_bits = hap_page_walk_set_ad_bits_2_levels }; static const struct paging_mode hap_paging_protected_mode = { @@ -779,7 +780,8 @@ static const struct paging_mode hap_paging_protected_mode = { .update_cr3 = hap_update_cr3, .update_paging_modes = hap_update_paging_modes, .write_p2m_entry = hap_write_p2m_entry, - .guest_levels = 2 + .guest_levels = 2, + .page_walk_set_ad_bits = hap_page_walk_set_ad_bits_2_levels }; static const struct paging_mode hap_paging_pae_mode = { @@ -790,7 +792,8 @@ static const struct paging_mode hap_paging_pae_mode = { .update_cr3 = hap_update_cr3, .update_paging_modes = hap_update_paging_modes, .write_p2m_entry = hap_write_p2m_entry, - .guest_levels = 3 + .guest_levels = 3, + .page_walk_set_ad_bits = hap_page_walk_set_ad_bits_3_levels }; static const struct paging_mode hap_paging_long_mode = { @@ -801,7 +804,8 @@ static const struct paging_mode hap_paging_long_mode = { .update_cr3 = hap_update_cr3, .update_paging_modes = hap_update_paging_modes, .write_p2m_entry = hap_write_p2m_entry, - .guest_levels = 4 + .guest_levels = 4, + .page_walk_set_ad_bits = hap_page_walk_set_ad_bits_4_levels }; /* diff --git a/xen/arch/x86/mm/hap/private.h b/xen/arch/x86/mm/hap/private.h index 973fbe8be5..abb933c4f8 100644 --- a/xen/arch/x86/mm/hap/private.h +++ b/xen/arch/x86/mm/hap/private.h @@ -47,4 +47,14 @@ unsigned long hap_p2m_ga_to_gfn_4_levels(struct vcpu *v, struct p2m_domain *p2m, unsigned long cr3, paddr_t ga, uint32_t *pfec, unsigned int *page_order); +void hap_page_walk_set_ad_bits_2_levels(struct vcpu *v, struct p2m_domain *p2m, + unsigned long va, uint32_t walk, + unsigned long cr3); +void hap_page_walk_set_ad_bits_3_levels(struct vcpu *v, struct p2m_domain *p2m, + unsigned long va, uint32_t walk, + unsigned long cr3); +void hap_page_walk_set_ad_bits_4_levels(struct vcpu *v, struct p2m_domain *p2m, + unsigned long va, uint32_t walk, + unsigned long cr3); + #endif /* __HAP_PRIVATE_H__ */ diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c index a8b3e99ec4..8b644946f0 100644 --- a/xen/arch/x86/mm/mem_access.c +++ b/xen/arch/x86/mm/mem_access.c @@ -214,7 +214,10 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla, d->arch.monitor.inguest_pagefault_disabled && npfec.kind != npfec_kind_with_gla ) /* don't send a mem_event */ { - hvm_emulate_one_vm_event(EMUL_KIND_NORMAL, TRAP_invalid_op, X86_EVENT_NO_EC); + struct hvm_hw_cpu ctxt; + + hvm_funcs.save_cpu_ctxt(v, &ctxt); + paging_get_hostmode(v)->page_walk_set_ad_bits(v, p2m, gla, 0, ctxt.cr3); return true; } diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index 5cb216f0db..d3df9be57c 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -178,12 +178,12 @@ sh_walk_guest_tables(struct vcpu *v, unsigned long va, walk_t *gw, return guest_walk_tables(v, p2m_get_hostp2m(v->domain), va, gw, pfec, #if GUEST_PAGING_LEVELS == 3 /* PAE */ INVALID_MFN, - v->arch.paging.shadow.gl3e + v->arch.paging.shadow.gl3e, #else /* 32 or 64 */ pagetable_get_mfn(v->arch.guest_table), - v->arch.paging.shadow.guest_vtable + v->arch.paging.shadow.guest_vtable, #endif - ); + false); } /* This validation is called with lock held, and after write permission diff --git a/xen/include/asm-x86/guest_pt.h b/xen/include/asm-x86/guest_pt.h index 8684b83fd6..3dfb7fa966 100644 --- a/xen/include/asm-x86/guest_pt.h +++ b/xen/include/asm-x86/guest_pt.h @@ -425,7 +425,8 @@ static inline unsigned int guest_walk_to_page_order(const walk_t *gw) bool guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, unsigned long va, - walk_t *gw, uint32_t pfec, mfn_t top_mfn, void *top_map); + walk_t *gw, uint32_t pfec, mfn_t top_mfn, void *top_map, + bool set_ad); /* Pretty-print the contents of a guest-walk */ static inline void print_gw(const walk_t *gw) diff --git a/xen/include/asm-x86/paging.h b/xen/include/asm-x86/paging.h index b51e1709d3..076ca204f5 100644 --- a/xen/include/asm-x86/paging.h +++ b/xen/include/asm-x86/paging.h @@ -127,7 +127,10 @@ struct paging_mode { void (*write_p2m_entry )(struct domain *d, unsigned long gfn, l1_pgentry_t *p, l1_pgentry_t new, unsigned int level); - + void (*page_walk_set_ad_bits )(struct vcpu *v, + struct p2m_domain *p2m, + unsigned long va, uint32_t walk, + unsigned long cr3); unsigned int guest_levels; /* paging support extension */ -- 2.17.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |