All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.