|
[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 |