|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v1] 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>
---
xen/arch/x86/mm/guest_walk.c | 7 ++++++-
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 | 15 ++++++++++++++-
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, 78 insertions(+), 12 deletions(-)
diff --git a/xen/arch/x86/mm/guest_walk.c b/xen/arch/x86/mm/guest_walk.c
index f67aeda..54140b9 100644
--- a/xen/arch/x86/mm/guest_walk.c
+++ b/xen/arch/x86/mm/guest_walk.c
@@ -82,7 +82,7 @@ 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, uint32_t *gf)
{
struct domain *d = v->domain;
p2m_type_t p2mt;
@@ -361,6 +361,11 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m,
* see whether the access should succeed.
*/
ar = (ar_and & AR_ACCUM_AND) | (ar_or & AR_ACCUM_OR);
+ if ( gf )
+ {
+ *gf = ar;
+ goto out;
+ }
/*
* Sanity check. If EFER.NX is disabled, _PAGE_NX_BIT is reserved and
diff --git a/xen/arch/x86/mm/hap/guest_walk.c b/xen/arch/x86/mm/hap/guest_walk.c
index cb3f9ce..c916b67 100644
--- a/xen/arch/x86/mm/hap/guest_walk.c
+++ b/xen/arch/x86/mm/hap/guest_walk.c
@@ -29,6 +29,9 @@ 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_pte_flags(levels) hap_pte_flags_##levels##_levels
+#define hap_pte_flags(levels) _hap_pte_flags(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 +42,33 @@ asm(".file \"" __OBJECT_FILE__ "\"");
#include <asm/guest_pt.h>
#include <asm/p2m.h>
+bool hap_pte_flags(GUEST_PAGING_LEVELS)(
+ struct vcpu *v, struct p2m_domain *p2m,
+ unsigned long va, uint32_t walk, unsigned long cr3,
+ uint32_t *gf)
+{
+ 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
+
+ return guest_walk_tables(v, p2m, va, &gw, walk, top_mfn, top_map, gf);
+}
+
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,
NULL);
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 812a840..2da7b63 100644
--- a/xen/arch/x86/mm/hap/hap.c
+++ b/xen/arch/x86/mm/hap/hap.c
@@ -767,7 +767,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,
+ .pte_flags = hap_pte_flags_2_levels
};
static const struct paging_mode hap_paging_protected_mode = {
@@ -778,7 +779,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,
+ .pte_flags = hap_pte_flags_2_levels
};
static const struct paging_mode hap_paging_pae_mode = {
@@ -789,7 +791,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,
+ .pte_flags = hap_pte_flags_3_levels
};
static const struct paging_mode hap_paging_long_mode = {
@@ -800,7 +803,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,
+ .pte_flags = hap_pte_flags_4_levels
};
/*
diff --git a/xen/arch/x86/mm/hap/private.h b/xen/arch/x86/mm/hap/private.h
index 973fbe8..615b02a 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);
+bool hap_pte_flags_2_levels(struct vcpu *v, struct p2m_domain *p2m,
+ unsigned long va, uint32_t walk, unsigned long cr3,
+ uint32_t *gf);
+bool hap_pte_flags_3_levels(struct vcpu *v, struct p2m_domain *p2m,
+ unsigned long va, uint32_t walk, unsigned long cr3,
+ uint32_t *gf);
+bool hap_pte_flags_4_levels(struct vcpu *v, struct p2m_domain *p2m,
+ unsigned long va, uint32_t walk, unsigned long
cr3,
+ uint32_t *gf);
+
#endif /* __HAP_PRIVATE_H__ */
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index 03a864156..b01194d 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -212,7 +212,20 @@ 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;
+ uint32_t pfec = PFEC_page_present;
+ unsigned long gfn;
+ uint32_t gflags;
+
+ hvm_funcs.save_cpu_ctxt(v, &ctxt);
+ paging_get_hostmode(v)->pte_flags(v, p2m, gla, 0, ctxt.cr3, &gflags);
+ if ( gflags & _PAGE_RW )
+ pfec |= PFEC_write_access;
+
+ if ( gflags & _PAGE_USER )
+ pfec |= PFEC_user_mode;
+
+ gfn = paging_ga_to_gfn_cr3(v, ctxt.cr3, gla, &pfec, NULL);
return true;
}
diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c
index 021ae25..199873f3 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
- );
+ NULL );
}
/* 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 08031c8..523ae34 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,
+ uint32_t *gf);
/* 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 f008551..e5f21c9 100644
--- a/xen/include/asm-x86/paging.h
+++ b/xen/include/asm-x86/paging.h
@@ -122,7 +122,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);
-
+ bool (*pte_flags )(struct vcpu *v,
+ struct p2m_domain *p2m,
+ unsigned long va, uint32_t walk,
+ unsigned long cr3, uint32_t *gf);
unsigned int guest_levels;
/* paging support extension */
--
2.7.4
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |