Skip to contentSkip to conversation

PML (Paging Modification Logging) support

PATCH Superseded Kai Huang 6 participants 62 messages Apr 15, 2015 – Apr 24, 2015

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

Kai Huang

author
#0 lore raw

v2 cover PML (Paging Modification Logging) support

This v2 patch series was rebased on latest upstream code.

v1->v2:

Firstly the sequence of this patch series were adjusted addressing Andrew and Tim's comments:

- Put v1 patch 2 (new boot parameter for PML) to be patch 1.
- Added a new patch to patch the doc change of new added boot parameter of controlling PML enabling, as patch 2.
- Added a new patch to introduce paging_mark_gfn_dirty, and made paging_mark_dirty as a wrapper of it, as patch 3.
- Merged v1 patch 1 (EPT A/D bits support) and v1 patch 10 (enabling PML in p2m-ept.c) to a single patch as they both operates on EPT A/D bits, with considering EPT A/D bits will be enabled only when PML is used as well. To me, looks a single patch is more straightforward.

The v2 patch series were orginized as following, with detail changes described under each of them.

patch 1: Add new boot parameter to control PML enabling
- adjusted the sequence of parsing function and boot parameter.

patch 2: new patch for adding description for new PML boot parameter
- inspired by "iommu=" parameter.

patch 3: add new paging_mark_gfn_dirty
- Introduced new paging_mark_gfn_dirty, which takes guest pfn as parameter, and made paging_mark_dirty a wrapper of paging_mark_gfn_dirty, commented by Tim.

patch 4: PML feature detection
- disable opt_pml_enabled if PML is not present, commented by Andrew.

patch 5 ~ 9: Add PML support in VMX
- changed vmx_*_{enable|disable}_pml, vmx_domain_flush_pml_buffer to be idempotent, commented by Tim. vmx_vcpu_flush_pml_buffer remains the same as it is also called in PML buffer full VMEXIT.
- changed vmx_{vcpu|domain}_pml_enabled to return bool_t, with taking const pointer (of vcpu or domain) as parameter, commented by Andrew.
- changed vmx_vcpu_flush_pml_buffer calling paging_mark_gfn_dirty instead of paging_mark_dirty, commented by Tim.
- changed various coding style issues and did several code refinements commented by Andrew.

patch 10: refine log-dirty common code to support PML
- removed PML buffer flush callback in log_dirty_domain in paging layer.
- changed to call p2m_flush_hardware_cached_dirty directly in hap_track_dirty_vram, and paging_log_dirty_op.

patch 11: enable EPT A/D bits and add PML support in p2m-ept.c
- Merged EPT A/D bits support with enabling PML in p2m-ept.c as it's more straightforward, with considering EPT A/D bits will only be enabled if PML is used, and both of them operates on EPT A/D bits.
- Manually set or clear A/D bits in ept_p2m_type_to_flags, and ept_set_middle_entry, commented by Tim.

Several sanity tests of live migration were done, and all tests worked well.

I also tested specjbb performance under global log-dirty, by using the same hack mentioned in v1. The result is consistent with v1 (~10% improvement in global log-dirty), and PML is beneficial in reducing hypervisor overhead in log-dirty mode.

- global log-dirty:

    WP              PML (v1)        PML (v2)
    72862           79511	        80007
    73466           81173	        81614
    72989           81177	        82047
    73138           81777	        81975
    72811           80257	        80139
    72486           80413	        81127

avg 72959 80718 81151

    100%            110.63%         111.22%

Kai Huang (11):
vmx: add new boot parameter to control PML enabling
doc: add description for new PML boot parameter
log-dirty: add new paging_mark_gfn_dirty
vmx: add PML definition and feature detection.
vmx: add new data structure member to support PML
vmx: add help functions to support PML
vmx: handle PML buffer full VMEXIT
vmx: handle PML enabling in vmx_vcpu_initialise
vmx: disable PML in vmx_vcpu_destroy
log-dirty: refine common code to support PML p2m/ept: enable PML in p2m-ept for log-dirty

 docs/misc/xen-command-line.markdown |  14 +++
 xen/arch/x86/hvm/vmx/vmcs.c         | 231 ++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/vmx/vmx.c          |  35 ++++++
 xen/arch/x86/mm/hap/hap.c           |  29 ++++-
 xen/arch/x86/mm/p2m-ept.c           |  79 ++++++++++--
 xen/arch/x86/mm/p2m.c               |  36 ++++++
 xen/arch/x86/mm/paging.c            |  41 +++++--
 xen/include/asm-x86/hvm/vmx/vmcs.h  |  25 +++-
 xen/include/asm-x86/hvm/vmx/vmx.h   |   4 +-
 xen/include/asm-x86/p2m.h           |  11 ++
 xen/include/asm-x86/paging.h        |   2 +
 11 files changed, 484 insertions(+), 23 deletions(-)
Signature · 1 line
2.1.0
author
#1 lore raw

PATCH v2 1/11 vmx: add new boot parameter to control PML enabling

A top level EPT parameter "ept=<options>" and a sub boolean "opt_pml_enabled" are added to control PML. Other booleans can be further added for any other EPT related features.

---
 xen/arch/x86/hvm/vmx/vmcs.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +31 -0
index d614638..4fff46d 100644
@@ -64,6 +64,37 @@ integer_param("ple_gap", ple_gap);
 static unsigned int __read_mostly ple_window = 4096;
 integer_param("ple_window", ple_window);
 
+static bool_t __read_mostly opt_pml_enabled = 0;
+
+/*
+ * The 'ept' parameter controls functionalities that depend on, or impact the
+ * EPT mechanism. Optional comma separated value may contain:
+ *
+ *  pml                 Enable PML
+ */
+static void __init parse_ept_param(char *s)
+{
+    char *ss;
+    int val;
+
+    do {
+        val = !!strncmp(s, "no-", 3);
+        if ( !val )
+            s += 3;
+
+        ss = strchr(s, ',');
+        if ( ss )
+            *ss = '\0';
+
+        if ( !strcmp(s, "pml") )
+            opt_pml_enabled = val;
+
+        s = ss + 1;
+    } while ( ss );
+}
+
+custom_param("ept", parse_ept_param);
+
 /* Dynamic (run-time adjusted) execution control flags. */
 u32 vmx_pin_based_exec_control __read_mostly;
 u32 vmx_cpu_based_exec_control __read_mostly;
Signature · 1 line
2.1.0
Reviewed-by on v2 1/11
#2 lore raw

Re: [v2 01/11] vmx: add new boot parameter to control PML enabling

Quoted 5 lines · Kai Huang

A top level EPT parameter "ept=<options>" and a sub boolean "opt_pml_enabled" are added to control PML. Other booleans can be further added for any other EPT related features.

Quoted 46 lines
---
 xen/arch/x86/hvm/vmx/vmcs.c | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +31 -0
index d614638..4fff46d 100644
@@ -64,6 +64,37 @@ integer_param("ple_gap", ple_gap);
 static unsigned int __read_mostly ple_window = 4096;
 integer_param("ple_window", ple_window);
 
+static bool_t __read_mostly opt_pml_enabled = 0;
+
+/*
+ * The 'ept' parameter controls functionalities that depend on, or impact the
+ * EPT mechanism. Optional comma separated value may contain:
+ *
+ *  pml                 Enable PML
+ */
+static void __init parse_ept_param(char *s)
+{
+    char *ss;
+    int val;
+
+    do {
+        val = !!strncmp(s, "no-", 3);
+        if ( !val )
+            s += 3;
+
+        ss = strchr(s, ',');
+        if ( ss )
+            *ss = '\0';
+
+        if ( !strcmp(s, "pml") )
+            opt_pml_enabled = val;
+
+        s = ss + 1;
+    } while ( ss );
+}
+
+custom_param("ept", parse_ept_param);
+
 /* Dynamic (run-time adjusted) execution control flags. */
 u32 vmx_pin_based_exec_control __read_mostly;
 u32 vmx_cpu_based_exec_control __read_mostly;
#3 lore raw

Re: [v2 01/11] vmx: add new boot parameter to control PML enabling

In reply to Kai Huang

xen/arch/x86/hvm/vmx/vmcs.c integer_param("ple_gap", ple_gap); · line 78

Quoted 5 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+static void __init parse_ept_param(char *s)
+{
+    char *ss;
+    int val;

bool_t, and would better move ...

xen/arch/x86/hvm/vmx/vmcs.c integer_param("ple_gap", ple_gap); · line 81

Quoted 3 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+
+    do {
+        val = !!strncmp(s, "no-", 3);

... here (making the right side expression its intializer).

Jan

#4 lore raw

Re: [v2 01/11] vmx: add new boot parameter to control PML enabling

Quoted 8 lines · Jan Beulich

xen/arch/x86/hvm/vmx/vmcs.c integer_param("ple_gap", ple_gap); · line 78

Quoted 5 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+static void __init parse_ept_param(char *s)
+{
+    char *ss;
+    int val;

bool_t, and would better move ...

Quoted 5 lines

xen/arch/x86/hvm/vmx/vmcs.c integer_param("ple_gap", ple_gap); · line 81

Quoted 3 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+
+    do {
+        val = !!strncmp(s, "no-", 3);

... here (making the right side expression its intializer).

Hi Jan,

Thanks for review. Do you mean below?

    do {
        bool_t val = !!strncmp(s,  "no-", 3);
        ...

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

Signature · 2 lines
Thanks,
-Kai
#5 lore raw

Re: [v2 01/11] vmx: add new boot parameter to control PML enabling

Quoted 14 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 15:20, <[email protected]> wrote:
Quoted 12 lines · Jan Beulich

xen/arch/x86/hvm/vmx/vmcs.c integer_param("ple_gap", ple_gap); · line 78

Quoted 5 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+static void __init parse_ept_param(char *s)
+{
+    char *ss;
+    int val;

bool_t, and would better move ...

Quoted 3 lines
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+
+    do {
+        val = !!strncmp(s, "no-", 3);
Quoted 7 lines
Quoted 1 line

... here (making the right side expression its intializer).

Thanks for review. Do you mean below?

    do {
        bool_t val = !!strncmp(s,  "no-", 3);
        ...

Yes.

Jan

author
#6 lore raw

PATCH v2 2/11 doc: add description for new PML boot parameter

In reply to Kai Huang

This patch adds doc description for new boot parameter 'ept=pml'.

---
 docs/misc/xen-command-line.markdown | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
docs/misc/xen-command-line.markdown +14 -0
index 1dda1f0..ae30d02 100644
@@ -685,6 +685,20 @@ requirement can be relaxed.  This option is particularly useful for nested
 virtualization, to allow the L1 hypervisor to use EPT even if the L0 hypervisor
 does not provide VM\_ENTRY\_LOAD\_GUEST\_PAT.
 
+### ept (Intel)
+> `= List of [ pml ]`
+
+> Sub-options:
+
+> `pml`
+
+> This sub-option is boolean type and can be prefixed with `no-` to effect the
+> inverse meaning.
+
+> Default: `false`
+
+>> Control the use of Page Modification Logging for log-dirty.
+
 ### gdb
 > `= <baud>[/<clock_hz>][,DPS[,<io-base>[,<irq>[,<port-bdf>[,<bridge-bdf>]]]] | pci | amt ] `
 
Signature · 1 line
2.1.0
#7 lore raw

Re: [v2 02/11] doc: add description for new PML boot parameter

Quoted 3 lines · Kai Huang

This patch adds doc description for new boot parameter 'ept=pml'.

Personally, I would fold this patch into the previous so the documentation is in the same patch as introduces the parameter.

Quoted 15 lines
---
 docs/misc/xen-command-line.markdown | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
docs/misc/xen-command-line.markdown +3 -0
index 1dda1f0..ae30d02 100644
@@ -685,6 +685,20 @@ requirement can be relaxed.  This option is particularly useful for nested
 virtualization, to allow the L1 hypervisor to use EPT even if the L0 hypervisor
 does not provide VM\_ENTRY\_LOAD\_GUEST\_PAT.
 
+### ept (Intel)
+> `= List of [ pml ]`
+

docs/misc/xen-command-line.markdown requirement can be relaxed. This option is particularly useful for nested · line 700

Quoted 10 lines
docs/misc/xen-command-line.markdown +10 -0
+> Sub-options:
+
+> `pml`
+
+> This sub-option is boolean type and can be prefixed with `no-` to effect the
+> inverse meaning.
+
+> Default: `false`
+
+>> Control the use of Page Modification Logging for log-dirty.

Can you follow the same style as the "psr" option? Specifically, I don't think you need to re-describe what a boolean parameter is.

~Andrew

Quoted 4 lines
docs/misc/xen-command-line.markdown +1 -0
+
 ### gdb
 > `= <baud>[/<clock_hz>][,DPS[,<io-base>[,<irq>[,<port-bdf>[,<bridge-bdf>]]]] | pci | amt ] `
 
#8 lore raw

Re: [v2 02/11] doc: add description for new PML boot parameter

Quoted 8 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 12:15, <[email protected]> wrote:
Quoted 3 lines · Kai Huang

This patch adds doc description for new boot parameter 'ept=pml'.

Personally, I would fold this patch into the previous so the documentation is in the same patch as introduces the parameter.

+1

Jan

author
#9 lore raw

Re: [v2 02/11] doc: add description for new PML boot parameter

In reply to Andrew Cooper
Quoted 6 lines · Andrew Cooper
Quoted 3 lines · Kai Huang

This patch adds doc description for new boot parameter 'ept=pml'.

Personally, I would fold this patch into the previous so the documentation is in the same patch as introduces the parameter.

Thanks for suggestion. Will do in the next version.

Quoted 13 lines
Quoted 13 lines
---
  docs/misc/xen-command-line.markdown | 14 ++++++++++++++
  1 file changed, 14 insertions(+)
docs/misc/xen-command-line.markdown +0 -0
index 1dda1f0..ae30d02 100644
@@ -685,6 +685,20 @@ requirement can be relaxed.  This option is particularly useful for nested
  virtualization, to allow the L1 hypervisor to use EPT even if the L0 hypervisor
  does not provide VM\_ENTRY\_LOAD\_GUEST\_PAT.
 
Quoted 15 lines

docs/misc/xen-command-line.markdown requirement can be relaxed. This option is particularly useful for nested · line 700

Quoted 13 lines
docs/misc/xen-command-line.markdown +13 -0
+### ept (Intel)
+> `= List of [ pml ]`
+
+> Sub-options:
+
+> `pml`
+
+> This sub-option is boolean type and can be prefixed with `no-` to effect the
+> inverse meaning.
+
+> Default: `false`
+
+>> Control the use of Page Modification Logging for log-dirty.

Can you follow the same style as the "psr" option? Specifically, I don't think you need to re-describe what a boolean parameter is.

Thanks for suggestion. I chose to follow the "iommu=" style parameter as to me the "ept=" parameter is more likely to the "iommu=" parameter -- both of them intend to have various sub-boolean types, within which some may or may not be independent to each other.

Referring to 'psr' parameter, does below change look good to you?

+### ept (Intel)
+> = List of ( pml<boolean> )
+
+> Default: false
+
+Controls EPT related features. Currently only Page Modification Logging (PML) is +the controllable feature as boolean type.
+
+PML is a new hardware feature in Intel's Broadwell Server and further platforms +which reduces hypervisor overhead of log-dirty mechanism by automatically +recording GPAs (guest physical addresses) when guest memory gets dirty, and +therefore significantly reducing number of EPT violation caused by write +protection of guest memory, which is a necessity to implement log-dirty +mechanism before PML.

Thanks,
-Kai

Quoted 12 lines

~Andrew

docs/misc/xen-command-line.markdown requirement can be relaxed. This option is particularly useful for nested · line 704

Quoted 4 lines
docs/misc/xen-command-line.markdown +1 -0
+
  ### gdb
  > `= <baud>[/<clock_hz>][,DPS[,<io-base>[,<irq>[,<port-bdf>[,<bridge-bdf>]]]] | pci | amt ] `
 

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#10 lore raw

Re: [v2 02/11] doc: add description for new PML boot parameter

Quoted 68 lines · Kai Huang
Quoted 6 lines · Andrew Cooper
Quoted 3 lines · Kai Huang

This patch adds doc description for new boot parameter 'ept=pml'.

Personally, I would fold this patch into the previous so the documentation is in the same patch as introduces the parameter.

Thanks for suggestion. Will do in the next version.

Quoted 23 lines
Quoted 23 lines
---
  docs/misc/xen-command-line.markdown | 14 ++++++++++++++
  1 file changed, 14 insertions(+)
docs/misc/xen-command-line.markdown +0 -0
index 1dda1f0..ae30d02 100644
@@ -685,6 +685,20 @@ requirement can be relaxed.  This option is

particularly useful for nested
virtualization, to allow the L1 hypervisor to use EPT even if the
L0 hypervisor
does not provide VM\_ENTRY\_LOAD\_GUEST\_PAT.
+### ept (Intel)
+> = List of [ pml ]

docs/misc/xen-command-line.markdown +6 -0
+
+> Sub-options:
+
+> `pml`
+
+> This sub-option is boolean type and can be prefixed with `no-` to
Quoted 8 lines

docs/misc/xen-command-line.markdown requirement can be relaxed. This option is particularly useful for nested · line 700

Quoted 6 lines

effect the
+> inverse meaning.

docs/misc/xen-command-line.markdown +4 -0
+
+> Default: `false`
+
+>> Control the use of Page Modification Logging for log-dirty.

Can you follow the same style as the "psr" option? Specifically, I don't think you need to re-describe what a boolean parameter is.

Thanks for suggestion. I chose to follow the "iommu=" style parameter as to me the "ept=" parameter is more likely to the "iommu=" parameter -- both of them intend to have various sub-boolean types, within which some may or may not be independent to each other.

Referring to 'psr' parameter, does below change look good to you?

docs/misc/xen-command-line.markdown +6 -0
+### ept (Intel)
+> `= List of ( pml<boolean> )`
+
+> Default: `false`
+
+Controls EPT related features. Currently only Page Modification

Logging (PML) is

(quoted diff) +3 -0
+the controllable feature as boolean type.
+
+PML is a new hardware feature in Intel's Broadwell Server and further

platforms
+which reduces hypervisor overhead of log-dirty mechanism by automatically
+recording GPAs (guest physical addresses) when guest memory gets dirty, and

(quoted diff) +3 -0
+therefore significantly reducing number of EPT violation caused by write
+protection of guest memory, which is a necessity to implement log-dirty
+mechanism before PML.
Quoted 2 lines

Thanks,
-Kai

Yep - that looks good.

~Andrew

author
#11 lore raw

PATCH v2 3/11 log-dirty: add new paging_mark_gfn_dirty

In reply to Kai Huang

PML logs GPA in PML buffer. Original paging_mark_dirty takes MFN as parameter but it gets guest pfn internally and use guest pfn to as index for looking up radix log-dirty tree. In flushing PML buffer, calling paging_mark_dirty directly introduces redundant p2m lookups (gfn->mfn->gfn), therefore we introduce paging_mark_gfn_dirty which is bulk of paging_mark_dirty but takes guest pfn as parameter, and in flushing PML buffer we call paging_mark_gfn_dirty directly. Original paging_mark_dirty then simply is a wrapper of paging_mark_gfn_dirty.

---
 xen/arch/x86/mm/paging.c     | 31 +++++++++++++++++++++----------
 xen/include/asm-x86/paging.h |  2 ++
 2 files changed, 23 insertions(+), 10 deletions(-)
xen/arch/x86/mm/paging.c +21 -10
index b54d76a..77c929b 100644
@@ -266,24 +266,17 @@ static int paging_log_dirty_disable(struct domain *d, bool_t resuming)
     return ret;
 }
 
-/* Mark a page as dirty */
-void paging_mark_dirty(struct domain *d, unsigned long guest_mfn)
+/* Mark a page as dirty, with taking guest pfn as parameter */
+void paging_mark_gfn_dirty(struct domain *d, unsigned long pfn)
 {
-    unsigned long pfn;
-    mfn_t gmfn;
     int changed;
     mfn_t mfn, *l4, *l3, *l2;
     unsigned long *l1;
     int i1, i2, i3, i4;
 
-    gmfn = _mfn(guest_mfn);
-
-    if ( !paging_mode_log_dirty(d) || !mfn_valid(gmfn) ||
-         page_get_owner(mfn_to_page(gmfn)) != d )
+    if ( !paging_mode_log_dirty(d) )
         return;
 
-    /* We /really/ mean PFN here, even for non-translated guests. */
-    pfn = get_gpfn_from_mfn(mfn_x(gmfn));
     /* Shared MFNs should NEVER be marked dirty */
     BUG_ON(SHARED_M2P(pfn));
 
@@ -351,6 +344,24 @@ out:
     return;
 }
 
+/* Mark a page as dirty */
+void paging_mark_dirty(struct domain *d, unsigned long guest_mfn)
+{
+    unsigned long pfn;
+    mfn_t gmfn;
+
+    gmfn = _mfn(guest_mfn);
+
+    if ( !paging_mode_log_dirty(d) || !mfn_valid(gmfn) ||
+         page_get_owner(mfn_to_page(gmfn)) != d )
+        return;
+
+    /* We /really/ mean PFN here, even for non-translated guests. */
+    pfn = get_gpfn_from_mfn(mfn_x(gmfn));
+
+    paging_mark_gfn_dirty(d, pfn);
+}
+
 
 /* Is this guest page dirty? */
 int paging_mfn_is_dirty(struct domain *d, mfn_t gmfn)
xen/include/asm-x86/paging.h +2 -0
index 53de715..c99324c 100644
@@ -156,6 +156,8 @@ void paging_log_dirty_init(struct domain *d,
 
 /* mark a page as dirty */
 void paging_mark_dirty(struct domain *d, unsigned long guest_mfn);
+/* mark a page as dirty with taking guest pfn as parameter */
+void paging_mark_gfn_dirty(struct domain *d, unsigned long pfn);
 
 /* is this guest page dirty? 
  * This is called from inside paging code, with the paging lock held. */
Signature · 1 line
2.1.0
author
#12 lore raw

PATCH v2 4/11 vmx: add PML definition and feature detection.

In reply to Kai Huang

The patch adds PML definition and feature detection. Note PML won't be detected if PML is disabled from boot parameter. PML is also disabled in construct_vmcs, as it will only be enabled when domain is switched to log dirty mode.

---
 xen/arch/x86/hvm/vmx/vmcs.c        | 22 ++++++++++++++++++++++
 xen/include/asm-x86/hvm/vmx/vmcs.h |  6 ++++++
 xen/include/asm-x86/hvm/vmx/vmx.h  |  1 +
 3 files changed, 29 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +22 -0
index 4fff46d..d120370 100644
@@ -141,6 +141,7 @@ static void __init vmx_display_features(void)
     P(cpu_has_vmx_virtual_intr_delivery, "Virtual Interrupt Delivery");
     P(cpu_has_vmx_posted_intr_processing, "Posted Interrupt Processing");
     P(cpu_has_vmx_vmcs_shadowing, "VMCS shadowing");
+    P(cpu_has_vmx_pml, "Page Modification Logging");
 #undef P
 
     if ( !printed )
@@ -238,6 +239,8 @@ static int vmx_init_vmcs_config(void)
             opt |= SECONDARY_EXEC_ENABLE_VPID;
         if ( opt_unrestricted_guest_enabled )
             opt |= SECONDARY_EXEC_UNRESTRICTED_GUEST;
+        if ( opt_pml_enabled )
+            opt |= SECONDARY_EXEC_ENABLE_PML;
 
         /*
          * "APIC Register Virtualization" and "Virtual Interrupt Delivery"
@@ -284,6 +287,14 @@ static int vmx_init_vmcs_config(void)
          */
         if ( !(_vmx_ept_vpid_cap & VMX_VPID_INVVPID_ALL_CONTEXT) )
             _vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_VPID;
+
+        /*
+         * PML cannot be supported if EPT A/D bits is not supported. Actually,
+         * PML should not be detected if EPT A/D bits is not supported, but for
+         * sure we do the check anyway.
+         */
+        if ( !(_vmx_ept_vpid_cap & VMX_EPT_AD_BIT) )
+            _vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
     }
 
     if ( _vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT )
@@ -304,6 +315,14 @@ static int vmx_init_vmcs_config(void)
                   SECONDARY_EXEC_UNRESTRICTED_GUEST);
     }
 
+    /* PML cannot be supported if EPT is not used */
+    if ( !(_vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT) )
+        _vmx_secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
+
+    /* Turn off opt_pml_enabled if PML feature is not present */
+    if ( !(_vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_PML) )
+        opt_pml_enabled = 0;
+
     if ( (_vmx_secondary_exec_control & SECONDARY_EXEC_PAUSE_LOOP_EXITING) &&
           ple_gap == 0 )
     {
@@ -1039,6 +1058,9 @@ static int construct_vmcs(struct vcpu *v)
         __vmwrite(POSTED_INTR_NOTIFICATION_VECTOR, posted_intr_vector);
     }
 
+    /* Disable PML anyway here as it will only be enabled in log dirty mode */
+    v->arch.hvm_vmx.secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
+
     /* Host data selectors. */
     __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
     __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);
xen/include/asm-x86/hvm/vmx/vmcs.h +6 -0
index 6fce6aa..f831a78 100644
@@ -215,6 +215,7 @@ extern u32 vmx_vmentry_control;
 #define SECONDARY_EXEC_ENABLE_INVPCID           0x00001000
 #define SECONDARY_EXEC_ENABLE_VMFUNC            0x00002000
 #define SECONDARY_EXEC_ENABLE_VMCS_SHADOWING    0x00004000
+#define SECONDARY_EXEC_ENABLE_PML               0x00020000
 extern u32 vmx_secondary_exec_control;
 
 #define VMX_EPT_EXEC_ONLY_SUPPORTED             0x00000001
@@ -226,6 +227,7 @@ extern u32 vmx_secondary_exec_control;
 #define VMX_EPT_INVEPT_INSTRUCTION              0x00100000
 #define VMX_EPT_INVEPT_SINGLE_CONTEXT           0x02000000
 #define VMX_EPT_INVEPT_ALL_CONTEXT              0x04000000
+#define VMX_EPT_AD_BIT                          0x00200000
 
 #define VMX_MISC_VMWRITE_ALL                    0x20000000
 
@@ -274,6 +276,8 @@ extern u32 vmx_secondary_exec_control;
     (vmx_pin_based_exec_control & PIN_BASED_POSTED_INTERRUPT)
 #define cpu_has_vmx_vmcs_shadowing \
     (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_VMCS_SHADOWING)
+#define cpu_has_vmx_pml \
+    (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_PML)
 
 #define VMCS_RID_TYPE_MASK              0x80000000
 
@@ -318,6 +322,7 @@ enum vmcs_field {
     GUEST_LDTR_SELECTOR             = 0x0000080c,
     GUEST_TR_SELECTOR               = 0x0000080e,
     GUEST_INTR_STATUS               = 0x00000810,
+    GUEST_PML_INDEX                 = 0x00000812,
     HOST_ES_SELECTOR                = 0x00000c00,
     HOST_CS_SELECTOR                = 0x00000c02,
     HOST_SS_SELECTOR                = 0x00000c04,
@@ -331,6 +336,7 @@ enum vmcs_field {
     VM_EXIT_MSR_STORE_ADDR          = 0x00002006,
     VM_EXIT_MSR_LOAD_ADDR           = 0x00002008,
     VM_ENTRY_MSR_LOAD_ADDR          = 0x0000200a,
+    PML_ADDRESS                     = 0x0000200e,
     TSC_OFFSET                      = 0x00002010,
     VIRTUAL_APIC_PAGE_ADDR          = 0x00002012,
     APIC_ACCESS_ADDR                = 0x00002014,
xen/include/asm-x86/hvm/vmx/vmx.h +1 -0
index 91c5e18..50f1bfc 100644
@@ -185,6 +185,7 @@ static inline unsigned long pi_get_pir(struct pi_desc *pi_desc, int group)
 #define EXIT_REASON_XSETBV              55
 #define EXIT_REASON_APIC_WRITE          56
 #define EXIT_REASON_INVPCID             58
+#define EXIT_REASON_PML_FULL            62
 
 /*
  * Interruption-information format
Signature · 1 line
2.1.0
#13 lore raw

Re: [v2 04/11] vmx: add PML definition and feature detection.

Quoted 52 lines

From: Kai Huang [mailto:[email protected]]
Sent: Wednesday, April 15, 2015 3:04 PM

The patch adds PML definition and feature detection. Note PML won't be detected
if PML is disabled from boot parameter. PML is also disabled in construct_vmcs,
as it will only be enabled when domain is switched to log dirty mode.

---
 xen/arch/x86/hvm/vmx/vmcs.c        | 22 ++++++++++++++++++++++
 xen/include/asm-x86/hvm/vmx/vmcs.h |  6 ++++++
 xen/include/asm-x86/hvm/vmx/vmx.h  |  1 +
 3 files changed, 29 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
index 4fff46d..d120370 100644
@@ -141,6 +141,7 @@ static void __init vmx_display_features(void)
     P(cpu_has_vmx_virtual_intr_delivery, "Virtual Interrupt Delivery");
     P(cpu_has_vmx_posted_intr_processing, "Posted Interrupt Processing");
     P(cpu_has_vmx_vmcs_shadowing, "VMCS shadowing");
+    P(cpu_has_vmx_pml, "Page Modification Logging");
 #undef P
 
     if ( !printed )
@@ -238,6 +239,8 @@ static int vmx_init_vmcs_config(void)
             opt |= SECONDARY_EXEC_ENABLE_VPID;
         if ( opt_unrestricted_guest_enabled )
             opt |= SECONDARY_EXEC_UNRESTRICTED_GUEST;
+        if ( opt_pml_enabled )
+            opt |= SECONDARY_EXEC_ENABLE_PML;
 
         /*
          * "APIC Register Virtualization" and "Virtual Interrupt Delivery"
@@ -284,6 +287,14 @@ static int vmx_init_vmcs_config(void)
          */
         if ( !(_vmx_ept_vpid_cap & VMX_VPID_INVVPID_ALL_CONTEXT) )
             _vmx_secondary_exec_control &=
 ~SECONDARY_EXEC_ENABLE_VPID;
+
+        /*
+         * PML cannot be supported if EPT A/D bits is not supported.
 Actually,
+         * PML should not be detected if EPT A/D bits is not supported, but

for

xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+         * sure we do the check anyway.
+         */
+        if ( !(_vmx_ept_vpid_cap & VMX_EPT_AD_BIT) )
+            _vmx_secondary_exec_control &=
Quoted 2 lines
~SECONDARY_EXEC_ENABLE_PML;
     }

the comment is not very clear. I think you just want to say "EPT A/D bit is required for PML" or no comment at all.

Quoted 97 lines

if ( _vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT )

xen/arch/x86/hvm/vmx/vmcs.c +8 -0
@@ -304,6 +315,14 @@ static int vmx_init_vmcs_config(void)
                   SECONDARY_EXEC_UNRESTRICTED_GUEST);
     }
 
+    /* PML cannot be supported if EPT is not used */
+    if ( !(_vmx_secondary_exec_control &
 SECONDARY_EXEC_ENABLE_EPT) )
+        _vmx_secondary_exec_control &=
 ~SECONDARY_EXEC_ENABLE_PML;
+
+    /* Turn off opt_pml_enabled if PML feature is not present */
+    if ( !(_vmx_secondary_exec_control &
 SECONDARY_EXEC_ENABLE_PML) )
+        opt_pml_enabled = 0;
+

if ( (_vmx_secondary_exec_control &
SECONDARY_EXEC_PAUSE_LOOP_EXITING) &&

           ple_gap == 0 )
     {
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
@@ -1039,6 +1058,9 @@ static int construct_vmcs(struct vcpu *v)
         __vmwrite(POSTED_INTR_NOTIFICATION_VECTOR,
 posted_intr_vector);
     }
 
+    /* Disable PML anyway here as it will only be enabled in log dirty mode
 */
+    v->arch.hvm_vmx.secondary_exec_control &=
 ~SECONDARY_EXEC_ENABLE_PML;
+
     /* Host data selectors. */
     __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
     __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);
xen/include/asm-x86/hvm/vmx/vmcs.h +6 -0
index 6fce6aa..f831a78 100644
@@ -215,6 +215,7 @@ extern u32 vmx_vmentry_control;
 #define SECONDARY_EXEC_ENABLE_INVPCID           0x00001000
 #define SECONDARY_EXEC_ENABLE_VMFUNC            0x00002000
 #define SECONDARY_EXEC_ENABLE_VMCS_SHADOWING    0x00004000
+#define SECONDARY_EXEC_ENABLE_PML               0x00020000
 extern u32 vmx_secondary_exec_control;
 
 #define VMX_EPT_EXEC_ONLY_SUPPORTED             0x00000001
@@ -226,6 +227,7 @@ extern u32 vmx_secondary_exec_control;
 #define VMX_EPT_INVEPT_INSTRUCTION              0x00100000
 #define VMX_EPT_INVEPT_SINGLE_CONTEXT           0x02000000
 #define VMX_EPT_INVEPT_ALL_CONTEXT              0x04000000
+#define VMX_EPT_AD_BIT                          0x00200000
 
 #define VMX_MISC_VMWRITE_ALL                    0x20000000
 
@@ -274,6 +276,8 @@ extern u32 vmx_secondary_exec_control;
     (vmx_pin_based_exec_control & PIN_BASED_POSTED_INTERRUPT)
 #define cpu_has_vmx_vmcs_shadowing \
     (vmx_secondary_exec_control &
 SECONDARY_EXEC_ENABLE_VMCS_SHADOWING)
+#define cpu_has_vmx_pml \
+    (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_PML)
 
 #define VMCS_RID_TYPE_MASK              0x80000000
@@ -318,6 +322,7 @@ enum vmcs_field {
     GUEST_LDTR_SELECTOR             = 0x0000080c,
     GUEST_TR_SELECTOR               = 0x0000080e,
     GUEST_INTR_STATUS               = 0x00000810,
+    GUEST_PML_INDEX                 = 0x00000812,
     HOST_ES_SELECTOR                = 0x00000c00,
     HOST_CS_SELECTOR                = 0x00000c02,
     HOST_SS_SELECTOR                = 0x00000c04,
@@ -331,6 +336,7 @@ enum vmcs_field {
     VM_EXIT_MSR_STORE_ADDR          = 0x00002006,
     VM_EXIT_MSR_LOAD_ADDR           = 0x00002008,
     VM_ENTRY_MSR_LOAD_ADDR          = 0x0000200a,
+    PML_ADDRESS                     = 0x0000200e,
     TSC_OFFSET                      = 0x00002010,
     VIRTUAL_APIC_PAGE_ADDR          = 0x00002012,
     APIC_ACCESS_ADDR                = 0x00002014,
xen/include/asm-x86/hvm/vmx/vmx.h +1 -0
index 91c5e18..50f1bfc 100644
@@ -185,6 +185,7 @@ static inline unsigned long pi_get_pir(struct pi_desc
 *pi_desc, int group)
 #define EXIT_REASON_XSETBV              55
 #define EXIT_REASON_APIC_WRITE          56
 #define EXIT_REASON_INVPCID             58
+#define EXIT_REASON_PML_FULL            62
 
 /*

* Interruption-information format
--
2.1.0

author
#14 lore raw

Re: [v2 04/11] vmx: add PML definition and feature detection.

Quoted 48 lines · Kevin
Quoted 48 lines

From: Kai Huang [mailto:[email protected]]
Sent: Wednesday, April 15, 2015 3:04 PM

The patch adds PML definition and feature detection. Note PML won't be detected
if PML is disabled from boot parameter. PML is also disabled in construct_vmcs,
as it will only be enabled when domain is switched to log dirty mode.

---
  xen/arch/x86/hvm/vmx/vmcs.c        | 22 ++++++++++++++++++++++
  xen/include/asm-x86/hvm/vmx/vmcs.h |  6 ++++++
  xen/include/asm-x86/hvm/vmx/vmx.h  |  1 +
  3 files changed, 29 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
index 4fff46d..d120370 100644
@@ -141,6 +141,7 @@ static void __init vmx_display_features(void)
      P(cpu_has_vmx_virtual_intr_delivery, "Virtual Interrupt Delivery");
      P(cpu_has_vmx_posted_intr_processing, "Posted Interrupt Processing");
      P(cpu_has_vmx_vmcs_shadowing, "VMCS shadowing");
+    P(cpu_has_vmx_pml, "Page Modification Logging");
  #undef P
 
      if ( !printed )
@@ -238,6 +239,8 @@ static int vmx_init_vmcs_config(void)
              opt |= SECONDARY_EXEC_ENABLE_VPID;
          if ( opt_unrestricted_guest_enabled )
              opt |= SECONDARY_EXEC_UNRESTRICTED_GUEST;
+        if ( opt_pml_enabled )
+            opt |= SECONDARY_EXEC_ENABLE_PML;
 
          /*
           * "APIC Register Virtualization" and "Virtual Interrupt Delivery"
@@ -284,6 +287,14 @@ static int vmx_init_vmcs_config(void)
           */
          if ( !(_vmx_ept_vpid_cap & VMX_VPID_INVVPID_ALL_CONTEXT) )
              _vmx_secondary_exec_control &=
 ~SECONDARY_EXEC_ENABLE_VPID;
+
+        /*
+         * PML cannot be supported if EPT A/D bits is not supported.
 Actually,
+         * PML should not be detected if EPT A/D bits is not supported, but

for

Quoted 8 lines
Quoted 6 lines
xen/arch/x86/hvm/vmx/vmcs.c +4 -0
+         * sure we do the check anyway.
+         */
+        if ( !(_vmx_ept_vpid_cap & VMX_EPT_AD_BIT) )
+            _vmx_secondary_exec_control &=
~SECONDARY_EXEC_ENABLE_PML;
      }

the comment is not very clear. I think you just want to say "EPT A/D bit is required for PML" or no comment at all.

Sure, I'll change it to "EPT A/D bit is required for PML".

Thanks,
-Kai

Quoted 102 lines
Quoted 94 lines

if ( _vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT )

xen/arch/x86/hvm/vmx/vmcs.c +8 -0
@@ -304,6 +315,14 @@ static int vmx_init_vmcs_config(void)
                    SECONDARY_EXEC_UNRESTRICTED_GUEST);
      }
 
+    /* PML cannot be supported if EPT is not used */
+    if ( !(_vmx_secondary_exec_control &
 SECONDARY_EXEC_ENABLE_EPT) )
+        _vmx_secondary_exec_control &=
 ~SECONDARY_EXEC_ENABLE_PML;
+
+    /* Turn off opt_pml_enabled if PML feature is not present */
+    if ( !(_vmx_secondary_exec_control &
 SECONDARY_EXEC_ENABLE_PML) )
+        opt_pml_enabled = 0;
+

if ( (_vmx_secondary_exec_control &
SECONDARY_EXEC_PAUSE_LOOP_EXITING) &&

            ple_gap == 0 )
      {
xen/arch/x86/hvm/vmx/vmcs.c +3 -0
@@ -1039,6 +1058,9 @@ static int construct_vmcs(struct vcpu *v)
          __vmwrite(POSTED_INTR_NOTIFICATION_VECTOR,
 posted_intr_vector);
      }
 
+    /* Disable PML anyway here as it will only be enabled in log dirty mode
 */
+    v->arch.hvm_vmx.secondary_exec_control &=
 ~SECONDARY_EXEC_ENABLE_PML;
+
      /* Host data selectors. */
      __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
      __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);
xen/include/asm-x86/hvm/vmx/vmcs.h +6 -0
index 6fce6aa..f831a78 100644
@@ -215,6 +215,7 @@ extern u32 vmx_vmentry_control;
  #define SECONDARY_EXEC_ENABLE_INVPCID           0x00001000
  #define SECONDARY_EXEC_ENABLE_VMFUNC            0x00002000
  #define SECONDARY_EXEC_ENABLE_VMCS_SHADOWING    0x00004000
+#define SECONDARY_EXEC_ENABLE_PML               0x00020000
  extern u32 vmx_secondary_exec_control;
 
  #define VMX_EPT_EXEC_ONLY_SUPPORTED             0x00000001
@@ -226,6 +227,7 @@ extern u32 vmx_secondary_exec_control;
  #define VMX_EPT_INVEPT_INSTRUCTION              0x00100000
  #define VMX_EPT_INVEPT_SINGLE_CONTEXT           0x02000000
  #define VMX_EPT_INVEPT_ALL_CONTEXT              0x04000000
+#define VMX_EPT_AD_BIT                          0x00200000
 
  #define VMX_MISC_VMWRITE_ALL                    0x20000000
 
@@ -274,6 +276,8 @@ extern u32 vmx_secondary_exec_control;
      (vmx_pin_based_exec_control & PIN_BASED_POSTED_INTERRUPT)
  #define cpu_has_vmx_vmcs_shadowing \
      (vmx_secondary_exec_control &
 SECONDARY_EXEC_ENABLE_VMCS_SHADOWING)
+#define cpu_has_vmx_pml \
+    (vmx_secondary_exec_control & SECONDARY_EXEC_ENABLE_PML)
 
  #define VMCS_RID_TYPE_MASK              0x80000000
@@ -318,6 +322,7 @@ enum vmcs_field {
      GUEST_LDTR_SELECTOR             = 0x0000080c,
      GUEST_TR_SELECTOR               = 0x0000080e,
      GUEST_INTR_STATUS               = 0x00000810,
+    GUEST_PML_INDEX                 = 0x00000812,
      HOST_ES_SELECTOR                = 0x00000c00,
      HOST_CS_SELECTOR                = 0x00000c02,
      HOST_SS_SELECTOR                = 0x00000c04,
@@ -331,6 +336,7 @@ enum vmcs_field {
      VM_EXIT_MSR_STORE_ADDR          = 0x00002006,
      VM_EXIT_MSR_LOAD_ADDR           = 0x00002008,
      VM_ENTRY_MSR_LOAD_ADDR          = 0x0000200a,
+    PML_ADDRESS                     = 0x0000200e,
      TSC_OFFSET                      = 0x00002010,
      VIRTUAL_APIC_PAGE_ADDR          = 0x00002012,
      APIC_ACCESS_ADDR                = 0x00002014,
xen/include/asm-x86/hvm/vmx/vmx.h +1 -0
index 91c5e18..50f1bfc 100644
@@ -185,6 +185,7 @@ static inline unsigned long pi_get_pir(struct pi_desc
 *pi_desc, int group)
  #define EXIT_REASON_XSETBV              55
  #define EXIT_REASON_APIC_WRITE          56
  #define EXIT_REASON_INVPCID             58
+#define EXIT_REASON_PML_FULL            62
 
  /*
Quoted 3 lines

* Interruption-information format
--
2.1.0

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

author
#15 lore raw

PATCH v2 5/11 vmx: add new data structure member to support PML

In reply to Kai Huang

A new 4K page pointer is added to arch_vmx_struct as PML buffer for vcpu. And a new 'status' field is added to vmx_domain to indicate whether PML is enabled for the domain or not. The 'status' field also can be used for further similiar purpose.

Note both new members don't have to be initialized to zero explicitly as both vcpu and domain structure are zero-ed when they are created.

---
 xen/include/asm-x86/hvm/vmx/vmcs.h | 7 +++++++
 1 file changed, 7 insertions(+)
xen/include/asm-x86/hvm/vmx/vmcs.h +7 -0
index f831a78..2c679ac 100644
@@ -70,8 +70,12 @@ struct ept_data {
     cpumask_var_t synced_mask;
 };
 
+#define _VMX_DOMAIN_PML_ENABLED    0
+#define VMX_DOMAIN_PML_ENABLED     (1ul << _VMX_DOMAIN_PML_ENABLED)
 struct vmx_domain {
     unsigned long apic_access_mfn;
+    /* VMX_DOMAIN_* */
+    unsigned long status;
 };
 
 struct pi_desc {
@@ -142,6 +146,9 @@ struct arch_vmx_struct {
     /* Bitmap to control vmexit policy for Non-root VMREAD/VMWRITE */
     struct page_info     *vmread_bitmap;
     struct page_info     *vmwrite_bitmap;
+
+#define NR_PML_ENTRIES   512
+    struct page_info     *pml_pg;
 };
 
 int vmx_create_vmcs(struct vcpu *v);
Signature · 1 line
2.1.0
#16 lore raw

Re: [v2 05/11] vmx: add new data structure member to support PML

xen/include/asm-x86/hvm/vmx/vmcs.h struct ept_data { · line 78

Quoted 13 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/include/asm-x86/hvm/vmx/vmcs.h +4 -0
@@ -70,8 +70,12 @@ struct ept_data {
     cpumask_var_t synced_mask;
 };
 
+#define _VMX_DOMAIN_PML_ENABLED    0
+#define VMX_DOMAIN_PML_ENABLED     (1ul << _VMX_DOMAIN_PML_ENABLED)
 struct vmx_domain {
     unsigned long apic_access_mfn;
+    /* VMX_DOMAIN_* */
+    unsigned long status;

Please us "unsigned int" until 32 bits wouldn't suffice anymore. This will (on the average) produce slightly smaller code.

Jan

author
#17 lore raw

Re: [v2 05/11] vmx: add new data structure member to support PML

Quoted 7 lines · Jan Beulich
Quoted 7 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/include/asm-x86/hvm/vmx/vmcs.h +0 -0
@@ -70,8 +70,12 @@ struct ept_data {
      cpumask_var_t synced_mask;
  };
 
Quoted 8 lines

xen/include/asm-x86/hvm/vmx/vmcs.h struct ept_data { · line 78

Quoted 6 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +4 -0
+#define _VMX_DOMAIN_PML_ENABLED    0
+#define VMX_DOMAIN_PML_ENABLED     (1ul << _VMX_DOMAIN_PML_ENABLED)
  struct vmx_domain {
      unsigned long apic_access_mfn;
+    /* VMX_DOMAIN_* */
+    unsigned long status;

Please us "unsigned int" until 32 bits wouldn't suffice anymore. This will (on the average) produce slightly smaller code.

Sure.

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#18 lore raw

Re: [v2 05/11] vmx: add new data structure member to support PML

In reply to Kai Huang
Quoted 9 lines

From: Kai Huang [mailto:[email protected]]
Sent: Wednesday, April 15, 2015 3:04 PM

A new 4K page pointer is added to arch_vmx_struct as PML buffer for vcpu. And a
new 'status' field is added to vmx_domain to indicate whether PML is enabled for
the domain or not. The 'status' field also can be used for further similiar purpose.

not sure about the last sentence. what's the similar purpose to "whether PML is enabled"? :-)

Quoted 3 lines

Note both new members don't have to be initialized to zero explicitly as both vcpu and domain structure are zero-ed when they are created.

no initialization in this patch, so why explaining it here?

Quoted 26 lines
---
 xen/include/asm-x86/hvm/vmx/vmcs.h | 7 +++++++
 1 file changed, 7 insertions(+)
xen/include/asm-x86/hvm/vmx/vmcs.h +4 -0
index f831a78..2c679ac 100644
@@ -70,8 +70,12 @@ struct ept_data {
     cpumask_var_t synced_mask;
 };
 
+#define _VMX_DOMAIN_PML_ENABLED    0
+#define VMX_DOMAIN_PML_ENABLED     (1ul <<
 _VMX_DOMAIN_PML_ENABLED)
 struct vmx_domain {
     unsigned long apic_access_mfn;
+    /* VMX_DOMAIN_* */
+    unsigned long status;
 };
 

struct pi_desc {

xen/include/asm-x86/hvm/vmx/vmcs.h struct arch_vmx_struct { · line 151

Quoted 6 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +3 -0
@@ -142,6 +146,9 @@ struct arch_vmx_struct {
     /* Bitmap to control vmexit policy for Non-root VMREAD/VMWRITE */
     struct page_info     *vmread_bitmap;
     struct page_info     *vmwrite_bitmap;
+
+#define NR_PML_ENTRIES   512
+    struct page_info     *pml_pg;

move the macro out of the structure. and is pml_buffer or pml_buf more clear?

Quoted 5 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +0 -1
 };
 
 int vmx_create_vmcs(struct vcpu *v);
--

2.1.0

author
#19 lore raw

Re: [v2 05/11] vmx: add new data structure member to support PML

Quoted 11 lines · Kevin
Quoted 9 lines

From: Kai Huang [mailto:[email protected]]
Sent: Wednesday, April 15, 2015 3:04 PM

A new 4K page pointer is added to arch_vmx_struct as PML buffer for vcpu. And a
new 'status' field is added to vmx_domain to indicate whether PML is enabled for
the domain or not. The 'status' field also can be used for further similiar purpose.

not sure about the last sentence. what's the similar purpose to "whether PML is enabled"? :-)

I mean potentially there might be such feature in the future, and I can't give you an example right now. If you are just commenting the description here but fine with the current code, I can remove that last sentence if you like. Or do you suggest to just use a "bool_t pml_enabled"? I am fine with both, but looks there's no objection from others so I intend to keep it as 'unsigned int status', if you agree.

Quoted 4 lines
Quoted 3 lines

Note both new members don't have to be initialized to zero explicitly as both vcpu and domain structure are zero-ed when they are created.

no initialization in this patch, so why explaining it here?

OK. Looks it's a common sense to all of you so I'll just remove this sentence.

Quoted 24 lines
Quoted 24 lines
---
  xen/include/asm-x86/hvm/vmx/vmcs.h | 7 +++++++
  1 file changed, 7 insertions(+)
xen/include/asm-x86/hvm/vmx/vmcs.h +4 -0
index f831a78..2c679ac 100644
@@ -70,8 +70,12 @@ struct ept_data {
      cpumask_var_t synced_mask;
  };
 
+#define _VMX_DOMAIN_PML_ENABLED    0
+#define VMX_DOMAIN_PML_ENABLED     (1ul <<
 _VMX_DOMAIN_PML_ENABLED)
  struct vmx_domain {
      unsigned long apic_access_mfn;
+    /* VMX_DOMAIN_* */
+    unsigned long status;
  };
 
Quoted 9 lines

xen/include/asm-x86/hvm/vmx/vmcs.h struct arch_vmx_struct { · line 151

Quoted 8 lines
  struct pi_desc {
xen/include/asm-x86/hvm/vmx/vmcs.h +3 -0
@@ -142,6 +146,9 @@ struct arch_vmx_struct {
      /* Bitmap to control vmexit policy for Non-root VMREAD/VMWRITE */
      struct page_info     *vmread_bitmap;
      struct page_info     *vmwrite_bitmap;
+
+#define NR_PML_ENTRIES   512
+    struct page_info     *pml_pg;

move the macro out of the structure.

OK. I will move it just above the declaration of struct arch_vmx_struct.

Quoted 1 line

and is pml_buffer or pml_buf more clear?

To me pml_buffer or pml_buf is more likely a virtual address you can access the buffer directly, while pml_pg indicates it's a pointer of struct page_info. If you you look at patch 6, you can find statements like:

    uint64_t *pml_buf;

    pml_buf = __map_domain_page(v->arch.hvm_vmx.pml_pg);

So I intend to keep it.

Thanks,
-Kai

Quoted 11 lines
Quoted 6 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +0 -1
  };
 
  int vmx_create_vmcs(struct vcpu *v);
--

2.1.0

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

author
#20 lore raw

Re: [v2 05/11] vmx: add new data structure member to support PML

Quoted 12 lines · Kai Huang
Quoted 9 lines · Kevin
Quoted 9 lines

From: Kai Huang [mailto:[email protected]]
Sent: Wednesday, April 15, 2015 3:04 PM

A new 4K page pointer is added to arch_vmx_struct as PML buffer for vcpu. And a
new 'status' field is added to vmx_domain to indicate whether PML is enabled for
the domain or not. The 'status' field also can be used for further similiar purpose.

Quoted 3 lines
Quoted 2 lines

not sure about the last sentence. what's the similar purpose to "whether PML is enabled"? :-)

I mean potentially there might be such feature in the future, and I can't give you an example right now. If you are just commenting the description here but fine with the current code, I can remove that last sentence if you like. Or do you suggest to just use a "bool_t pml_enabled"? I am fine with both, but looks there's no objection from others so I intend to keep it as 'unsigned int status', if you agree.

Hi Kevin,

What's your opinion here? Is 'unsigned int status' OK to you?

Quoted 44 lines
Quoted 5 lines
Quoted 4 lines

Note both new members don't have to be initialized to zero explicitly as both vcpu and domain structure are zero-ed when they are created.

no initialization in this patch, so why explaining it here?

OK. Looks it's a common sense to all of you so I'll just remove this sentence.

Quoted 24 lines
Quoted 24 lines
---
  xen/include/asm-x86/hvm/vmx/vmcs.h | 7 +++++++
  1 file changed, 7 insertions(+)
xen/include/asm-x86/hvm/vmx/vmcs.h +4 -0
index f831a78..2c679ac 100644
@@ -70,8 +70,12 @@ struct ept_data {
      cpumask_var_t synced_mask;
  };
 
+#define _VMX_DOMAIN_PML_ENABLED    0
+#define VMX_DOMAIN_PML_ENABLED     (1ul <<
 _VMX_DOMAIN_PML_ENABLED)
  struct vmx_domain {
      unsigned long apic_access_mfn;
+    /* VMX_DOMAIN_* */
+    unsigned long status;
  };
 
Quoted 9 lines

xen/include/asm-x86/hvm/vmx/vmcs.h struct arch_vmx_struct { · line 151

Quoted 8 lines
  struct pi_desc {
xen/include/asm-x86/hvm/vmx/vmcs.h +3 -0
@@ -142,6 +146,9 @@ struct arch_vmx_struct {
      /* Bitmap to control vmexit policy for Non-root VMREAD/VMWRITE */
      struct page_info     *vmread_bitmap;
      struct page_info     *vmwrite_bitmap;
+
+#define NR_PML_ENTRIES   512
+    struct page_info     *pml_pg;

move the macro out of the structure.

OK. I will move it just above the declaration of struct arch_vmx_struct.

Quoted 1 line

and is pml_buffer or pml_buf more clear?

Quoted 7 lines

To me pml_buffer or pml_buf is more likely a virtual address you can access the buffer directly, while pml_pg indicates it's a pointer of struct page_info. If you you look at patch 6, you can find statements like:

    uint64_t *pml_buf;

    pml_buf = __map_domain_page(v->arch.hvm_vmx.pml_pg);

So I intend to keep it.

And this one? Are you OK with 'pml_pg'?

Thanks,
-Kai

Quoted 20 lines

Thanks,
-Kai

Quoted 11 lines
Quoted 6 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +0 -0
  };
 
  int vmx_create_vmcs(struct vcpu *v);
Signature · 1 line
2.1.0

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#21 lore raw

Re: [v2 05/11] vmx: add new data structure member to support PML

Quoted 29 lines

From: Kai Huang [mailto:[email protected]]
Sent: Tuesday, April 21, 2015 2:05 PM

Quoted 18 lines · Kai Huang
Quoted 12 lines · Kevin
Quoted 12 lines

From: Kai Huang [mailto:[email protected]]
Sent: Wednesday, April 15, 2015 3:04 PM

A new 4K page pointer is added to arch_vmx_struct as PML buffer for vcpu.
And a
new 'status' field is added to vmx_domain to indicate whether PML is enabled
for
the domain or not. The 'status' field also can be used for further similiar
purpose.

Quoted 3 lines

not sure about the last sentence. what's the similar purpose to "whether PML
is enabled"? :-)

Quoted 6 lines

I mean potentially there might be such feature in the future, and I can't give you an example right now. If you are just commenting the description here but fine with the current code, I can remove that last sentence if you like. Or do you suggest to just use a "bool_t pml_enabled"? I am fine with both, but looks there's no objection from others so I intend to keep it as 'unsigned int status', if you agree.

Quoted 3 lines

Hi Kevin,

What's your opinion here? Is 'unsigned int status' OK to you?

yes

Quoted 53 lines
Quoted 34 lines
Quoted 7 lines
Quoted 6 lines

Note both new members don't have to be initialized to zero explicitly as both
vcpu and domain structure are zero-ed when they are created.

no initialization in this patch, so why explaining it here?

OK. Looks it's a common sense to all of you so I'll just remove this sentence.

Quoted 24 lines
Quoted 24 lines
---
  xen/include/asm-x86/hvm/vmx/vmcs.h | 7 +++++++
  1 file changed, 7 insertions(+)
xen/include/asm-x86/hvm/vmx/vmcs.h +4 -0
index f831a78..2c679ac 100644
@@ -70,8 +70,12 @@ struct ept_data {
      cpumask_var_t synced_mask;
  };
 
+#define _VMX_DOMAIN_PML_ENABLED    0
+#define VMX_DOMAIN_PML_ENABLED     (1ul <<
 _VMX_DOMAIN_PML_ENABLED)
  struct vmx_domain {
      unsigned long apic_access_mfn;
+    /* VMX_DOMAIN_* */
+    unsigned long status;
  };
 
Quoted 3 lines
Quoted 3 lines

xen/include/asm-x86/hvm/vmx/vmcs.h struct arch_vmx_struct { · line 146

Quoted 3 lines
  struct pi_desc {
xen/include/asm-x86/hvm/vmx/vmcs.h +0 -0
@@ -142,6 +146,9 @@ struct arch_vmx_struct {
      /* Bitmap to control vmexit policy for Non-root

VMREAD/VMWRITE */

Quoted 15 lines
Quoted 6 lines

xen/include/asm-x86/hvm/vmx/vmcs.h struct arch_vmx_struct { · line 151

Quoted 5 lines
xen/include/asm-x86/hvm/vmx/vmcs.h +3 -0
      struct page_info     *vmread_bitmap;
      struct page_info     *vmwrite_bitmap;
+
+#define NR_PML_ENTRIES   512
+    struct page_info     *pml_pg;

move the macro out of the structure.

OK. I will move it just above the declaration of struct arch_vmx_struct.

Quoted 1 line

and is pml_buffer or pml_buf more clear?

To me pml_buffer or pml_buf is more likely a virtual address you can access the buffer directly, while pml_pg indicates it's a pointer of struct page_info. If you you look at patch 6, you can find statements like:

Quoted 7 lines
Quoted 5 lines
    uint64_t *pml_buf;

    pml_buf = __map_domain_page(v->arch.hvm_vmx.pml_pg);

So I intend to keep it.

And this one? Are you OK with 'pml_pg'?

good to me too.

author
#22 lore raw

PATCH v2 6/11 vmx: add help functions to support PML

In reply to Kai Huang

This patch adds help functions to enable/disable PML, and flush PML buffer for single vcpu and particular domain for further use.

---
 xen/arch/x86/hvm/vmx/vmcs.c        | 178 +++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/hvm/vmx/vmcs.h |   9 ++
 2 files changed, 187 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +178 -0
index d120370..d3cb50f 100644
@@ -1328,6 +1328,184 @@ void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector)
                 &v->arch.hvm_vmx.eoi_exitmap_changed);
 }
 
+bool_t vmx_vcpu_pml_enabled(const struct vcpu *v)
+{
+    return !!(v->arch.hvm_vmx.secondary_exec_control &
+              SECONDARY_EXEC_ENABLE_PML);
+}
+
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    if ( vmx_vcpu_pml_enabled(v) )
+        return 0;
+
+    v->arch.hvm_vmx.pml_pg = d->arch.paging.alloc_page(d);
+    if ( !v->arch.hvm_vmx.pml_pg )
+        return -ENOMEM;
+
+    vmx_vmcs_enter(v);
+
+    __vmwrite(PML_ADDRESS, page_to_mfn(v->arch.hvm_vmx.pml_pg) << PAGE_SHIFT);
+    __vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);
+
+    v->arch.hvm_vmx.secondary_exec_control |= SECONDARY_EXEC_ENABLE_PML;
+
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+              v->arch.hvm_vmx.secondary_exec_control);
+
+    vmx_vmcs_exit(v);
+
+    return 0;
+}
+
+void vmx_vcpu_disable_pml(struct vcpu *v)
+{
+    if ( !vmx_vcpu_pml_enabled(v) )
+        return;
+
+    /* Make sure we don't lose any logged GPAs */
+    vmx_vcpu_flush_pml_buffer(v);
+
+    vmx_vmcs_enter(v);
+
+    v->arch.hvm_vmx.secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+              v->arch.hvm_vmx.secondary_exec_control);
+
+    vmx_vmcs_exit(v);
+
+    v->domain->arch.paging.free_page(v->domain, v->arch.hvm_vmx.pml_pg);
+    v->arch.hvm_vmx.pml_pg = NULL;
+}
+
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);
+
+    /* Do nothing if PML buffer is empty */
+    if ( pml_idx == (NR_PML_ENTRIES - 1) )
+        goto out;
+
+    pml_buf = __map_domain_page(v->arch.hvm_vmx.pml_pg);
+
+    /*
+     * PML index can be either 2^16-1 (buffer is full), or 0~511 (buffer is not
+     * full), and in latter case PML index always points to next available
+     * entity.
+     */
+    if (pml_idx >= NR_PML_ENTRIES)
+        pml_idx = 0;
+    else
+        pml_idx++;
+
+    for ( ; pml_idx < NR_PML_ENTRIES; pml_idx++ )
+    {
+        unsigned long gfn = pml_buf[pml_idx] >> PAGE_SHIFT;
+        /*
+         * Need to change type from log-dirty to normal memory for logged GFN.
+         * hap_track_dirty_vram depends on it to work. And we really only need
+         * to mark GFNs which hve been successfully changed from log-dirty to
+         * normal memory to be dirty.
+         */
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
+            paging_mark_gfn_dirty(v->domain, gfn);
+    }
+
+    unmap_domain_page(pml_buf);
+
+    /* Reset PML index */
+    __vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);
+
+out:
+    vmx_vmcs_exit(v);
+}
+
+bool_t vmx_domain_pml_enabled(const struct domain *d)
+{
+    return !!(d->arch.hvm_domain.vmx.status & VMX_DOMAIN_PML_ENABLED);
+}
+
+/*
+ * This function enables PML for particular domain. It should be called when
+ * domain is paused.
+ *
+ * PML needs to be enabled globally for all vcpus of the domain, as PML buffer
+ * and PML index are pre-vcpu, but EPT table is shared by vcpus, therefore
+ * enabling PML on partial vcpus won't work.
+ */
+int vmx_domain_enable_pml(struct domain *d)
+{
+    struct vcpu *v;
+    int rc;
+
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( vmx_domain_pml_enabled(d) )
+        return 0;
+
+    for_each_vcpu( d, v )
+        if ( (rc = vmx_vcpu_enable_pml(v)) != 0 )
+            goto error;
+
+    d->arch.hvm_domain.vmx.status |= VMX_DOMAIN_PML_ENABLED;
+
+    return 0;
+
+error:
+    for_each_vcpu( d, v )
+        if ( vmx_vcpu_pml_enabled(v) )
+            vmx_vcpu_disable_pml(v);
+    return rc;
+}
+
+/*
+ * Disable PML for particular domain. Called when domain is paused.
+ *
+ * The same as enabling PML for domain, disabling PML should be done for all
+ * vcpus at once.
+ */
+void vmx_domain_disable_pml(struct domain *d)
+{
+    struct vcpu *v;
+
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( !vmx_domain_pml_enabled(d) )
+        return;
+
+    for_each_vcpu( d, v )
+        vmx_vcpu_disable_pml(v);
+
+    d->arch.hvm_domain.vmx.status &= ~VMX_DOMAIN_PML_ENABLED;
+}
+
+/*
+ * Flush PML buffer of all vcpus, and update the logged dirty pages to log-dirty
+ * radix tree. Called when domain is paused.
+ */
+void vmx_domain_flush_pml_buffers(struct domain *d)
+{
+    struct vcpu *v;
+
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( !vmx_domain_pml_enabled(d) )
+        return;
+
+    for_each_vcpu( d, v )
+        vmx_vcpu_flush_pml_buffer(v);
+}
+
 int vmx_create_vmcs(struct vcpu *v)
 {
     struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
xen/include/asm-x86/hvm/vmx/vmcs.h +9 -0
index 2c679ac..ceb09bf 100644
@@ -498,6 +498,15 @@ static inline int vmx_add_host_load_msr(u32 msr)
 
 DECLARE_PER_CPU(bool_t, vmxon);
 
+bool_t vmx_vcpu_pml_enabled(const struct vcpu *v);
+int vmx_vcpu_enable_pml(struct vcpu *v);
+void vmx_vcpu_disable_pml(struct vcpu *v);
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v);
+bool_t vmx_domain_pml_enabled(const struct domain *d);
+int vmx_domain_enable_pml(struct domain *d);
+void vmx_domain_disable_pml(struct domain *d);
+void vmx_domain_flush_pml_buffers(struct domain *d);
+
 #endif /* ASM_X86_HVM_VMX_VMCS_H__ */
 
 /*
Signature · 1 line
2.1.0
#23 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1344

Quoted 9 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    if ( vmx_vcpu_pml_enabled(v) )
+        return 0;
+
+    v->arch.hvm_vmx.pml_pg = d->arch.paging.alloc_page(d);

So you latch v->domain into d for this invocation, ...

Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+void vmx_vcpu_disable_pml(struct vcpu *v)
+{
+    if ( !vmx_vcpu_pml_enabled(v) )
+        return;
+
+    /* Make sure we don't lose any logged GPAs */
+    vmx_vcpu_flush_pml_buffer(v);

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1379

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+
+    vmx_vmcs_enter(v);
+
+    v->arch.hvm_vmx.secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+              v->arch.hvm_vmx.secondary_exec_control);
+
+    vmx_vmcs_exit(v);
+
+    v->domain->arch.paging.free_page(v->domain, v->arch.hvm_vmx.pml_pg);

... but not for this one. Please be consistent.

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1392

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);

Don't you require the vCPU to be non-running or current when you get here? If so, perhaps add a respective ASSERT()?

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+
+    /* Do nothing if PML buffer is empty */
+    if ( pml_idx == (NR_PML_ENTRIES - 1) )
+        goto out;
+
+    pml_buf = __map_domain_page(v->arch.hvm_vmx.pml_pg);
+
+    /*
+     * PML index can be either 2^16-1 (buffer is full), or 0~511 (buffer is not
+     * full), and in latter case PML index always points to next available

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1412

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+     * entity.
+     */
+    if (pml_idx >= NR_PML_ENTRIES)
+        pml_idx = 0;
+    else
+        pml_idx++;
+
+    for ( ; pml_idx < NR_PML_ENTRIES; pml_idx++ )
+    {
+        unsigned long gfn = pml_buf[pml_idx] >> PAGE_SHIFT;

Blank line here please.

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1420

Quoted 8 lines
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+        /*
+         * Need to change type from log-dirty to normal memory for logged GFN.
+         * hap_track_dirty_vram depends on it to work. And we really only need
+         * to mark GFNs which hve been successfully changed from log-dirty to
+         * normal memory to be dirty.
+         */
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )

Indentation.

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1429

Quoted 9 lines
xen/arch/x86/hvm/vmx/vmcs.c +9 -0
+            paging_mark_gfn_dirty(v->domain, gfn);
+    }
+
+    unmap_domain_page(pml_buf);
+
+    /* Reset PML index */
+    __vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);
+
+out:

Labels indented by at least one space please.

Jan

author
#24 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 21 lines · Jan Beulich

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1344

Quoted 9 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    if ( vmx_vcpu_pml_enabled(v) )
+        return 0;
+
+    v->arch.hvm_vmx.pml_pg = d->arch.paging.alloc_page(d);

So you latch v->domain into d for this invocation, ...

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+void vmx_vcpu_disable_pml(struct vcpu *v)
+{
+    if ( !vmx_vcpu_pml_enabled(v) )
+        return;
+
+    /* Make sure we don't lose any logged GPAs */
+    vmx_vcpu_flush_pml_buffer(v);
+
+    vmx_vmcs_enter(v);
+
Quoted 8 lines

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1379

Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+    v->arch.hvm_vmx.secondary_exec_control &= ~SECONDARY_EXEC_ENABLE_PML;
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+              v->arch.hvm_vmx.secondary_exec_control);
+
+    vmx_vmcs_exit(v);
+
+    v->domain->arch.paging.free_page(v->domain, v->arch.hvm_vmx.pml_pg);

... but not for this one. Please be consistent.

Hmm. My bad. I'll use v->domain in both function.

Quoted 13 lines

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1392

Quoted 11 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);

Don't you require the vCPU to be non-running or current when you get here? If so, perhaps add a respective ASSERT()?

Yes an ASSERT would be better.

v->pause_count will be increased if vcpu is kicked out by domain_pause explicitly, but looks the same thing won't be done if vcpu is kicked out by PML buffer full VMEXIT. So should the ASSERT be done like below?

ASSERT(atomic_read(&v->pause_count) || (v == current));

Quoted 14 lines
Quoted 14 lines
xen/arch/x86/hvm/vmx/vmcs.c +13 -0
+
+    /* Do nothing if PML buffer is empty */
+    if ( pml_idx == (NR_PML_ENTRIES - 1) )
+        goto out;
+
+    pml_buf = __map_domain_page(v->arch.hvm_vmx.pml_pg);
+
+    /*
+     * PML index can be either 2^16-1 (buffer is full), or 0~511 (buffer is not
+     * full), and in latter case PML index always points to next available
+     * entity.
+     */
+    if (pml_idx >= NR_PML_ENTRIES)
Quoted 8 lines

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1412

Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+        pml_idx = 0;
+    else
+        pml_idx++;
+
+    for ( ; pml_idx < NR_PML_ENTRIES; pml_idx++ )
+    {
+        unsigned long gfn = pml_buf[pml_idx] >> PAGE_SHIFT;

Blank line here please.

Will do.

Quoted 10 lines

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1420

Quoted 9 lines
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+        /*
+         * Need to change type from log-dirty to normal memory for logged GFN.
+         * hap_track_dirty_vram depends on it to work. And we really only need
+         * to mark GFNs which hve been successfully changed from log-dirty to
+         * normal memory to be dirty.
+         */
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )

Indentation.

To be where exactly? Sorry I didn't find an example to refer in such case.

Quoted 11 lines

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1429

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +9 -0
+            paging_mark_gfn_dirty(v->domain, gfn);
+    }
+
+    unmap_domain_page(pml_buf);
+
+    /* Reset PML index */
+    __vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);
+
+out:

Labels indented by at least one space please.

OK. I'll put one space before the "out:" label.

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#25 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 15 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 05:10, <[email protected]> wrote:
Quoted 13 lines · Jan Beulich

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1392

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);

Don't you require the vCPU to be non-running or current when you get here? If so, perhaps add a respective ASSERT()?

Quoted 7 lines

Yes an ASSERT would be better.

v->pause_count will be increased if vcpu is kicked out by domain_pause explicitly, but looks the same thing won't be done if vcpu is kicked out by PML buffer full VMEXIT. So should the ASSERT be done like below?

ASSERT(atomic_read(&v->pause_count) || (v == current));

For one I'd reverse the two parts. And then I think pause count being non-zero is not a sufficient condition - if a non-synchronous pause was issued against the vCPU it may still be running. I'd suggest !vcpu_runnable(v) && !v->is_running, possibly with the pause count check instead of the runnable one if the only permitted case where v != current requires the vCPU to be paused.

Quoted 10 lines
Quoted 9 lines

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1420

Quoted 8 lines
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+        /*
+         * Need to change type from log-dirty to normal memory for logged GFN.
+         * hap_track_dirty_vram depends on it to work. And we really only need
+         * to mark GFNs which hve been successfully changed from log-dirty to
+         * normal memory to be dirty.
+         */
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )

Indentation.

To be where exactly? Sorry I didn't find an example to refer in such case.

p2m_ram_rw should align with the v in v->domain.

Jan

author
#26 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 21 lines · Jan Beulich
Quoted 21 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 05:10, <[email protected]> wrote:
Quoted 13 lines · Jan Beulich

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1392

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);

Don't you require the vCPU to be non-running or current when you get here? If so, perhaps add a respective ASSERT()?

Yes an ASSERT would be better.

v->pause_count will be increased if vcpu is kicked out by domain_pause explicitly, but looks the same thing won't be done if vcpu is kicked out by PML buffer full VMEXIT. So should the ASSERT be done like below?

Quoted 8 lines
Quoted 1 line

ASSERT(atomic_read(&v->pause_count) || (v == current));

For one I'd reverse the two parts. And then I think pause count being non-zero is not a sufficient condition - if a non-synchronous pause was issued against the vCPU it may still be running. I'd suggest !vcpu_runnable(v) && !v->is_running, possibly with the pause count check instead of the runnable one if the only permitted case where v != current requires the vCPU to be paused.

The vmx_vcpu_flush_pml_buffer is only supposed to be called in below cases:

- When PML full VMEXIT happens
- In paging_log_dirty_op & hap_track_dirty_vram, before reporting
dirty pages to userspace.
- In vmx_vcpu_disable_pml, called from vmx_vcpu_destroy, or when
log-dirty mode is disabled.

In the latter two cases, domain_pause is guaranteed to be called before vmx_vcpu_flush_pml_buffer is called, therefore looks there's no possibility of non-synchronous pause of the vcpu.

Or are you suggesting we should suppose this function can be called from any caller, and meanwhile is able to act reasonably?

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+        /*
+         * Need to change type from log-dirty to normal memory for logged GFN.
+         * hap_track_dirty_vram depends on it to work. And we really only need
+         * to mark GFNs which hve been successfully changed from log-dirty to
+         * normal memory to be dirty.
+         */
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
Quoted 3 lines
Quoted 2 lines
Quoted 1 line

Indentation.

To be where exactly? Sorry I didn't find an example to refer in such case.

p2m_ram_rw should align with the v in v->domain.

Understood. Will do.

Thanks,
-Kai

Quoted 3 lines

Jan

#27 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 41 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 08:51, <[email protected]> wrote:
Quoted 21 lines · Jan Beulich
Quoted 21 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 05:10, <[email protected]> wrote:
Quoted 13 lines · Jan Beulich

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1392

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);

Don't you require the vCPU to be non-running or current when you get here? If so, perhaps add a respective ASSERT()?

Yes an ASSERT would be better.

v->pause_count will be increased if vcpu is kicked out by domain_pause explicitly, but looks the same thing won't be done if vcpu is kicked out by PML buffer full VMEXIT. So should the ASSERT be done like below?

Quoted 8 lines
Quoted 1 line

ASSERT(atomic_read(&v->pause_count) || (v == current));

For one I'd reverse the two parts. And then I think pause count being non-zero is not a sufficient condition - if a non-synchronous pause was issued against the vCPU it may still be running. I'd suggest !vcpu_runnable(v) && !v->is_running, possibly with the pause count check instead of the runnable one if the only permitted case where v != current requires the vCPU to be paused.

The vmx_vcpu_flush_pml_buffer is only supposed to be called in below cases:

- When PML full VMEXIT happens
- In paging_log_dirty_op & hap_track_dirty_vram, before reporting
dirty pages to userspace.
- In vmx_vcpu_disable_pml, called from vmx_vcpu_destroy, or when
log-dirty mode is disabled.

Quoted 6 lines

In the latter two cases, domain_pause is guaranteed to be called before vmx_vcpu_flush_pml_buffer is called, therefore looks there's no possibility of non-synchronous pause of the vcpu.

Or are you suggesting we should suppose this function can be called from any caller, and meanwhile is able to act reasonably?

No. All I'm saying is in order to protect against eventual undue future callers, it should assert that its preconditions are met. I.e. if the vCPU is expected to be paused, check that the pause count in non-zero _and_ that the pause actually took effect.

Jan

author
#28 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 43 lines · Jan Beulich
Quoted 43 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 08:51, <[email protected]> wrote:
Quoted 21 lines · Jan Beulich
Quoted 21 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 05:10, <[email protected]> wrote:
Quoted 13 lines · Jan Beulich

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1392

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);

Don't you require the vCPU to be non-running or current when you get here? If so, perhaps add a respective ASSERT()?

Yes an ASSERT would be better.

v->pause_count will be increased if vcpu is kicked out by domain_pause explicitly, but looks the same thing won't be done if vcpu is kicked out by PML buffer full VMEXIT. So should the ASSERT be done like below?

Quoted 8 lines
Quoted 1 line

ASSERT(atomic_read(&v->pause_count) || (v == current));

For one I'd reverse the two parts. And then I think pause count being non-zero is not a sufficient condition - if a non-synchronous pause was issued against the vCPU it may still be running. I'd suggest !vcpu_runnable(v) && !v->is_running, possibly with the pause count check instead of the runnable one if the only permitted case where v != current requires the vCPU to be paused.

The vmx_vcpu_flush_pml_buffer is only supposed to be called in below cases:

- When PML full VMEXIT happens
- In paging_log_dirty_op & hap_track_dirty_vram, before reporting
dirty pages to userspace.
- In vmx_vcpu_disable_pml, called from vmx_vcpu_destroy, or when
log-dirty mode is disabled.

In the latter two cases, domain_pause is guaranteed to be called before vmx_vcpu_flush_pml_buffer is called, therefore looks there's no possibility of non-synchronous pause of the vcpu.

Quoted 6 lines
Quoted 2 lines

Or are you suggesting we should suppose this function can be called from any caller, and meanwhile is able to act reasonably?

No. All I'm saying is in order to protect against eventual undue future callers, it should assert that its preconditions are met. I.e. if the vCPU is expected to be paused, check that the pause count in non-zero _and_ that the pause actually took effect.

I see. I will do as you suggested:

ASSERT((v == current) || (!vcpu_runnable(v) && !v->is_running));

And v != current should be the only case requires the vcpu to be paused.

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#29 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 53 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 09:23, <[email protected]> wrote:
Quoted 43 lines · Jan Beulich
Quoted 43 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 08:51, <[email protected]> wrote:
Quoted 21 lines · Jan Beulich
Quoted 21 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 05:10, <[email protected]> wrote:
Quoted 13 lines · Jan Beulich

Review

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
(quoted diff) +10 -0
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);

Don't you require the vCPU to be non-running or current when you get here? If so, perhaps add a respective ASSERT()?

Yes an ASSERT would be better.

v->pause_count will be increased if vcpu is kicked out by domain_pause explicitly, but looks the same thing won't be done if vcpu is kicked out by PML buffer full VMEXIT. So should the ASSERT be done like below?

Quoted 8 lines
Quoted 1 line

ASSERT(atomic_read(&v->pause_count) || (v == current));

For one I'd reverse the two parts. And then I think pause count being non-zero is not a sufficient condition - if a non-synchronous pause was issued against the vCPU it may still be running. I'd suggest !vcpu_runnable(v) && !v->is_running, possibly with the pause count check instead of the runnable one if the only permitted case where v != current requires the vCPU to be paused.

The vmx_vcpu_flush_pml_buffer is only supposed to be called in below cases:

- When PML full VMEXIT happens
- In paging_log_dirty_op & hap_track_dirty_vram, before reporting
dirty pages to userspace.
- In vmx_vcpu_disable_pml, called from vmx_vcpu_destroy, or when
log-dirty mode is disabled.

In the latter two cases, domain_pause is guaranteed to be called before vmx_vcpu_flush_pml_buffer is called, therefore looks there's no possibility of non-synchronous pause of the vcpu.

Quoted 6 lines
Quoted 2 lines

Or are you suggesting we should suppose this function can be called from any caller, and meanwhile is able to act reasonably?

No. All I'm saying is in order to protect against eventual undue future callers, it should assert that its preconditions are met. I.e. if the vCPU is expected to be paused, check that the pause count in non-zero _and_ that the pause actually took effect.

Quoted 5 lines

I see. I will do as you suggested:

ASSERT((v == current) || (!vcpu_runnable(v) && !v->is_running));

And v != current should be the only case requires the vcpu to be paused.

But if you require (or at least expect) the vCPU to be paused, this isn't what I suggested. Afaict

ASSERT((v == current) || (!v->is_running && atomic_read(v->pause_count)));

would then be the right check (and, while not be a full guarantee that things wouldn't change behind your back, would at least increase chances that the vCPU's runnable state won't change, as the vCPU could have been non-runnable for reasons other than having been paused).

Jan

author
#30 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 59 lines · Jan Beulich
Quoted 51 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 09:23, <[email protected]> wrote:
Quoted 43 lines · Jan Beulich
Quoted 43 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 08:51, <[email protected]> wrote:
Quoted 21 lines · Jan Beulich
Quoted 21 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 05:10, <[email protected]> wrote:
Quoted 13 lines · Jan Beulich

Review

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
(quoted diff) +10 -0
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);

Don't you require the vCPU to be non-running or current when you get here? If so, perhaps add a respective ASSERT()?

Yes an ASSERT would be better.

v->pause_count will be increased if vcpu is kicked out by domain_pause explicitly, but looks the same thing won't be done if vcpu is kicked out by PML buffer full VMEXIT. So should the ASSERT be done like below?

Quoted 8 lines
Quoted 1 line

ASSERT(atomic_read(&v->pause_count) || (v == current));

For one I'd reverse the two parts. And then I think pause count being non-zero is not a sufficient condition - if a non-synchronous pause was issued against the vCPU it may still be running. I'd suggest !vcpu_runnable(v) && !v->is_running, possibly with the pause count check instead of the runnable one if the only permitted case where v != current requires the vCPU to be paused.

The vmx_vcpu_flush_pml_buffer is only supposed to be called in below cases:

- When PML full VMEXIT happens
- In paging_log_dirty_op & hap_track_dirty_vram, before reporting
dirty pages to userspace.
- In vmx_vcpu_disable_pml, called from vmx_vcpu_destroy, or when
log-dirty mode is disabled.

In the latter two cases, domain_pause is guaranteed to be called before vmx_vcpu_flush_pml_buffer is called, therefore looks there's no possibility of non-synchronous pause of the vcpu.

Quoted 6 lines
Quoted 2 lines

Or are you suggesting we should suppose this function can be called from any caller, and meanwhile is able to act reasonably?

No. All I'm saying is in order to protect against eventual undue future callers, it should assert that its preconditions are met. I.e. if the vCPU is expected to be paused, check that the pause count in non-zero _and_ that the pause actually took effect.

Quoted 5 lines

I see. I will do as you suggested:

ASSERT((v == current) || (!vcpu_runnable(v) && !v->is_running));

And v != current should be the only case requires the vcpu to be paused.

But if you require (or at least expect) the vCPU to be paused, this isn't what I suggested. Afaict

Quoted 7 lines

ASSERT((v == current) || (!v->is_running && atomic_read(v->pause_count)));

would then be the right check (and, while not be a full guarantee that things wouldn't change behind your back, would at least increase chances that the vCPU's runnable state won't change, as the vCPU could have been non-runnable for reasons other than having been paused).

You are right. Your last sentence convinced me. I didn't go that far. I will use atomic_read(&v->pause_count) instead of !vcpu_runnable(v).

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

author
#31 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

In reply to Jan Beulich
Quoted 59 lines · Jan Beulich
Quoted 51 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 09:23, <[email protected]> wrote:
Quoted 43 lines · Jan Beulich
Quoted 43 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 08:51, <[email protected]> wrote:
Quoted 21 lines · Jan Beulich
Quoted 21 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 05:10, <[email protected]> wrote:
Quoted 13 lines · Jan Beulich

Review

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
(quoted diff) +10 -0
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);

Don't you require the vCPU to be non-running or current when you get here? If so, perhaps add a respective ASSERT()?

Yes an ASSERT would be better.

v->pause_count will be increased if vcpu is kicked out by domain_pause explicitly, but looks the same thing won't be done if vcpu is kicked out by PML buffer full VMEXIT. So should the ASSERT be done like below?

Quoted 8 lines
Quoted 1 line

ASSERT(atomic_read(&v->pause_count) || (v == current));

For one I'd reverse the two parts. And then I think pause count being non-zero is not a sufficient condition - if a non-synchronous pause was issued against the vCPU it may still be running. I'd suggest !vcpu_runnable(v) && !v->is_running, possibly with the pause count check instead of the runnable one if the only permitted case where v != current requires the vCPU to be paused.

The vmx_vcpu_flush_pml_buffer is only supposed to be called in below cases:

- When PML full VMEXIT happens
- In paging_log_dirty_op & hap_track_dirty_vram, before reporting
dirty pages to userspace.
- In vmx_vcpu_disable_pml, called from vmx_vcpu_destroy, or when
log-dirty mode is disabled.

In the latter two cases, domain_pause is guaranteed to be called before vmx_vcpu_flush_pml_buffer is called, therefore looks there's no possibility of non-synchronous pause of the vcpu.

Quoted 6 lines
Quoted 2 lines

Or are you suggesting we should suppose this function can be called from any caller, and meanwhile is able to act reasonably?

No. All I'm saying is in order to protect against eventual undue future callers, it should assert that its preconditions are met. I.e. if the vCPU is expected to be paused, check that the pause count in non-zero _and_ that the pause actually took effect.

Quoted 5 lines

I see. I will do as you suggested:

ASSERT((v == current) || (!vcpu_runnable(v) && !v->is_running));

And v != current should be the only case requires the vcpu to be paused.

But if you require (or at least expect) the vCPU to be paused, this isn't what I suggested. Afaict

Quoted 7 lines

ASSERT((v == current) || (!v->is_running && atomic_read(v->pause_count)));

would then be the right check (and, while not be a full guarantee that things wouldn't change behind your back, would at least increase chances that the vCPU's runnable state won't change, as the vCPU could have been non-runnable for reasons other than having been paused).

Hi Jan,

I tried the ASSERT with atomic_read(&v->pause_count), and it turns out the ASSERT would fail and panic Xen. The reason is domain_pause only increases d->pause_count, but it doesn't internally increase v->pause_count for all vcpus.

vmx_vcpu_flush_pml_buffer is only supposed to be called from PML buffer full VMEXIT, and vmx_domain_flush_pml_buffer, before which domain_pause should be called.

Sorry that obviously I had some misunderstanding regarding to "require (or at least expect) vCPU to be paused", and looks !vcpu_runnable(v) is the right choice.

What's your opinion?

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#32 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 29 lines
Quoted 1 line
Quoted 1 line · On 24.04.15 at 08:32, <[email protected]> wrote:
Quoted 9 lines · Jan Beulich
Quoted 6 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 09:23, <[email protected]> wrote:

I see. I will do as you suggested:

ASSERT((v == current) || (!vcpu_runnable(v) && !v->is_running));

And v != current should be the only case requires the vcpu to be paused.

But if you require (or at least expect) the vCPU to be paused, this isn't what I suggested. Afaict

Quoted 7 lines

ASSERT((v == current) || (!v->is_running && atomic_read(v->pause_count)));

would then be the right check (and, while not be a full guarantee that things wouldn't change behind your back, would at least increase chances that the vCPU's runnable state won't change, as the vCPU could have been non-runnable for reasons other than having been paused).

Hi Jan,

I tried the ASSERT with atomic_read(&v->pause_count), and it turns out the ASSERT would fail and panic Xen. The reason is domain_pause only increases d->pause_count, but it doesn't internally increase v->pause_count for all vcpus.

vmx_vcpu_flush_pml_buffer is only supposed to be called from PML buffer full VMEXIT, and vmx_domain_flush_pml_buffer, before which domain_pause should be called.

Quoted 5 lines

Sorry that obviously I had some misunderstanding regarding to "require (or at least expect) vCPU to be paused", and looks !vcpu_runnable(v) is the right choice.

What's your opinion?

Then either go with the slightly weaker original (still quoted at the top) or (preferred by me) OR together both pause counts in the condition.

Jan

author
#33 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 29 lines · Jan Beulich
Quoted 29 lines
Quoted 1 line
Quoted 1 line · On 24.04.15 at 08:32, <[email protected]> wrote:
Quoted 9 lines · Jan Beulich
Quoted 6 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 09:23, <[email protected]> wrote:

I see. I will do as you suggested:

ASSERT((v == current) || (!vcpu_runnable(v) && !v->is_running));

And v != current should be the only case requires the vcpu to be paused.

But if you require (or at least expect) the vCPU to be paused, this isn't what I suggested. Afaict

Quoted 7 lines

ASSERT((v == current) || (!v->is_running && atomic_read(v->pause_count)));

would then be the right check (and, while not be a full guarantee that things wouldn't change behind your back, would at least increase chances that the vCPU's runnable state won't change, as the vCPU could have been non-runnable for reasons other than having been paused).

Hi Jan,

I tried the ASSERT with atomic_read(&v->pause_count), and it turns out the ASSERT would fail and panic Xen. The reason is domain_pause only increases d->pause_count, but it doesn't internally increase v->pause_count for all vcpus.

vmx_vcpu_flush_pml_buffer is only supposed to be called from PML buffer full VMEXIT, and vmx_domain_flush_pml_buffer, before which domain_pause should be called.

Quoted 8 lines
Quoted 5 lines

Sorry that obviously I had some misunderstanding regarding to "require (or at least expect) vCPU to be paused", and looks !vcpu_runnable(v) is the right choice.

What's your opinion?

Then either go with the slightly weaker original (still quoted at the top) or (preferred by me) OR together both pause counts in the condition.

Thanks. Then I'd like to use original weaker one (below) instead of explicitly doing OR 'd->pause_count' and 'v->pause_count', as you are not objecting the former :)

ASSERT((v == current) || (!vcpu_runnable(v) && !v->is_running));

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#34 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

In reply to Kai Huang
Quoted 97 lines

From: Kai Huang [mailto:[email protected]]
Sent: Wednesday, April 15, 2015 3:04 PM

This patch adds help functions to enable/disable PML, and flush PML buffer for single vcpu and particular domain for further use.

---
 xen/arch/x86/hvm/vmx/vmcs.c        | 178
+++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/hvm/vmx/vmcs.h |   9 ++
 2 files changed, 187 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +43 -0
index d120370..d3cb50f 100644
@@ -1328,6 +1328,184 @@ void vmx_clear_eoi_exit_bitmap(struct vcpu *v,
 u8 vector)
                 &v->arch.hvm_vmx.eoi_exitmap_changed);
 }
 
+bool_t vmx_vcpu_pml_enabled(const struct vcpu *v)
+{
+    return !!(v->arch.hvm_vmx.secondary_exec_control &
+              SECONDARY_EXEC_ENABLE_PML);
+}
+
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    if ( vmx_vcpu_pml_enabled(v) )
+        return 0;
+
+    v->arch.hvm_vmx.pml_pg = d->arch.paging.alloc_page(d);
+    if ( !v->arch.hvm_vmx.pml_pg )
+        return -ENOMEM;
+
+    vmx_vmcs_enter(v);
+
+    __vmwrite(PML_ADDRESS, page_to_mfn(v->arch.hvm_vmx.pml_pg) <<
 PAGE_SHIFT);
+    __vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);
+
+    v->arch.hvm_vmx.secondary_exec_control |=
 SECONDARY_EXEC_ENABLE_PML;
+
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+              v->arch.hvm_vmx.secondary_exec_control);
+
+    vmx_vmcs_exit(v);
+
+    return 0;
+}
+
+void vmx_vcpu_disable_pml(struct vcpu *v)
+{
+    if ( !vmx_vcpu_pml_enabled(v) )
+        return;
+
+    /* Make sure we don't lose any logged GPAs */
+    vmx_vcpu_flush_pml_buffer(v);
+
+    vmx_vmcs_enter(v);
+
+    v->arch.hvm_vmx.secondary_exec_control &=

~SECONDARY_EXEC_ENABLE_PML;

xen/arch/x86/hvm/vmx/vmcs.c +6 -0
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+              v->arch.hvm_vmx.secondary_exec_control);
+
+    vmx_vmcs_exit(v);
+
+    v->domain->arch.paging.free_page(v->domain,

v->arch.hvm_vmx.pml_pg);

xen/arch/x86/hvm/vmx/vmcs.c +22 -0
+    v->arch.hvm_vmx.pml_pg = NULL;
+}
+
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);
+
+    /* Do nothing if PML buffer is empty */
+    if ( pml_idx == (NR_PML_ENTRIES - 1) )
+        goto out;
+
+    pml_buf = __map_domain_page(v->arch.hvm_vmx.pml_pg);
+
+    /*
+     * PML index can be either 2^16-1 (buffer is full), or 0~511 (buffer is
Quoted 1 line

not

0~NR_PML_ENTRIES-1

Quoted 18 lines
xen/arch/x86/hvm/vmx/vmcs.c +13 -0
+     * full), and in latter case PML index always points to next available
+     * entity.
+     */
+    if (pml_idx >= NR_PML_ENTRIES)
+        pml_idx = 0;
+    else
+        pml_idx++;
+
+    for ( ; pml_idx < NR_PML_ENTRIES; pml_idx++ )
+    {
+        unsigned long gfn = pml_buf[pml_idx] >> PAGE_SHIFT;
+        /*
+         * Need to change type from log-dirty to normal memory for

logged GFN.
+ * hap_track_dirty_vram depends on it to work. And we really only
need
+ * to mark GFNs which hve been successfully changed from
log-dirty to

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1421

Quoted 5 lines
xen/arch/x86/hvm/vmx/vmcs.c +5 -0
+         * normal memory to be dirty.
+         */
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
+            paging_mark_gfn_dirty(v->domain, gfn);

Should we handle error from p2m_change_type_one and consequently making this flush function non-void?

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1427

Quoted 6 lines
xen/arch/x86/hvm/vmx/vmcs.c +6 -0
+    }
+
+    unmap_domain_page(pml_buf);
+
+    /* Reset PML index */
+    __vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);

Like Jan pointed out an assertion of vcpu status is required here otherwise blindly reset PML index may race with new logged entries from a running vcpu.

Quoted 25 lines
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+
+out:
+    vmx_vmcs_exit(v);
+}
+
+bool_t vmx_domain_pml_enabled(const struct domain *d)
+{
+    return !!(d->arch.hvm_domain.vmx.status &

VMX_DOMAIN_PML_ENABLED);

xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+}
+
+/*
+ * This function enables PML for particular domain. It should be called when
+ * domain is paused.
+ *
+ * PML needs to be enabled globally for all vcpus of the domain, as PML

buffer
+ * and PML index are pre-vcpu, but EPT table is shared by vcpus, therefore
+ * enabling PML on partial vcpus won't work.
+ */

xen/arch/x86/hvm/vmx/vmcs.c +5 -0
+int vmx_domain_enable_pml(struct domain *d)
+{
+    struct vcpu *v;
+    int rc;
+

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1460

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( vmx_domain_pml_enabled(d) )
+        return 0;
+
+    for_each_vcpu( d, v )
+        if ( (rc = vmx_vcpu_enable_pml(v)) != 0 )
+            goto error;
+
+    d->arch.hvm_domain.vmx.status |= VMX_DOMAIN_PML_ENABLED;

I didn't see how this domain-wise flag is useful. Or if we really want to go this way, you also need to clear this flag if vcpu pml enable is failed in vcpu hotplug phase, since the flag itself means all vcpus of the domain so we must keep this intention in all places.

Quoted 76 lines
xen/arch/x86/hvm/vmx/vmcs.c +14 -0
+
+    return 0;
+
+error:
+    for_each_vcpu( d, v )
+        if ( vmx_vcpu_pml_enabled(v) )
+            vmx_vcpu_disable_pml(v);
+    return rc;
+}
+
+/*
+ * Disable PML for particular domain. Called when domain is paused.
+ *
+ * The same as enabling PML for domain, disabling PML should be done for

all
+ * vcpus at once.
+ */

xen/arch/x86/hvm/vmx/vmcs.c +17 -0
+void vmx_domain_disable_pml(struct domain *d)
+{
+    struct vcpu *v;
+
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( !vmx_domain_pml_enabled(d) )
+        return;
+
+    for_each_vcpu( d, v )
+        vmx_vcpu_disable_pml(v);
+
+    d->arch.hvm_domain.vmx.status &= ~VMX_DOMAIN_PML_ENABLED;
+}
+
+/*
+ * Flush PML buffer of all vcpus, and update the logged dirty pages to

log-dirty
+ * radix tree. Called when domain is paused.
+ */

xen/arch/x86/hvm/vmx/vmcs.c +13 -0
+void vmx_domain_flush_pml_buffers(struct domain *d)
+{
+    struct vcpu *v;
+
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( !vmx_domain_pml_enabled(d) )
+        return;
+
+    for_each_vcpu( d, v )
+        vmx_vcpu_flush_pml_buffer(v);
+}
+
 int vmx_create_vmcs(struct vcpu *v)
 {
     struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
xen/include/asm-x86/hvm/vmx/vmcs.h +9 -1
index 2c679ac..ceb09bf 100644
@@ -498,6 +498,15 @@ static inline int vmx_add_host_load_msr(u32 msr)
 
 DECLARE_PER_CPU(bool_t, vmxon);
 
+bool_t vmx_vcpu_pml_enabled(const struct vcpu *v);
+int vmx_vcpu_enable_pml(struct vcpu *v);
+void vmx_vcpu_disable_pml(struct vcpu *v);
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v);
+bool_t vmx_domain_pml_enabled(const struct domain *d);
+int vmx_domain_enable_pml(struct domain *d);
+void vmx_domain_disable_pml(struct domain *d);
+void vmx_domain_flush_pml_buffers(struct domain *d);
+
 #endif /* ASM_X86_HVM_VMX_VMCS_H__ */
 
 /*
--

2.1.0

#35 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 7 lines · Kevin

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1421

Quoted 4 lines

From: Kai Huang [mailto:[email protected]]

xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
+            paging_mark_gfn_dirty(v->domain, gfn);

Should we handle error from p2m_change_type_one and consequently making this flush function non-void?

I don't think we need to return an error, but we should probably call mark_dirty here for anything except -EBUSY.

Quoted 7 lines
Quoted 1 line

+ d->arch.hvm_domain.vmx.status |= VMX_DOMAIN_PML_ENABLED;

I didn't see how this domain-wise flag is useful. Or if we really want to go this way, you also need to clear this flag if vcpu pml enable is failed in vcpu hotplug phase, since the flag itself means all vcpus of the domain so we must keep this intention in all places.

IIUC we need this flag so that we know whether to enable PML on any new vcpus. If we fail to enable PML on hotplug, we fail the hotplug (like for other vcpu bringup errors) so the invariant still holds.

Cheers,

Tim.

author
#36 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 10 lines · Tim Deegan
Quoted 6 lines · Kevin

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1421

Quoted 4 lines

From: Kai Huang [mailto:[email protected]]

xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
+            paging_mark_gfn_dirty(v->domain, gfn);

Should we handle error from p2m_change_type_one and consequently making this flush function non-void?

I don't think we need to return an error, but we should probably call mark_dirty here for anything except -EBUSY.

Hi Kevin, Tim,

My intention here is to rule out the GFN with original type that is not p2m_ram_logdirty, though with patch 11 it's not likely have such GFN logged.

Looks -EBUSY returns exactly when original type is not p2m_ram_logdirty, so I think it might be OK to do as Tim suggested.

But given the same thing has already been done in hap_track_dirty_vram (hap_track_dirty_vram->paging_log_dirty_range, in which gfn is set in bitmap with !p2m_change_type_one is true), and in EPT violation (p2m_change_type_one is called unconditionally without checking return value), I think it should be safe to do the current code here.

What's your comments?

Thanks,
-Kai

Quoted 19 lines
Quoted 7 lines
Quoted 2 lines

+ d->arch.hvm_domain.vmx.status |= VMX_DOMAIN_PML_ENABLED;

I didn't see how this domain-wise flag is useful. Or if we really want to go this way, you also need to clear this flag if vcpu pml enable is failed in vcpu hotplug phase, since the flag itself means all vcpus of the domain so we must keep this intention in all places.

IIUC we need this flag so that we know whether to enable PML on any new vcpus. If we fail to enable PML on hotplug, we fail the hotplug (like for other vcpu bringup errors) so the invariant still holds.

Cheers,

Tim.

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#37 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 19 lines · Kai Huang
Quoted 10 lines · Tim Deegan
Quoted 6 lines · Kevin

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1421

Quoted 4 lines

From: Kai Huang [mailto:[email protected]]

xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
+            paging_mark_gfn_dirty(v->domain, gfn);

Should we handle error from p2m_change_type_one and consequently making this flush function non-void?

I don't think we need to return an error, but we should probably call mark_dirty here for anything except -EBUSY.

Hi Kevin, Tim,

My intention here is to rule out the GFN with original type that is not p2m_ram_logdirty, though with patch 11 it's not likely have such GFN logged.

Quoted 8 lines

Looks -EBUSY returns exactly when original type is not p2m_ram_logdirty, so I think it might be OK to do as Tim suggested.

But given the same thing has already been done in hap_track_dirty_vram (hap_track_dirty_vram->paging_log_dirty_range, in which gfn is set in bitmap with !p2m_change_type_one is true), and in EPT violation (p2m_change_type_one is called unconditionally without checking return value), I think it should be safe to do the current code here.

The paging_log_dirty_range case is doing something quite different:
it is making pages read-only so they can be tracked, and it needs to mark any page that couldn't be made read-only (because the guest can write to them). Its three cases are:
- change succeeded: no mark, we will trap any new writes
- EBUSY: mark, since we can't be sure we'll trap new writes
- other error: mark, since we can't be sure we'll trap new writes

In this case we _know_ the guest has written to the page (because it's in the PML log), so our only reason for not calling mark_dirty() is if we see that someone else has changed the p2m (EBUSY) and that someone else ought to already have DTRT.

Now that I've written it out, and since we expect these races to be very rare, I've changed my mind: we should _always_ call mark_dirty here. The extra cost should be negligible, and a missing mark is extremely difficult to debug.

Cheers,

Tim.

author
#38 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 27 lines · Tim Deegan
Quoted 18 lines · Kai Huang
Quoted 10 lines · Tim Deegan
Quoted 6 lines · Kevin

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1421

Quoted 4 lines

From: Kai Huang [mailto:[email protected]]

xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
+            paging_mark_gfn_dirty(v->domain, gfn);

Should we handle error from p2m_change_type_one and consequently making this flush function non-void?

I don't think we need to return an error, but we should probably call mark_dirty here for anything except -EBUSY.

Hi Kevin, Tim,

My intention here is to rule out the GFN with original type that is not p2m_ram_logdirty, though with patch 11 it's not likely have such GFN logged.

Quoted 8 lines

Looks -EBUSY returns exactly when original type is not p2m_ram_logdirty, so I think it might be OK to do as Tim suggested.

But given the same thing has already been done in hap_track_dirty_vram (hap_track_dirty_vram->paging_log_dirty_range, in which gfn is set in bitmap with !p2m_change_type_one is true), and in EPT violation (p2m_change_type_one is called unconditionally without checking return value), I think it should be safe to do the current code here.

Quoted 4 lines

The paging_log_dirty_range case is doing something quite different:
it is making pages read-only so they can be tracked, and it needs to mark any page that couldn't be made read-only (because the guest can write to them).

Thanks for comprehensive reply. However, looks I can't agree on some points.

paging_log_dirty_range currently is only used by hap_track_dirty_vram for video ram tracking, and it doesn't call paging_mark_dirty in any case. Basically, paging_log_dirty_range only does below thing but nothing else:

    for ( i = 0, pfn = begin_pfn; pfn < begin_pfn + nr; i++, pfn++ )
        if ( !p2m_change_type_one(d, pfn, p2m_ram_rw, p2m_ram_logdirty) )
            dirty_bitmap[i >> 3] |= (1 << (i & 7));

From which we can see the purpose of this function (and let us put PML away for now):

- change GFN's type from p2m_ram_rw back to p2m_ram_logdirty, in
order to be able to log the GFN again (more precisely, to track the GFN again in EPT violation), with the fact that the dirty page's p2m type has been changed from p2m_log_dirty to p2m_ram_rw, in EPT violation.
- mark the dirty GFN to the bitmap only when above changing
p2m_ram_logdirty to p2m_ram_rw is done successfully. It is reasonable, as only a successful changing from p2m_ram_rw to p2m_ram_dirty means the dirty page has been changed from p2m_ram_logdirty to p2m_ram_rw in EPT violation.

Btw, from which we can also note that currently video ram tracking is not via log-dirty radix tree but depends on p2m type change, this is the reason we must call p2m_type_change_one in vmx_vcpu_flush_pml_buffer.

Quoted 4 lines

Its three cases are:
- change succeeded: no mark, we will trap any new writes
- EBUSY: mark, since we can't be sure we'll trap new writes
- other error: mark, since we can't be sure we'll trap new writes

Regarding to the above three cases, I assume you are referring to changing p2m_ram_rw back to p2m_ram_logdirty in paging_log_dirty_range , in which case the paging_mark_dirty is not called at all, as I mentioned above.

Quoted 5 lines

In this case we _know_ the guest has written to the page (because it's in the PML log), so our only reason for not calling mark_dirty() is if we see that someone else has changed the p2m (EBUSY) and that someone else ought to already have DTRT.

I agree on this, given you said we can't be sure for the unsuccessful p2m type change.

Quoted 5 lines

Now that I've written it out, and since we expect these races to be very rare, I've changed my mind: we should _always_ call mark_dirty here. The extra cost should be negligible, and a missing mark is extremely difficult to debug.

Which is also good to me, and in this case we should also call p2m_change_type_one(.., p2m_ram_logdirty, p2m_ram_rw) unconditionally, as this is required for video ram tracking.

Thanks,
-Kai

Quoted 4 lines

Cheers,

Tim.

#39 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 34 lines · Kai Huang
Quoted 27 lines · Tim Deegan
Quoted 18 lines · Kai Huang
Quoted 10 lines · Tim Deegan
Quoted 6 lines · Kevin

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1421

Quoted 4 lines

From: Kai Huang [mailto:[email protected]]

xen/arch/x86/hvm/vmx/vmcs.c +3 -0
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
+            paging_mark_gfn_dirty(v->domain, gfn);

Should we handle error from p2m_change_type_one and consequently making this flush function non-void?

I don't think we need to return an error, but we should probably call mark_dirty here for anything except -EBUSY.

Hi Kevin, Tim,

My intention here is to rule out the GFN with original type that is not p2m_ram_logdirty, though with patch 11 it's not likely have such GFN logged.

Quoted 8 lines

Looks -EBUSY returns exactly when original type is not p2m_ram_logdirty, so I think it might be OK to do as Tim suggested.

But given the same thing has already been done in hap_track_dirty_vram (hap_track_dirty_vram->paging_log_dirty_range, in which gfn is set in bitmap with !p2m_change_type_one is true), and in EPT violation (p2m_change_type_one is called unconditionally without checking return value), I think it should be safe to do the current code here.

Quoted 4 lines

The paging_log_dirty_range case is doing something quite different:
it is making pages read-only so they can be tracked, and it needs to mark any page that couldn't be made read-only (because the guest can write to them).

Quoted 5 lines

Thanks for comprehensive reply. However, looks I can't agree on some points.

paging_log_dirty_range currently is only used by hap_track_dirty_vram for video ram tracking, and it doesn't call paging_mark_dirty in any case.

Sure, it doesn't call paging_mark_dirty(), but instead it puts the marks into a bitmap directly.

Quoted 10 lines

Basically, paging_log_dirty_range only does below thing but nothing else:

     for ( i = 0, pfn = begin_pfn; pfn < begin_pfn + nr; i++, pfn++ )
         if ( !p2m_change_type_one(d, pfn, p2m_ram_rw, p2m_ram_logdirty) )
             dirty_bitmap[i >> 3] |= (1 << (i & 7));

From which we can see the purpose of this function (and let us put PML
away for now):

Quoted 9 lines

- change GFN's type from p2m_ram_rw back to p2m_ram_logdirty, in
order to be able to log the GFN again (more precisely, to track the GFN again in EPT violation), with the fact that the dirty page's p2m type has been changed from p2m_log_dirty to p2m_ram_rw, in EPT violation.
- mark the dirty GFN to the bitmap only when above changing
p2m_ram_logdirty to p2m_ram_rw is done successfully. It is reasonable, as only a successful changing from p2m_ram_rw to p2m_ram_dirty means the dirty page has been changed from p2m_ram_logdirty to p2m_ram_rw in EPT violation.

Right; so this code should probably also be setting the mark if p2m_change_type_one() returns anything except EBUSY.

But in this vram code we can't just set the mark in all cases, because we need to detect the case where the type is still p2m_ram_logdirty -- i.e. the page hasn't been written to.

Quoted 3 lines

Btw, from which we can also note that currently video ram tracking is not via log-dirty radix tree but depends on p2m type change, this is the reason we must call p2m_type_change_one in vmx_vcpu_flush_pml_buffer.

I think we need to do that anyway, to make sure that next time we clear the bitmap, the change back from _rw to _logdirty clears the D bit.

But it does suggest that we might want to flush the PML buffers in the vram function.

Quoted 7 lines
Quoted 4 lines

Now that I've written it out, and since we expect these races to be very rare, I've changed my mind: we should _always_ call mark_dirty here. The extra cost should be negligible, and a missing mark is extremely difficult to debug.

Which is also good to me, and in this case we should also call p2m_change_type_one(.., p2m_ram_logdirty, p2m_ram_rw) unconditionally, as this is required for video ram tracking.

Yep.

Tim.

#40 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Quoted 64 lines · Tim Deegan
Quoted 34 lines · Kai Huang
Quoted 27 lines · Tim Deegan
Quoted 18 lines · Kai Huang
Quoted 10 lines · Tim Deegan
Quoted 6 lines · Kevin

Review

Quoted 4 lines

From: Kai Huang [mailto:[email protected]]

(quoted diff) +3 -0
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
+            paging_mark_gfn_dirty(v->domain, gfn);

Should we handle error from p2m_change_type_one and consequently making this flush function non-void?

I don't think we need to return an error, but we should probably call mark_dirty here for anything except -EBUSY.

Hi Kevin, Tim,

My intention here is to rule out the GFN with original type that is not p2m_ram_logdirty, though with patch 11 it's not likely have such GFN logged.

Quoted 8 lines

Looks -EBUSY returns exactly when original type is not p2m_ram_logdirty, so I think it might be OK to do as Tim suggested.

But given the same thing has already been done in hap_track_dirty_vram (hap_track_dirty_vram->paging_log_dirty_range, in which gfn is set in bitmap with !p2m_change_type_one is true), and in EPT violation (p2m_change_type_one is called unconditionally without checking return value), I think it should be safe to do the current code here.

Quoted 4 lines

The paging_log_dirty_range case is doing something quite different:
it is making pages read-only so they can be tracked, and it needs to mark any page that couldn't be made read-only (because the guest can write to them).

Quoted 5 lines

Thanks for comprehensive reply. However, looks I can't agree on some points.

paging_log_dirty_range currently is only used by hap_track_dirty_vram for video ram tracking, and it doesn't call paging_mark_dirty in any case.

Sure, it doesn't call paging_mark_dirty(), but instead it puts the marks into a bitmap directly.

Quoted 10 lines

Basically, paging_log_dirty_range only does below thing but nothing else:

     for ( i = 0, pfn = begin_pfn; pfn < begin_pfn + nr; i++, pfn++ )
         if ( !p2m_change_type_one(d, pfn, p2m_ram_rw, p2m_ram_logdirty) )
             dirty_bitmap[i >> 3] |= (1 << (i & 7));

From which we can see the purpose of this function (and let us put PML
away for now):

Quoted 9 lines

- change GFN's type from p2m_ram_rw back to p2m_ram_logdirty, in
order to be able to log the GFN again (more precisely, to track the GFN again in EPT violation), with the fact that the dirty page's p2m type has been changed from p2m_log_dirty to p2m_ram_rw, in EPT violation.
- mark the dirty GFN to the bitmap only when above changing
p2m_ram_logdirty to p2m_ram_rw is done successfully. It is reasonable, as only a successful changing from p2m_ram_rw to p2m_ram_dirty means the dirty page has been changed from p2m_ram_logdirty to p2m_ram_rw in EPT violation.

Quoted 2 lines

Right; so this code should probably also be setting the mark if p2m_change_type_one() returns anything except EBUSY.

Reasonable. But as so far there's nothing wrong behavior observed with current code, I intend to leave it unchanged. Is it OK to you?

Quoted 4 lines

But in this vram code we can't just set the mark in all cases, because we need to detect the case where the type is still p2m_ram_logdirty -- i.e. the page hasn't been written to.

Agreed.

Quoted 10 lines
Quoted 4 lines

Btw, from which we can also note that currently video ram tracking is not via log-dirty radix tree but depends on p2m type change, this is the reason we must call p2m_type_change_one in vmx_vcpu_flush_pml_buffer.

I think we need to do that anyway, to make sure that next time we clear the bitmap, the change back from _rw to _logdirty clears the D bit.

But it does suggest that we might want to flush the PML buffers in the vram function.

True.

Quoted 10 lines
Quoted 8 lines
Quoted 5 lines

Now that I've written it out, and since we expect these races to be very rare, I've changed my mind: we should _always_ call mark_dirty here. The extra cost should be negligible, and a missing mark is extremely difficult to debug.

Which is also good to me, and in this case we should also call p2m_change_type_one(.., p2m_ram_logdirty, p2m_ram_rw) unconditionally, as this is required for video ram tracking.

Yep.

Agreed. So this time for the PML patches, I'll always call both mark_dirty and p2m_change_type_one (and ignore return value) for all logged GPA.

But I intend not to change current video ram tracking code (paging_log_dirty_range), as explained above. Is this good to you?

Thanks,
-Kai

Quoted 7 lines

Tim.

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

Signature · 2 lines
Thanks,
-Kai
#41 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

Hi,

Quoted 6 lines · Kai Huang

Agreed. So this time for the PML patches, I'll always call both mark_dirty and p2m_change_type_one (and ignore return value) for all logged GPA.

But I intend not to change current video ram tracking code (paging_log_dirty_range), as explained above. Is this good to you?

Yes, that's fine.

Cheers,

Tim.

author
#42 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

In reply to Tian, Kevin
Quoted 91 lines · Kevin
Quoted 91 lines

From: Kai Huang [mailto:[email protected]]
Sent: Wednesday, April 15, 2015 3:04 PM

This patch adds help functions to enable/disable PML, and flush PML buffer for single vcpu and particular domain for further use.

---
  xen/arch/x86/hvm/vmx/vmcs.c        | 178
+++++++++++++++++++++++++++++++++++++
  xen/include/asm-x86/hvm/vmx/vmcs.h |   9 ++
  2 files changed, 187 insertions(+)
xen/arch/x86/hvm/vmx/vmcs.c +43 -0
index d120370..d3cb50f 100644
@@ -1328,6 +1328,184 @@ void vmx_clear_eoi_exit_bitmap(struct vcpu *v,
 u8 vector)
                  &v->arch.hvm_vmx.eoi_exitmap_changed);
  }
 
+bool_t vmx_vcpu_pml_enabled(const struct vcpu *v)
+{
+    return !!(v->arch.hvm_vmx.secondary_exec_control &
+              SECONDARY_EXEC_ENABLE_PML);
+}
+
+int vmx_vcpu_enable_pml(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+
+    if ( vmx_vcpu_pml_enabled(v) )
+        return 0;
+
+    v->arch.hvm_vmx.pml_pg = d->arch.paging.alloc_page(d);
+    if ( !v->arch.hvm_vmx.pml_pg )
+        return -ENOMEM;
+
+    vmx_vmcs_enter(v);
+
+    __vmwrite(PML_ADDRESS, page_to_mfn(v->arch.hvm_vmx.pml_pg) <<
 PAGE_SHIFT);
+    __vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);
+
+    v->arch.hvm_vmx.secondary_exec_control |=
 SECONDARY_EXEC_ENABLE_PML;
+
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+              v->arch.hvm_vmx.secondary_exec_control);
+
+    vmx_vmcs_exit(v);
+
+    return 0;
+}
+
+void vmx_vcpu_disable_pml(struct vcpu *v)
+{
+    if ( !vmx_vcpu_pml_enabled(v) )
+        return;
+
+    /* Make sure we don't lose any logged GPAs */
+    vmx_vcpu_flush_pml_buffer(v);
+
+    vmx_vmcs_enter(v);
+
+    v->arch.hvm_vmx.secondary_exec_control &=

~SECONDARY_EXEC_ENABLE_PML;

xen/arch/x86/hvm/vmx/vmcs.c +6 -0
+    __vmwrite(SECONDARY_VM_EXEC_CONTROL,
+              v->arch.hvm_vmx.secondary_exec_control);
+
+    vmx_vmcs_exit(v);
+
+    v->domain->arch.paging.free_page(v->domain,

v->arch.hvm_vmx.pml_pg);

xen/arch/x86/hvm/vmx/vmcs.c +16 -0
+    v->arch.hvm_vmx.pml_pg = NULL;
+}
+
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v)
+{
+    uint64_t *pml_buf;
+    unsigned long pml_idx;
+
+    ASSERT(vmx_vcpu_pml_enabled(v));
+
+    vmx_vmcs_enter(v);
+
+    __vmread(GUEST_PML_INDEX, &pml_idx);
+
+    /* Do nothing if PML buffer is empty */
+    if ( pml_idx == (NR_PML_ENTRIES - 1) )
Quoted 8 lines
Quoted 7 lines
xen/arch/x86/hvm/vmx/vmcs.c +6 -0
+        goto out;
+
+    pml_buf = __map_domain_page(v->arch.hvm_vmx.pml_pg);
+
+    /*
+     * PML index can be either 2^16-1 (buffer is full), or 0~511 (buffer is

not

0~NR_PML_ENTRIES-1

Will do.

Quoted 27 lines
Quoted 19 lines
xen/arch/x86/hvm/vmx/vmcs.c +13 -0
+     * full), and in latter case PML index always points to next available
+     * entity.
+     */
+    if (pml_idx >= NR_PML_ENTRIES)
+        pml_idx = 0;
+    else
+        pml_idx++;
+
+    for ( ; pml_idx < NR_PML_ENTRIES; pml_idx++ )
+    {
+        unsigned long gfn = pml_buf[pml_idx] >> PAGE_SHIFT;
+        /*
+         * Need to change type from log-dirty to normal memory for

logged GFN.
+ * hap_track_dirty_vram depends on it to work. And we really only
need
+ * to mark GFNs which hve been successfully changed from
log-dirty to

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1421

Quoted 5 lines
xen/arch/x86/hvm/vmx/vmcs.c +5 -0
+         * normal memory to be dirty.
+         */
+        if ( !p2m_change_type_one(v->domain, gfn, p2m_ram_logdirty,
+                    p2m_ram_rw) )
+            paging_mark_gfn_dirty(v->domain, gfn);

Should we handle error from p2m_change_type_one and consequently making this flush function non-void?

Quoted 9 lines

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1427

Quoted 6 lines
xen/arch/x86/hvm/vmx/vmcs.c +6 -0
+    }
+
+    unmap_domain_page(pml_buf);
+
+    /* Reset PML index */
+    __vmwrite(GUEST_PML_INDEX, NR_PML_ENTRIES - 1);

Like Jan pointed out an assertion of vcpu status is required here otherwise blindly reset PML index may race with new logged entries from a running vcpu.

Yeah will do.

Thanks,
-Kai

Quoted 123 lines
Quoted 26 lines
xen/arch/x86/hvm/vmx/vmcs.c +8 -0
+
+out:
+    vmx_vmcs_exit(v);
+}
+
+bool_t vmx_domain_pml_enabled(const struct domain *d)
+{
+    return !!(d->arch.hvm_domain.vmx.status &

VMX_DOMAIN_PML_ENABLED);

xen/arch/x86/hvm/vmx/vmcs.c +7 -0
+}
+
+/*
+ * This function enables PML for particular domain. It should be called when
+ * domain is paused.
+ *
+ * PML needs to be enabled globally for all vcpus of the domain, as PML

buffer
+ * and PML index are pre-vcpu, but EPT table is shared by vcpus, therefore
+ * enabling PML on partial vcpus won't work.
+ */

xen/arch/x86/hvm/vmx/vmcs.c +5 -0
+int vmx_domain_enable_pml(struct domain *d)
+{
+    struct vcpu *v;
+    int rc;
+

xen/arch/x86/hvm/vmx/vmcs.c void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector) · line 1460

Quoted 10 lines
xen/arch/x86/hvm/vmx/vmcs.c +10 -0
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( vmx_domain_pml_enabled(d) )
+        return 0;
+
+    for_each_vcpu( d, v )
+        if ( (rc = vmx_vcpu_enable_pml(v)) != 0 )
+            goto error;
+
+    d->arch.hvm_domain.vmx.status |= VMX_DOMAIN_PML_ENABLED;

I didn't see how this domain-wise flag is useful. Or if we really want to go this way, you also need to clear this flag if vcpu pml enable is failed in vcpu hotplug phase, since the flag itself means all vcpus of the domain so we must keep this intention in all places.

Quoted 75 lines
xen/arch/x86/hvm/vmx/vmcs.c +14 -0
+
+    return 0;
+
+error:
+    for_each_vcpu( d, v )
+        if ( vmx_vcpu_pml_enabled(v) )
+            vmx_vcpu_disable_pml(v);
+    return rc;
+}
+
+/*
+ * Disable PML for particular domain. Called when domain is paused.
+ *
+ * The same as enabling PML for domain, disabling PML should be done for

all
+ * vcpus at once.
+ */

xen/arch/x86/hvm/vmx/vmcs.c +17 -0
+void vmx_domain_disable_pml(struct domain *d)
+{
+    struct vcpu *v;
+
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( !vmx_domain_pml_enabled(d) )
+        return;
+
+    for_each_vcpu( d, v )
+        vmx_vcpu_disable_pml(v);
+
+    d->arch.hvm_domain.vmx.status &= ~VMX_DOMAIN_PML_ENABLED;
+}
+
+/*
+ * Flush PML buffer of all vcpus, and update the logged dirty pages to

log-dirty
+ * radix tree. Called when domain is paused.
+ */

xen/arch/x86/hvm/vmx/vmcs.c +13 -0
+void vmx_domain_flush_pml_buffers(struct domain *d)
+{
+    struct vcpu *v;
+
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( !vmx_domain_pml_enabled(d) )
+        return;
+
+    for_each_vcpu( d, v )
+        vmx_vcpu_flush_pml_buffer(v);
+}
+
  int vmx_create_vmcs(struct vcpu *v)
  {
      struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
xen/include/asm-x86/hvm/vmx/vmcs.h +9 -1
index 2c679ac..ceb09bf 100644
@@ -498,6 +498,15 @@ static inline int vmx_add_host_load_msr(u32 msr)
 
  DECLARE_PER_CPU(bool_t, vmxon);
 
+bool_t vmx_vcpu_pml_enabled(const struct vcpu *v);
+int vmx_vcpu_enable_pml(struct vcpu *v);
+void vmx_vcpu_disable_pml(struct vcpu *v);
+void vmx_vcpu_flush_pml_buffer(struct vcpu *v);
+bool_t vmx_domain_pml_enabled(const struct domain *d);
+int vmx_domain_enable_pml(struct domain *d);
+void vmx_domain_disable_pml(struct domain *d);
+void vmx_domain_flush_pml_buffers(struct domain *d);
+
  #endif /* ASM_X86_HVM_VMX_VMCS_H__ */
 
  /*
--
Quoted 1 line

2.1.0

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#43 lore raw

Re: [v2 06/11] vmx: add help functions to support PML

In reply to Kai Huang
Quoted 15 lines

From: Tian, Kevin
Sent: Friday, April 17, 2015 6:57 AM

Quoted 13 lines
xen/arch/x86/hvm/vmx/vmcs.c +13 -0
+int vmx_domain_enable_pml(struct domain *d)
+{
+    struct vcpu *v;
+    int rc;
+
+    ASSERT(atomic_read(&d->pause_count));
+
+    if ( vmx_domain_pml_enabled(d) )
+        return 0;
+
+    for_each_vcpu( d, v )
+        if ( (rc = vmx_vcpu_enable_pml(v)) != 0 )
+            goto error;
Quoted 9 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+    d->arch.hvm_domain.vmx.status |= VMX_DOMAIN_PML_ENABLED;

I didn't see how this domain-wise flag is useful. Or if we really want to go this way, you also need to clear this flag if vcpu pml enable is failed in vcpu hotplug phase, since the flag itself means all vcpus of the domain so we must keep this intention in all places.

forget this comment. Your [08/11] did it. :-)

Thanks
Kevin

author
#44 lore raw

PATCH v2 7/11 vmx: handle PML buffer full VMEXIT

In reply to Kai Huang

We need to flush PML buffer when it's full.

---
 xen/arch/x86/hvm/vmx/vmx.c | 4 ++++
 1 file changed, 4 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +4 -0
index 2ac1492..279e745 100644
@@ -3177,6 +3177,10 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
         vmx_handle_apic_write();
         break;
 
+    case EXIT_REASON_PML_FULL:
+        vmx_vcpu_flush_pml_buffer(v);
+        break;
+
     case EXIT_REASON_ACCESS_GDTR_OR_IDTR:
     case EXIT_REASON_ACCESS_LDTR_OR_TR:
     case EXIT_REASON_VMX_PREEMPTION_TIMER_EXPIRED:
Signature · 1 line
2.1.0
author
#45 lore raw

PATCH v2 8/11 vmx: handle PML enabling in vmx_vcpu_initialise

In reply to Kai Huang

It's possible domain has already been in log-dirty mode when creating vcpu, in which case we should enable PML for this vcpu if PML has been enabled for the domain.

---
 xen/arch/x86/hvm/vmx/vmx.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +23 -0
index 279e745..ad9d7d4 100644
@@ -116,6 +116,29 @@ static int vmx_vcpu_initialise(struct vcpu *v)
         return rc;
     }
 
+    /*
+     * It's rare but still possible that domain has already been in log-dirty
+     * mode when vcpu is being created (commented by Tim), in which case we
+     * should enable PML for this vcpu if PML has been enabled for the domain,
+     * and failure to enable results in failure of creating this vcpu.
+     *
+     * Note even there's no vcpu created for the domain, vmx_domain_enable_pml
+     * will return successful in which case vmx_domain_pml_enabled will also
+     * return true. And even this is the first vcpu to be created with
+     * vmx_domain_pml_enabled being true, failure of enabling PML still results
+     * in failure of creating vcpu, to avoid complicated logic to revert PML
+     * style EPT table to non-PML style EPT table.
+     */
+    if ( vmx_domain_pml_enabled(v->domain) )
+    {
+        if ( (rc = vmx_vcpu_enable_pml(v)) != 0 )
+        {
+            dprintk(XENLOG_ERR, "%pv: Failed to enable PML.\n", v);
+            vmx_destroy_vmcs(v);
+            return rc;
+        }
+    }
+
     vpmu_initialise(v);
 
     vmx_install_vlapic_mapping(v);
Signature · 1 line
2.1.0
author
#46 lore raw

PATCH v2 9/11 vmx: disable PML in vmx_vcpu_destroy

In reply to Kai Huang

It's possible domain still remains in log-dirty mode when it is about to be destroyed, in which case we should manually disable PML for it.

---
 xen/arch/x86/hvm/vmx/vmx.c | 8 ++++++++
 1 file changed, 8 insertions(+)
xen/arch/x86/hvm/vmx/vmx.c +8 -0
index ad9d7d4..821e90b 100644
@@ -152,6 +152,14 @@ static int vmx_vcpu_initialise(struct vcpu *v)
 
 static void vmx_vcpu_destroy(struct vcpu *v)
 {
+    /*
+     * There are cases that domain still remains in log-dirty mode when it is
+     * about to be destroyed (ex, user types 'xl destroy <dom>'), in which case
+     * we should disable PML manually here. Note that vmx_vcpu_destroy is called
+     * prior to vmx_domain_destroy so we need to disable PML for each vcpu
+     * separately here.
+     */
+    vmx_vcpu_disable_pml(v);
     vmx_destroy_vmcs(v);
     vpmu_destroy(v);
     passive_domain_destroy(v);
Signature · 1 line
2.1.0
author
#47 lore raw

PATCH v2 10/11 log-dirty: refine common code to support PML

In reply to Kai Huang

Using PML, it's possible there are dirty GPAs logged in vcpus' PML buffers when userspace peek/clear dirty pages, therefore we need to flush them befor reporting dirty pages to userspace. This applies to both video ram tracking and paging_log_dirty_op.

This patch adds new p2m layer functions to enable/disable PML and flush PML buffers. The new functions are named to be generic to cover potential futher PML-like features for other platforms.

---
 xen/arch/x86/mm/hap/hap.c | 29 +++++++++++++++++++++++++----
 xen/arch/x86/mm/p2m.c     | 36 ++++++++++++++++++++++++++++++++++++
 xen/arch/x86/mm/paging.c  | 10 ++++++++++
 xen/include/asm-x86/p2m.h | 11 +++++++++++
 4 files changed, 82 insertions(+), 4 deletions(-)
xen/arch/x86/mm/hap/hap.c +25 -4
index 4ecb2e2..1099670 100644
@@ -121,7 +121,10 @@ int hap_track_dirty_vram(struct domain *d,
                 p2m_change_type_range(d, ostart, oend,
                                       p2m_ram_logdirty, p2m_ram_rw);
 
-            /* set l1e entries of range within P2M table to be read-only. */
+            /*
+             * switch vram to log dirty mode, either by setting l1e entries of
+             * P2M table to be read-only, or via hardware-assisted log-dirty.
+             */
             p2m_change_type_range(d, begin_pfn, begin_pfn + nr,
                                   p2m_ram_rw, p2m_ram_logdirty);
 
@@ -135,6 +138,9 @@ int hap_track_dirty_vram(struct domain *d,
 
             domain_pause(d);
 
+            /* flush dirty GFNs potentially cached by hardware */
+            p2m_flush_hardware_cached_dirty(d);
+
             /* get the bitmap */
             paging_log_dirty_range(d, begin_pfn, nr, dirty_bitmap);
 
@@ -190,9 +196,15 @@ static int hap_enable_log_dirty(struct domain *d, bool_t log_global)
     d->arch.paging.mode |= PG_log_dirty;
     paging_unlock(d);
 
+    /* enable hardware-assisted log-dirty if it is supported */
+    p2m_enable_hardware_log_dirty(d);
+
     if ( log_global )
     {
-        /* set l1e entries of P2M table to be read-only. */
+        /*
+         * switch to log dirty mode, either by setting l1e entries of P2M table
+         * to be read-only, or via hardware-assisted log-dirty.
+         */
         p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
         flush_tlb_mask(d->domain_dirty_cpumask);
     }
@@ -205,14 +217,23 @@ static int hap_disable_log_dirty(struct domain *d)
     d->arch.paging.mode &= ~PG_log_dirty;
     paging_unlock(d);
 
-    /* set l1e entries of P2M table with normal mode */
+    /* disable hardware-assisted log-dirty if it is supported */
+    p2m_disable_hardware_log_dirty(d);
+
+    /*
+     * switch to normal mode, either by setting l1e entries of P2M table to
+     * normal mode, or via hardware-assisted log-dirty.
+     */
     p2m_change_entry_type_global(d, p2m_ram_logdirty, p2m_ram_rw);
     return 0;
 }
 
 static void hap_clean_dirty_bitmap(struct domain *d)
 {
-    /* set l1e entries of P2M table to be read-only. */
+    /*
+     * switch to log-dirty mode, either by setting l1e entries of P2M table to
+     * be read-only, or via hardware-assisted log-dirty.
+     */
     p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
     flush_tlb_mask(d->domain_dirty_cpumask);
 }
xen/arch/x86/mm/p2m.c +36 -0
index 6a06e9f..291a275 100644
@@ -239,6 +239,42 @@ void p2m_memory_type_changed(struct domain *d)
     }
 }
 
+void p2m_enable_hardware_log_dirty(struct domain *d)
+{
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+
+    if ( p2m->enable_hardware_log_dirty )
+    {
+        p2m_lock(p2m);
+        p2m->enable_hardware_log_dirty(p2m);
+        p2m_unlock(p2m);
+    }
+}
+
+void p2m_disable_hardware_log_dirty(struct domain *d)
+{
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+
+    if ( p2m->disable_hardware_log_dirty )
+    {
+        p2m_lock(p2m);
+        p2m->disable_hardware_log_dirty(p2m);
+        p2m_unlock(p2m);
+    }
+}
+
+void p2m_flush_hardware_cached_dirty(struct domain *d)
+{
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+
+    if ( p2m->flush_hardware_cached_dirty )
+    {
+        p2m_lock(p2m);
+        p2m->flush_hardware_cached_dirty(p2m);
+        p2m_unlock(p2m);
+    }
+}
+
 mfn_t __get_gfn_type_access(struct p2m_domain *p2m, unsigned long gfn,
                     p2m_type_t *t, p2m_access_t *a, p2m_query_t q,
                     unsigned int *page_order, bool_t locked)
xen/arch/x86/mm/paging.c +10 -0
index 77c929b..59d4720 100644
@@ -422,7 +422,17 @@ static int paging_log_dirty_op(struct domain *d,
     int i4, i3, i2;
 
     if ( !resuming )
+    {
         domain_pause(d);
+
+        /*
+         * Flush dirty GFNs potentially cached by hardware. Only need to flush
+         * when not resuming, as domain was paused in resuming case therefore
+         * it's not possible to have any new dirty pages.
+         */
+        p2m_flush_hardware_cached_dirty(d);
+    }
+
     paging_lock(d);
 
     if ( !d->arch.paging.preempt.dom )
xen/include/asm-x86/p2m.h +11 -0
index e93c551..91c17a5 100644
@@ -233,6 +233,9 @@ struct p2m_domain {
                                        p2m_access_t *p2ma,
                                        p2m_query_t q,
                                        unsigned int *page_order);
+    void               (*enable_hardware_log_dirty)(struct p2m_domain *p2m);
+    void               (*disable_hardware_log_dirty)(struct p2m_domain *p2m);
+    void               (*flush_hardware_cached_dirty)(struct p2m_domain *p2m);
     void               (*change_entry_type_global)(struct p2m_domain *p2m,
                                                    p2m_type_t ot,
                                                    p2m_type_t nt);
@@ -507,6 +510,14 @@ void guest_physmap_remove_page(struct domain *d,
 /* Set a p2m range as populate-on-demand */
 int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn,
                                           unsigned int order);
+/* Enable hardware-assisted log-dirty. */
+void p2m_enable_hardware_log_dirty(struct domain *d);
+
+/* Disable hardware-assisted log-dirty */
+void p2m_disable_hardware_log_dirty(struct domain *d);
+
+/* Flush hardware cached dirty GFNs */
+void p2m_flush_hardware_cached_dirty(struct domain *d);
 
 /* Change types across all p2m entries in a domain */
 void p2m_change_entry_type_global(struct domain *d, 
Signature · 1 line
2.1.0
#48 lore raw

Re: [v2 10/11] log-dirty: refine common code to support PML

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global) · line 200

Quoted 8 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/mm/hap/hap.c +2 -0
@@ -190,9 +196,15 @@ static int hap_enable_log_dirty(struct domain *d, bool_t log_global)
     d->arch.paging.mode |= PG_log_dirty;
     paging_unlock(d);
 
+    /* enable hardware-assisted log-dirty if it is supported */
+    p2m_enable_hardware_log_dirty(d);

I don't see that you would anywhere avoid setting up software log-dirty handling - is that on purpose? If so, is there really a win from adding PML?

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global) · line 208

Quoted 8 lines
xen/arch/x86/mm/hap/hap.c +4 -1
     if ( log_global )
     {
-        /* set l1e entries of P2M table to be read-only. */
+        /*
+         * switch to log dirty mode, either by setting l1e entries of P2M table
+         * to be read-only, or via hardware-assisted log-dirty.
+         */
         p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);

Or did I miss you changing the behavior of this anywhere (as the changed comment suggests)?

Jan

#49 lore raw

Re: [v2 10/11] log-dirty: refine common code to support PML

Quoted 22 lines

From: Jan Beulich [mailto:[email protected]]
Sent: Thursday, April 16, 2015 11:52 PM

Review static int hap_enable_log_dirty(struct domain *d,

Quoted 3 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
(quoted diff) +0 -0
@@ -190,9 +196,15 @@ static int hap_enable_log_dirty(struct domain *d,

bool_t log_global)

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global) · line 200

Quoted 5 lines
xen/arch/x86/mm/hap/hap.c +2 -0
     d->arch.paging.mode |= PG_log_dirty;
     paging_unlock(d);
 
+    /* enable hardware-assisted log-dirty if it is supported */
+    p2m_enable_hardware_log_dirty(d);

I don't see that you would anywhere avoid setting up software log-dirty handling - is that on purpose? If so, is there really a win from adding PML?

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global)

Quoted 5 lines
xen/arch/x86/mm/hap/hap.c +2 -1
     if ( log_global )
     {
-        /* set l1e entries of P2M table to be read-only. */
+        /*
+         * switch to log dirty mode, either by setting l1e entries of P2M
Quoted 9 lines

table

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global)

Quoted 3 lines
xen/arch/x86/mm/hap/hap.c +2 -0
+         * to be read-only, or via hardware-assisted log-dirty.
+         */
         p2m_change_entry_type_global(d, p2m_ram_rw,

p2m_ram_logdirty);

Or did I miss you changing the behavior of this anywhere (as the changed comment suggests)?

just found behavior is changed in [11/11]. :-)

Thanks
Kevin

author
#50 lore raw

Re: [v2 10/11] log-dirty: refine common code to support PML

Quoted 24 lines · Kevin
Quoted 24 lines

From: Jan Beulich [mailto:[email protected]]
Sent: Thursday, April 16, 2015 11:52 PM

Review static int hap_enable_log_dirty(struct domain *d,

Quoted 2 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
(quoted diff) +0 -0
@@ -190,9 +196,15 @@ static int hap_enable_log_dirty(struct domain *d,

bool_t log_global)

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global) · line 200

Quoted 5 lines
xen/arch/x86/mm/hap/hap.c +2 -0
      d->arch.paging.mode |= PG_log_dirty;
      paging_unlock(d);
 
+    /* enable hardware-assisted log-dirty if it is supported */
+    p2m_enable_hardware_log_dirty(d);

I don't see that you would anywhere avoid setting up software log-dirty handling - is that on purpose? If so, is there really a win from adding PML?

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global)

Quoted 5 lines
xen/arch/x86/mm/hap/hap.c +2 -1
      if ( log_global )
      {
-        /* set l1e entries of P2M table to be read-only. */
+        /*
+         * switch to log dirty mode, either by setting l1e entries of P2M

table

Quoted 3 lines
xen/arch/x86/mm/hap/hap.c +2 -0
+         * to be read-only, or via hardware-assisted log-dirty.
+         */
          p2m_change_entry_type_global(d, p2m_ram_rw,
Quoted 6 lines
Quoted 5 lines

p2m_ram_logdirty);

Or did I miss you changing the behavior of this anywhere (as the changed comment suggests)?

just found behavior is changed in [11/11]. :-)

Yes.

Thanks,
-Kai

Quoted 8 lines

Thanks
Kevin

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

author
#51 lore raw

Re: [v2 10/11] log-dirty: refine common code to support PML

In reply to Jan Beulich
Quoted 19 lines · Jan Beulich

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global) · line 200

Quoted 7 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/mm/hap/hap.c +2 -0
@@ -190,9 +196,15 @@ static int hap_enable_log_dirty(struct domain *d, bool_t log_global)
      d->arch.paging.mode |= PG_log_dirty;
      paging_unlock(d);
 
+    /* enable hardware-assisted log-dirty if it is supported */
+    p2m_enable_hardware_log_dirty(d);

I don't see that you would anywhere avoid setting up software log-dirty handling - is that on purpose? If so, is there really a win from adding PML?

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global) · line 208

Quoted 8 lines
xen/arch/x86/mm/hap/hap.c +4 -1
      if ( log_global )
      {
-        /* set l1e entries of P2M table to be read-only. */
+        /*
+         * switch to log dirty mode, either by setting l1e entries of P2M table
+         * to be read-only, or via hardware-assisted log-dirty.
+         */
          p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
Quoted 2 lines

Or did I miss you changing the behavior of this anywhere (as the changed comment suggests)?

Both of your comments are done in patch 11.

And I think even without patch 11, there's no harm with this patch as p2m_enable_hardware_log_dirty will essentially do nothing and write protection will be used for log-dirty :)

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#52 lore raw

Re: [v2 10/11] log-dirty: refine common code to support PML

Quoted 21 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 04:46, <[email protected]> wrote:
Quoted 19 lines · Jan Beulich

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global) · line 200

Quoted 7 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/mm/hap/hap.c +2 -0
@@ -190,9 +196,15 @@ static int hap_enable_log_dirty(struct domain *d, bool_t log_global)
      d->arch.paging.mode |= PG_log_dirty;
      paging_unlock(d);
 
+    /* enable hardware-assisted log-dirty if it is supported */
+    p2m_enable_hardware_log_dirty(d);

I don't see that you would anywhere avoid setting up software log-dirty handling - is that on purpose? If so, is there really a win from adding PML?

Quoted 8 lines
xen/arch/x86/mm/hap/hap.c +4 -1
      if ( log_global )
      {
-        /* set l1e entries of P2M table to be read-only. */
+        /*
+         * switch to log dirty mode, either by setting l1e entries of P2M table
+         * to be read-only, or via hardware-assisted log-dirty.
+         */
          p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
Quoted 3 lines
Quoted 2 lines

Or did I miss you changing the behavior of this anywhere (as the changed comment suggests)?

Both of your comments are done in patch 11.

Partly - the new behavior indeed gets added there, but the misconfig VM exits still seem to be a necessary part of the logic, so the question
stands: Is there really a win from adding PML? Or wait, I think now I recall - the benefit comes from avoiding the protection violation exits, not the misconfig ones. Sorry for the noise then.

Jan

author
#53 lore raw

Re: [v2 10/11] log-dirty: refine common code to support PML

Quoted 21 lines · Jan Beulich
Quoted 21 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 04:46, <[email protected]> wrote:
Quoted 19 lines · Jan Beulich

xen/arch/x86/mm/hap/hap.c static int hap_enable_log_dirty(struct domain *d, bool_t log_global) · line 200

Quoted 7 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:
xen/arch/x86/mm/hap/hap.c +2 -0
@@ -190,9 +196,15 @@ static int hap_enable_log_dirty(struct domain *d, bool_t log_global)
       d->arch.paging.mode |= PG_log_dirty;
       paging_unlock(d);
 
+    /* enable hardware-assisted log-dirty if it is supported */
+    p2m_enable_hardware_log_dirty(d);

I don't see that you would anywhere avoid setting up software log-dirty handling - is that on purpose? If so, is there really a win from adding PML?

Quoted 8 lines
xen/arch/x86/mm/hap/hap.c +4 -1
       if ( log_global )
       {
-        /* set l1e entries of P2M table to be read-only. */
+        /*
+         * switch to log dirty mode, either by setting l1e entries of P2M table
+         * to be read-only, or via hardware-assisted log-dirty.
+         */
           p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
Quoted 8 lines
Quoted 3 lines
Quoted 2 lines

Or did I miss you changing the behavior of this anywhere (as the changed comment suggests)?

Both of your comments are done in patch 11.

Partly - the new behavior indeed gets added there, but the misconfig VM exits still seem to be a necessary part of the logic, so the question
stands: Is there really a win from adding PML? Or wait, I think now I recall - the benefit comes from avoiding the protection violation exits, not the misconfig ones. Sorry for the noise then.

Yes PML is targeted to significantly reduce number of EPT violation caused by write protection of guest memory, and thus reduce hypervisor overhead of log-dirty mechanism.

Thanks,
-Kai

Quoted 3 lines

Jan

author
#54 lore raw

PATCH v2 11/11 p2m/ept: enable PML in p2m-ept for log-dirty

In reply to Kai Huang

This patch firstly enables EPT A/D bits if PML is used, as PML depends on EPT A/D bits to work. A bit is set for all present leaf p2m types, D bit is set for all writable types, except log-dirty type.

With PML, for 4K pages, instead of setting EPT entry to read-only, we just need to clear D bit in order to log that GFN. For superpages, we still need to set it to read-only as we need to split superpage to 4K pages in EPT violation.

---
 xen/arch/x86/mm/p2m-ept.c          | 79 ++++++++++++++++++++++++++++++++++----
 xen/include/asm-x86/hvm/vmx/vmcs.h |  3 +-
 xen/include/asm-x86/hvm/vmx/vmx.h  |  3 +-
 3 files changed, 76 insertions(+), 9 deletions(-)
xen/arch/x86/mm/p2m-ept.c +72 -7
index 5e95a83..ff84c16 100644
@@ -102,9 +102,20 @@ static int atomic_write_ept_entry(ept_entry_t *entryptr, ept_entry_t new,
     return rc;
 }
 
-static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_access_t access)
+static void ept_p2m_type_to_flags(struct p2m_domain *p2m, ept_entry_t *entry,
+                                  p2m_type_t type, p2m_access_t access)
 {
-    /* First apply type permissions */
+    /*
+     * First apply type permissions.
+     *
+     * A/D bits are also manually set to avoid overhead of MMU having to set
+     * them later. Both A/D bits are safe to be updated directly as they are
+     * ignored by processor if EPT A/D bits is not turned on.
+     *
+     * A bit is set for all present leaf types. D bit is set for all writable
+     * types and cleared for read-only types, as read-only types are apparently
+     * impossible to be dirty.
+     */
     switch(type)
     {
         case p2m_invalid:
@@ -118,27 +129,51 @@ static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type, p2m_acces
             break;
         case p2m_ram_rw:
             entry->r = entry->w = entry->x = 1;
+            entry->a = entry->d = 1;
             break;
         case p2m_mmio_direct:
             entry->r = entry->x = 1;
             entry->w = !rangeset_contains_singleton(mmio_ro_ranges,
                                                     entry->mfn);
+            entry->a = 1;
+            entry->d = entry->w;
             break;
         case p2m_ram_logdirty:
+            entry->r = entry->x = 1;
+            /*
+             * In case of PML, we don't have to write protect 4K page, but
+             * only need to clear D-bit for it, but we still need to write
+             * protect super page in order to split it to 4K pages in EPT
+             * violation.
+             */
+            if ( vmx_domain_pml_enabled(p2m->domain)
+                 && !is_epte_superpage(entry) )
+                entry->w = 1;
+            else
+                entry->w = 0;
+            entry->a = 1;
+            /* For both PML or non-PML cases we clear D bit anyway */
+            entry->d = 0;
+            break;
         case p2m_ram_ro:
         case p2m_ram_shared:
             entry->r = entry->x = 1;
             entry->w = 0;
+            entry->a = 1;
+            entry->d = 0;
             break;
         case p2m_grant_map_rw:
         case p2m_map_foreign:
             entry->r = entry->w = 1;
             entry->x = 0;
+            entry->a = entry->d = 1;
             break;
         case p2m_grant_map_ro:
         case p2m_mmio_write_dm:
             entry->r = 1;
             entry->w = entry->x = 0;
+            entry->a = 1;
+            entry->d = 0;
             break;
     }
 
@@ -194,6 +229,8 @@ static int ept_set_middle_entry(struct p2m_domain *p2m, ept_entry_t *ept_entry)
     ept_entry->access = p2m->default_access;
 
     ept_entry->r = ept_entry->w = ept_entry->x = 1;
+    /* Manually set A bit to avoid overhead of MMU having to write it later. */
+    ept_entry->a = 1;
 
     return 1;
 }
@@ -244,10 +281,9 @@ static int ept_split_super_page(struct p2m_domain *p2m, ept_entry_t *ept_entry,
         epte->sp = (level > 1);
         epte->mfn += i * trunk;
         epte->snp = (iommu_enabled && iommu_snoop);
-        ASSERT(!epte->rsvd1);
         ASSERT(!epte->avail3);
 
-        ept_p2m_type_to_flags(epte, epte->sa_p2mt, epte->access);
+        ept_p2m_type_to_flags(p2m, epte, epte->sa_p2mt, epte->access);
 
         if ( (level - 1) == target )
             continue;
@@ -489,7 +525,7 @@ static int resolve_misconfig(struct p2m_domain *p2m, unsigned long gfn)
                     {
                          e.sa_p2mt = p2m_is_logdirty_range(p2m, gfn + i, gfn + i)
                                      ? p2m_ram_logdirty : p2m_ram_rw;
-                         ept_p2m_type_to_flags(&e, e.sa_p2mt, e.access);
+                         ept_p2m_type_to_flags(p2m, &e, e.sa_p2mt, e.access);
                     }
                     e.recalc = 0;
                     wrc = atomic_write_ept_entry(&epte[i], e, level);
@@ -541,7 +577,7 @@ static int resolve_misconfig(struct p2m_domain *p2m, unsigned long gfn)
                 e.ipat = ipat;
                 e.recalc = 0;
                 if ( recalc && p2m_is_changeable(e.sa_p2mt) )
-                    ept_p2m_type_to_flags(&e, e.sa_p2mt, e.access);
+                    ept_p2m_type_to_flags(p2m, &e, e.sa_p2mt, e.access);
                 wrc = atomic_write_ept_entry(&epte[i], e, level);
                 ASSERT(wrc == 0);
             }
@@ -752,7 +788,7 @@ ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
         if ( ept_entry->mfn == new_entry.mfn )
              need_modify_vtd_table = 0;
 
-        ept_p2m_type_to_flags(&new_entry, p2mt, p2ma);
+        ept_p2m_type_to_flags(p2m, &new_entry, p2mt, p2ma);
     }
 
     rc = atomic_write_ept_entry(ept_entry, new_entry, target);
@@ -1053,6 +1089,26 @@ void ept_sync_domain(struct p2m_domain *p2m)
                      __ept_sync_domain, p2m, 1);
 }
 
+static void ept_enable_pml(struct p2m_domain *p2m)
+{
+    /*
+     * No need to check if vmx_domain_enable_pml has succeeded or not, as
+     * ept_p2m_type_to_flags will do the check, and write protection will be
+     * used if PML is not enabled.
+     */
+    vmx_domain_enable_pml(p2m->domain);
+}
+
+static void ept_disable_pml(struct p2m_domain *p2m)
+{
+    vmx_domain_disable_pml(p2m->domain);
+}
+
+static void ept_flush_pml_buffers(struct p2m_domain *p2m)
+{
+    vmx_domain_flush_pml_buffers(p2m->domain);
+}
+
 int ept_p2m_init(struct p2m_domain *p2m)
 {
     struct ept_data *ept = &p2m->ept;
@@ -1070,6 +1126,15 @@ int ept_p2m_init(struct p2m_domain *p2m)
     /* set EPT page-walk length, now it's actual walk length - 1, i.e. 3 */
     ept->ept_wl = 3;
 
+    if ( cpu_has_vmx_pml )
+    {
+        /* Enable EPT A/D bits if we are going to use PML */
+        ept->ept_ad = cpu_has_vmx_pml ? 1 : 0;
+        p2m->enable_hardware_log_dirty = ept_enable_pml;
+        p2m->disable_hardware_log_dirty = ept_disable_pml;
+        p2m->flush_hardware_cached_dirty = ept_flush_pml_buffers;
+    }
+
     if ( !zalloc_cpumask_var(&ept->synced_mask) )
         return -ENOMEM;
 
xen/include/asm-x86/hvm/vmx/vmcs.h +2 -1
index ceb09bf..afdaf6b 100644
@@ -62,7 +62,8 @@ struct ept_data {
     struct {
             u64 ept_mt :3,
                 ept_wl :3,
-                rsvd   :6,
+                ept_ad :1,  /* bit 6 - enable EPT A/D bits */
+                rsvd   :5,
                 asr    :52;
         };
         u64 eptp;
xen/include/asm-x86/hvm/vmx/vmx.h +2 -1
index 50f1bfc..35f804a 100644
@@ -37,7 +37,8 @@ typedef union {
         emt         :   3,  /* bits 5:3 - EPT Memory type */
         ipat        :   1,  /* bit 6 - Ignore PAT memory type */
         sp          :   1,  /* bit 7 - Is this a superpage? */
-        rsvd1       :   2,  /* bits 9:8 - Reserved for future use */
+        a           :   1,  /* bit 8 - Access bit */
+        d           :   1,  /* bit 9 - Dirty bit */
         recalc      :   1,  /* bit 10 - Software available 1 */
         snp         :   1,  /* bit 11 - VT-d snoop control in shared
                                EPT/VT-d usage */
Signature · 1 line
2.1.0
#55 lore raw

Re: [v2 11/11] p2m/ept: enable PML in p2m-ept for log-dirty

Quoted 4 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:

This patch firstly enables EPT A/D bits if PML is used, as PML depends on EPT A/D bits to work. A bit is set for all present leaf p2m types, D bit is set for all writable types, except log-dirty type.

I think the tying of "leaf" to the A bit part of the description became stale, as you're now also doing this for non-leaf ones.

Jan

author
#56 lore raw

Re: [v2 11/11] p2m/ept: enable PML in p2m-ept for log-dirty

Quoted 6 lines · Jan Beulich
Quoted 4 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:

This patch firstly enables EPT A/D bits if PML is used, as PML depends on EPT A/D bits to work. A bit is set for all present leaf p2m types, D bit is set for all writable types, except log-dirty type.

I think the tying of "leaf" to the A bit part of the description became stale, as you're now also doing this for non-leaf ones.

You are right. How about just "A bit is set for all present p2m types, ..."?

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#57 lore raw

Re: [v2 11/11] p2m/ept: enable PML in p2m-ept for log-dirty

Quoted 11 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 04:40, <[email protected]> wrote:
Quoted 2 lines · Jan Beulich
Quoted 2 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:

This patch firstly enables EPT A/D bits if PML is used, as PML depends on

EPT

Quoted 1 line
Quoted 1 line

A/D bits to work. A bit is set for all present leaf p2m types, D bit is set

for

Quoted 3 lines
Quoted 1 line

all writable types, except log-dirty type.

I think the tying of "leaf" to the A bit part of the description became stale, as you're now also doing this for non-leaf ones.

You are right. How about just "A bit is set for all present p2m types, ..."?

Almost - adding "leaf" to the D bit part would still be desirable for clarity.

Jan

author
#58 lore raw

Re: [v2 11/11] p2m/ept: enable PML in p2m-ept for log-dirty

Quoted 5 lines · Jan Beulich
Quoted 5 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 04:40, <[email protected]> wrote:
Quoted 2 lines · Jan Beulich
Quoted 2 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:

This patch firstly enables EPT A/D bits if PML is used, as PML depends on

EPT

Quoted 8 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line

A/D bits to work. A bit is set for all present leaf p2m types, D bit is set

for

Quoted 3 lines
Quoted 1 line

all writable types, except log-dirty type.

I think the tying of "leaf" to the A bit part of the description became stale, as you're now also doing this for non-leaf ones.

You are right. How about just "A bit is set for all present p2m types, ..."?

Almost - adding "leaf" to the D bit part would still be desirable for clarity.

That will be more accurate. Thanks for suggestion. Is below good to you?

"A bit is set for all present p2m types in middle and leaf EPT entries, and D bit is set for all writable types in the leaf EPT entry, except log-dirty type."

And I will update comments at the beginning of ept_p2m_type_to_flags accordingly.

Thanks,
-Kai

Quoted 8 lines

Jan

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xen.org/xen-devel

#59 lore raw

Re: [v2 11/11] p2m/ept: enable PML in p2m-ept for log-dirty

Quoted 8 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 09:10, <[email protected]> wrote:
Quoted 6 lines · Jan Beulich
Quoted 6 lines
Quoted 1 line
Quoted 1 line · On 17.04.15 at 04:40, <[email protected]> wrote:
Quoted 2 lines · Jan Beulich
Quoted 2 lines
Quoted 1 line
Quoted 1 line · On 15.04.15 at 09:03, <[email protected]> wrote:

This patch firstly enables EPT A/D bits if PML is used, as PML depends on

EPT

Quoted 1 line
Quoted 1 line

A/D bits to work. A bit is set for all present leaf p2m types, D bit is set

Quoted 8 lines
Quoted 7 lines
Quoted 5 lines

for

Quoted 3 lines
Quoted 1 line

all writable types, except log-dirty type.

I think the tying of "leaf" to the A bit part of the description became stale, as you're now also doing this for non-leaf ones.

You are right. How about just "A bit is set for all present p2m types, ..."?

Almost - adding "leaf" to the D bit part would still be desirable for clarity.

That will be more accurate. Thanks for suggestion. Is below good to you?

Yes.

Quoted 6 lines

"A bit is set for all present p2m types in middle and leaf EPT entries, and D bit is set for all writable types in the leaf EPT entry, except log-dirty type."

And I will update comments at the beginning of ept_p2m_type_to_flags accordingly.

Thanks.

Jan