xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Zhang Yi <yi.z.zhang@linux.intel.com>
To: xen-devel@lists.xenproject.org
Cc: kevin.tian@intel.com, tamas@tklengyel.com, wei.liu2@citrix.com,
	jun.nakajima@intel.com, rcojocaru@bitdefender.com,
	george.dunlap@eu.citrix.com, andrew.cooper3@citrix.com,
	ian.jackson@eu.citrix.com,
	Zhang Yi Z <yi.z.zhang@linux.intel.com>,
	jbeulich@suse.com
Subject: [PATCH RFC 08/14] xen: vmx: Added setup spp page structure.
Date: Thu, 19 Oct 2017 16:12:33 +0800	[thread overview]
Message-ID: <d505ccd98f0e9f4faf1b10088b1edf53130ce8db.1508397860.git.yi.z.zhang@linux.intel.com> (raw)
In-Reply-To: <cover.1508397860.git.yi.z.zhang@linux.intel.com>

From: Zhang Yi Z <yi.z.zhang@linux.intel.com>

The hardware uses the guest-physical address and bits 11:7 of the
address accessed to lookup the SPPT to fetch a write permission bit for
the 128 byte wide sub-page region being accessed within the 4K
guest-physical page. If the sub-page region write permission bit is set,
the write is allowed; otherwise the write is disallowed and results in
an EPT violation.

Guest-physical pages mapped via leaf EPT-paging-structures for which the
accumulated write-access bit and the SPP bits are both clear (0)
generate
EPT violations on memory writes accesses. Guest-physical pages mapped
via EPT-paging-structure for which the accumulated write-access bit is
set (1) allow writes, effectively ignoring the SPP bit on the leaf
EPT-paging structure.

Software will setup the spp page table level4,3,2 as well as EPT page
structure, and fill the level1 via the 32 bit bitmap per a single 4K
page.
Now it could be divided to 32 x 128 sub-pages.

Signed-off-by: Zhang Yi Z <yi.z.zhang@linux.intel.com>
---
 xen/arch/x86/mm/mem_access.c      | 35 +++++++++++++++
 xen/arch/x86/mm/p2m-ept.c         | 94 +++++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/hvm/vmx/vmx.h | 10 +++++
 xen/include/asm-x86/p2m.h         |  3 ++
 4 files changed, 142 insertions(+)

diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index a471c74..1b97469 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -490,6 +490,41 @@ unlock_exit:
     return rc;
 }
 
+static u64 format_spp_spte(u32 spp_wp_bitmap)
+{
+	u64 new_spte = 0;
+	int i = 0;
+
+	/*
+	 * One 4K page contains 32 sub-pages, in SPP table L4E, old bits
+	 * are reserved, so we need to transfer u32 subpage write
+	 * protect bitmap to u64 SPP L4E format.
+	 */
+	while ( i < 32 ) {
+		if ( spp_wp_bitmap & (1ULL << i) )
+			new_spte |= 1ULL << (i * 2);
+
+		i++;
+	}
+
+	return new_spte;
+}
+
+int p2m_set_spp_page_st(struct domain *d, gfn_t gfn, uint32_t access_map)
+{
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    u64 access = format_spp_spte(access_map);
+    unsigned long gfn_l = gfn_x(gfn);
+    int ret = -1;
+
+    p2m_lock(p2m);
+    if ( p2m->spp_set_entry )
+        ret = p2m->spp_set_entry(p2m, gfn_l, access);
+    p2m_unlock(p2m);
+
+    return ret;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c
index c249286..c9dc29c 100644
--- a/xen/arch/x86/mm/p2m-ept.c
+++ b/xen/arch/x86/mm/p2m-ept.c
@@ -38,6 +38,8 @@
 
 #define is_epte_present(ept_entry)      ((ept_entry)->epte & 0x7)
 #define is_epte_superpage(ept_entry)    ((ept_entry)->sp)
+#define is_sppt_present(spp_entry)      ((spp_entry)->spp & 0x1)
+
 static inline bool_t is_epte_valid(ept_entry_t *e)
 {
     /* suppress_ve alone is not considered valid, so mask it off */
@@ -253,6 +255,22 @@ static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t *ept_entry)
     return 1;
 }
 
+static int spp_set_middle_entry(struct p2m_domain *p2m, spp_entry_t *spp_entry)
+{
+    struct page_info *pg;
+
+    pg = p2m_alloc_ptp(p2m, 0);
+    if ( pg == NULL )
+        return 0;
+
+    spp_entry->spp = 0;
+    spp_entry->mfn = page_to_mfn(pg);
+
+    spp_entry->present = 1;
+
+    return 1;
+}
+
 /* free ept sub tree behind an entry */
 static void ept_free_entry(struct p2m_domain *p2m, ept_entry_t *ept_entry, int level)
 {
@@ -323,6 +341,44 @@ static bool_t ept_split_super_page(struct p2m_domain *p2m,
     return rv;
 }
 
+static int spp_next_level(struct p2m_domain *p2m,
+                          spp_entry_t **table, unsigned long *gfn_remainder,
+                          int next_level)
+{
+    unsigned long mfn;
+    spp_entry_t *spp_entry, e;
+    u32 shift, index;
+
+    shift = next_level * EPT_TABLE_ORDER;
+
+    index = *gfn_remainder >> shift;
+
+    /* index must be falling into the page */
+    ASSERT(index < EPT_PAGETABLE_ENTRIES);
+
+    spp_entry = (*table) + index;
+
+    /* ept_next_level() is called (sometimes) without a lock.  Read
+     * the entry once, and act on the "cached" entry after that to
+     * avoid races. */
+    e.spp = read_atomic(&(spp_entry->spp));
+
+    if ( !is_sppt_present(&e) )
+    {
+        if ( !spp_set_middle_entry(p2m, spp_entry) )
+            return GUEST_TABLE_MAP_FAILED;
+        else
+            e.spp = read_atomic(&(spp_entry->spp)); /* Refresh */
+    }
+
+    mfn = e.mfn;
+    unmap_domain_page(*table);
+    *table = map_domain_page(_mfn(mfn));
+    *gfn_remainder &= (1UL << shift) - 1;
+    return GUEST_TABLE_NORMAL_PAGE;
+}
+
+
 /* Take the currently mapped table, find the corresponding gfn entry,
  * and map the next table, if available.  If the entry is empty
  * and read_only is set, 
@@ -709,6 +765,43 @@ out:
     return rc;
 }
 
+static int
+spp_set_entry(struct p2m_domain *p2m, unsigned long gfn, u64 access)
+{
+    struct spp_data *spp = &p2m->spptp;
+    unsigned long gfn_remainder = gfn;
+    spp_entry_t *table;
+    u64 *pspp_bitmap;
+    u64 old_spp_bitmap;
+    unsigned int i;
+    int ret, rc = 0;
+
+    ASSERT(spp);
+    table = map_domain_page(_mfn(pagetable_get_pfn(p2m_get_spp_pagetable(p2m))));
+
+    for ( i = 3; i > 0; i-- )
+    {
+        ret = spp_next_level(p2m, &table, &gfn_remainder, i);
+        if ( ret != GUEST_TABLE_NORMAL_PAGE )
+        {
+            printk("dazhang1 error oc ret = %x\n", ret);
+            rc = -1;
+            goto out;
+        }
+    }
+
+    pspp_bitmap = (u64 *) (table + gfn_remainder);
+    old_spp_bitmap = read_atomic(pspp_bitmap);
+    if( old_spp_bitmap != access )
+    {
+        write_atomic(pspp_bitmap, access);
+    }
+
+out:
+    unmap_domain_page(table);
+    return rc;
+}
+
 /*
  * ept_set_entry() computes 'need_modify_vtd_table' for itself,
  * by observing whether any gfn->mfn translations are modified.
@@ -1309,6 +1402,7 @@ int ept_p2m_init(struct p2m_domain *p2m)
     if ( cpu_has_vmx_ept_spp )
     {
         p2m->update_ept_spp_wp = ept_spp_update_wp;
+        p2m->spp_set_entry = spp_set_entry;
     }
 
     if ( !zalloc_cpumask_var(&ept->invalidate) )
diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h
index 18383b8..655ce80 100644
--- a/xen/include/asm-x86/hvm/vmx/vmx.h
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h
@@ -52,6 +52,16 @@ typedef union {
     u64 epte;
 } ept_entry_t;
 
+typedef union {
+    struct {
+        u64 present     :   1,  /* bit 0 - spp middle table is present */
+        reserved        :   11, /* bit 1:11 - reserved */
+        mfn             :   40, /* bit 12:51 - Machine physical frame number */
+        reserved2       :   12; /* bit 52:63 - reserved */
+    };
+    u64 spp;
+} spp_entry_t;
+
 typedef struct {
     /*use lxe[0] to save result */
     ept_entry_t lxe[5];
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index adbc1c6..b94ebb2 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -268,6 +268,9 @@ struct p2m_domain {
     long               (*audit_p2m)(struct p2m_domain *p2m);
     int                (*update_ept_spp_wp)(struct p2m_domain *p2m,
                                  unsigned long gfn);
+    int                (*spp_set_entry)(struct p2m_domain *p2m,
+                                unsigned long gfn,
+                                u64 access);
 
     /*
      * P2M updates may require TLBs to be flushed (invalidated).
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

  parent reply	other threads:[~2017-10-19  8:12 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-19  8:04 [PATCH RFC 00/14] Intel EPT-Based Sub-page Write Protection Support Zhang Yi
2017-10-19  8:08 ` [PATCH RFC 01/14] xen: vmx: Added EPT based Subpage Write Protection Doc Zhang Yi
2017-10-19  8:08 ` [PATCH RFC 02/14] xen: vmx: Added VMX SPP feature flags and VM-Execution Controls Zhang Yi
2017-10-19  8:09 ` [PATCH RFC 03/14] xen: vmx: Introduce the SPPTP and SPP page table Zhang Yi
2017-10-19  8:10 ` [PATCH RFC 04/14] xen: vmx: Introduce SPP-Induced vm exit and it's handle Zhang Yi
2017-10-19  8:11 ` [PATCH RFC 05/14] xen: vmx: Disable the 2M/1G superpage when SPP enabled Zhang Yi
2017-10-19 18:17   ` Tamas K Lengyel
2017-10-20  8:44     ` Yi Zhang
2017-10-24 17:43       ` Tamas K Lengyel
2017-10-25 15:32         ` Yi Zhang
2017-10-25 15:12           ` Tamas K Lengyel
2017-10-19  8:11 ` [PATCH RFC 06/14] xen: vmx: Added SPP flags in EPT leaf entry Zhang Yi
2017-10-19  8:12 ` [PATCH RFC 07/14] xen: vmx: Update the EPT leaf entry indicated with the SPP enable bit Zhang Yi
2017-10-19  8:12 ` Zhang Yi [this message]
2017-10-19 18:26   ` [PATCH RFC 08/14] xen: vmx: Added setup spp page structure Tamas K Lengyel
2017-10-20  8:43     ` Yi Zhang
2017-10-19  8:13 ` [PATCH RFC 09/14] xen: vmx: Introduce a Hyper call to set subpage Zhang Yi
2017-10-19 18:34   ` Tamas K Lengyel
2017-10-20  8:41     ` Yi Zhang
2017-10-19  8:13 ` [PATCH RFC 10/14] xen: vmx: Implement the Hypercall p2m_set_subpage Zhang Yi
2017-10-19  8:14 ` [PATCH RFC 11/14] xen: vmx: Added handle of SPP write protection fault Zhang Yi
2017-10-19  8:15 ` [PATCH RFC 12/14] xen: vmx: Support for clear EPT SPP write Protect bit Zhang Yi
2017-10-19  8:15 ` [PATCH RFC 13/14] xen: tools: Introduce the set-subpage into xenctrl Zhang Yi
2017-10-19  8:37   ` Razvan Cojocaru
2017-10-20  8:40     ` Yi Zhang
2017-10-19  8:16 ` [PATCH RFC 14/14] xen: tools: Added xen-subpage tool Zhang Yi
2017-10-19  8:42   ` Razvan Cojocaru
2017-10-20  8:39     ` Yi Zhang
2017-10-19  9:07 ` [PATCH RFC 00/14] Intel EPT-Based Sub-page Write Protection Support Razvan Cojocaru
2017-10-20  8:37   ` Yi Zhang
2017-10-20  8:39     ` Razvan Cojocaru
2017-10-20  8:39     ` Razvan Cojocaru

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d505ccd98f0e9f4faf1b10088b1edf53130ce8db.1508397860.git.yi.z.zhang@linux.intel.com \
    --to=yi.z.zhang@linux.intel.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=george.dunlap@eu.citrix.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=jbeulich@suse.com \
    --cc=jun.nakajima@intel.com \
    --cc=kevin.tian@intel.com \
    --cc=rcojocaru@bitdefender.com \
    --cc=tamas@tklengyel.com \
    --cc=wei.liu2@citrix.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).